diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index c0a0f68..77cf4a8 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -8,6 +8,13 @@ on: 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: @@ -32,22 +39,68 @@ jobs: env: REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} run: | - # Find the Docker daemon (dind is on the gateway) - DOCKER_HOST_IP=$(ip route | grep default | awk '{print $3}') - export DOCKER_HOST="tcp://${DOCKER_HOST_IP}:2375" - echo "DOCKER_HOST=$DOCKER_HOST" + set -euo pipefail - # Login - echo "$REGISTRY_TOKEN" | docker login $REGISTRY -u luochen570 --password-stdin + # 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 - # Build - docker build -t $REGISTRY/$IMAGE:${{ github.sha }} . - docker tag $REGISTRY/$IMAGE:${{ github.sha }} $REGISTRY/$IMAGE:latest + # 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 - # Push - docker push $REGISTRY/$IMAGE:${{ github.sha }} - docker push $REGISTRY/$IMAGE:latest + 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: | - echo "Deploy step - skipped until runner kubectl is configured" + 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 diff --git a/deploy/hugo-deployment.yaml b/deploy/hugo-deployment.yaml index 30489cc..02dc32e 100644 --- a/deploy/hugo-deployment.yaml +++ b/deploy/hugo-deployment.yaml @@ -20,6 +20,8 @@ spec: labels: app: hugo-blog spec: + imagePullSecrets: + - name: gitea-registry containers: - name: nginx image: git.luochen570.cn/luochen570/hugo-blog:latest