name: Deploy Hugo Blog to k3s on: push: branches: [main] workflow_dispatch: env: REGISTRY: git.luochen570.cn IMAGE: luochen570/hugo-blog K8S_NAMESPACE: hugo K8S_DEPLOYMENT: hugo-blog K8S_CONTAINER: nginx K8S_INGRESS: hugo-blog TEST_HOST: hugo.test.luochen570.cn PROD_HOST: hugo.luochen570.cn DOCKER_HOST: unix:///run/user/1000/docker.sock jobs: build-and-deploy: runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Hugo uses: peaceiris/actions-hugo@v3 with: hugo-version: '0.161.1' extended: true - name: Hugo Build run: hugo --minify - name: Build and Push Docker Image env: REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} run: | set -euo pipefail # k3s dind-rootless runner: use rootless Docker Unix socket. # Avoid the unverified TCP Docker API path here. export DOCKER_HOST="${DOCKER_HOST}" unset DOCKER_TLS_VERIFY DOCKER_CERT_PATH DOCKER_CONTEXT # Avoid proxy pollution in the container/rootless Docker path; proxy envs # can break image pulls through the slirp4netns namespace. unset HTTP_PROXY HTTPS_PROXY ALL_PROXY http_proxy https_proxy all_proxy if [ -z "${REGISTRY_TOKEN:-}" ]; then echo "REGISTRY_TOKEN secret is required" >&2 exit 1 fi docker version echo "$REGISTRY_TOKEN" | docker login "$REGISTRY" -u luochen570 --password-stdin docker build \ -t "$REGISTRY/$IMAGE:${{ github.sha }}" \ -t "$REGISTRY/$IMAGE:latest" \ . docker push "$REGISTRY/$IMAGE:${{ github.sha }}" docker push "$REGISTRY/$IMAGE:latest" - name: Deploy to k3s env: KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }} run: | set -euo pipefail if [ -z "${KUBECONFIG_B64:-}" ]; then echo "KUBECONFIG_B64 secret is required" >&2 exit 1 fi KUBECONFIG_FILE="$(mktemp)" trap 'rm -f "$KUBECONFIG_FILE" /tmp/kubectl' EXIT echo "$KUBECONFIG_B64" | base64 -d > "$KUBECONFIG_FILE" chmod 600 "$KUBECONFIG_FILE" KUBECTL_VERSION="v1.32.0" curl -fsSLo /tmp/kubectl "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" chmod +x /tmp/kubectl if /tmp/kubectl --kubeconfig "$KUBECONFIG_FILE" \ auth can-i get ingresses -n "$K8S_NAMESPACE" >/dev/null 2>&1; then ingress_hosts="$(/tmp/kubectl --kubeconfig "$KUBECONFIG_FILE" \ get ingress "$K8S_INGRESS" -n "$K8S_NAMESPACE" \ --ignore-not-found \ -o jsonpath='{range .spec.rules[*]}{.host}{"\n"}{end}{range .spec.tls[*].hosts[*]}{.}{"\n"}{end}')" printf '%s\n' "$ingress_hosts" | grep -Fx "$TEST_HOST" >/dev/null if printf '%s\n' "$ingress_hosts" | grep -Fx "$PROD_HOST" >/dev/null; then echo "Refusing deploy: ingress contains production host $PROD_HOST" >&2 exit 1 fi else echo "Kubeconfig cannot read ingresses; relying on K8S_NAMESPACE/K8S_DEPLOYMENT scope: $K8S_NAMESPACE/$K8S_DEPLOYMENT" fi /tmp/kubectl --kubeconfig "$KUBECONFIG_FILE" \ set image "deployment/$K8S_DEPLOYMENT" -n "$K8S_NAMESPACE" \ "$K8S_CONTAINER=$REGISTRY/$IMAGE:${{ github.sha }}" /tmp/kubectl --kubeconfig "$KUBECONFIG_FILE" \ rollout status "deployment/$K8S_DEPLOYMENT" -n "$K8S_NAMESPACE" --timeout=120s