Files
lpt-fe/.gitea/workflows/deploy.yml
T

226 lines
9.0 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: lpt-fe Build & Deploy
on:
workflow_dispatch:
inputs:
environment:
description: '部署环境(dev 仅允许 dev 分支;prod 仅允许 master/main'
required: true
type: choice
options:
- dev
- prod
env:
REGISTRY: 192.168.123.199:5000
APP: lpt-fe
REPO_URL: http://git.cat-shark.xyz/cat-shark/lpt-fe.git
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Validate branch ↔ environment
run: |
set -euo pipefail
REF="${{ gitea.ref }}"
BRANCH="${REF#refs/heads/}"
# tag 触发时拒绝
if [[ "$REF" == refs/tags/* ]]; then
echo "ERROR: 请从分支触发部署,不要用 tag。当前 ref=$REF"
exit 1
fi
ENV="${{ inputs.environment }}"
echo "branch=$BRANCH environment=$ENV sha=${{ gitea.sha }}"
case "$ENV" in
prod)
case "$BRANCH" in
master|main) echo "OK: prod 允许从 $BRANCH 部署" ;;
*)
echo "ERROR: prod 只能从 master/main 部署,当前分支是 '$BRANCH'"
echo "请切换到 master 后再 Run workflow,并选择 environment=prod"
exit 1
;;
esac
;;
dev)
case "$BRANCH" in
dev) echo "OK: dev 允许从 $BRANCH 部署" ;;
*)
echo "ERROR: dev 只能从 dev 分支部署,当前分支是 '$BRANCH'"
echo "请切换到 dev 后再 Run workflow,并选择 environment=dev"
echo "(禁止用 master 代码部署到 lpt-dev,避免环境错配)"
exit 1
;;
esac
;;
*)
echo "ERROR: 未知 environment=$ENV"
exit 1
;;
esac
- name: Checkout code
run: |
set -euo pipefail
git clone "$REPO_URL" .
git checkout "${{ gitea.sha }}"
- name: Login to Docker Registry
run: |
set -euo pipefail
USER="${{ secrets.REGISTRY_USERNAME }}"
PASS="${{ secrets.REGISTRY_PASSWORD }}"
if [ -z "$USER" ] || [ -z "$PASS" ]; then
echo "ERROR: REGISTRY_USERNAME / REGISTRY_PASSWORD 未配置或为空"
echo "请在 Gitea 仓库 Settings → Secrets 中配置后重试"
exit 1
fi
echo "$PASS" | docker login "$REGISTRY" -u "$USER" --password-stdin
- name: Build & Push Docker image
run: |
set -euo pipefail
ENV="${{ inputs.environment }}"
if [ "$ENV" = "prod" ]; then
BUILD_MODE=production
else
BUILD_MODE=development
fi
TAG="${{ gitea.sha }}-$(date +%s)"
echo "Building $REGISTRY/$APP:$TAG (BUILD_MODE=$BUILD_MODE, env tag=$ENV)"
docker build \
--build-arg "BUILD_MODE=$BUILD_MODE" \
-t "$REGISTRY/$APP:$TAG" \
-t "$REGISTRY/$APP:$ENV" .
docker push "$REGISTRY/$APP:$TAG"
docker push "$REGISTRY/$APP:$ENV"
# 持久化 TAG:兼容 Gitea / GitHub Actions;文件兜底避免 env 文件不支持
if [ -n "${GITHUB_ENV:-}" ]; then
echo "IMAGE_TAG=$TAG" >> "$GITHUB_ENV"
fi
if [ -n "${GITEA_ENV:-}" ]; then
echo "IMAGE_TAG=$TAG" >> "$GITEA_ENV"
fi
echo "$TAG" > image_tag.txt
if [ -n "${{ runner.temp }}" ]; then
echo "$TAG" > "${{ runner.temp }}/image_tag.txt" || true
fi
echo "IMAGE_TAG=$TAG"
- name: Setup kubectl
run: |
set -euo pipefail
if [ -z "${{ secrets.KUBECONFIG_B64 }}" ]; then
echo "ERROR: KUBECONFIG_B64 未配置或为空"
exit 1
fi
curl -sLO "https://dl.k8s.io/release/v1.30.0/bin/linux/amd64/kubectl"
chmod +x kubectl
mv kubectl /usr/local/bin/
echo "${{ secrets.KUBECONFIG_B64 }}" | base64 -d > /tmp/kubeconfig
kubectl --kubeconfig=/tmp/kubeconfig cluster-info >/dev/null
- name: Create/Update imagePullSecret
run: |
set -euo pipefail
ENV="${{ inputs.environment }}"
NS="lpt-$ENV"
USER="${{ secrets.REGISTRY_USERNAME }}"
PASS="${{ secrets.REGISTRY_PASSWORD }}"
if [ -z "$USER" ] || [ -z "$PASS" ]; then
echo "ERROR: REGISTRY_USERNAME / REGISTRY_PASSWORD 为空,无法创建 regcred"
exit 1
fi
# 确保 namespace 存在
kubectl --kubeconfig=/tmp/kubeconfig get ns "$NS" >/dev/null 2>&1 \
|| kubectl --kubeconfig=/tmp/kubeconfig create ns "$NS"
# 删除旧 secret 再重建,避免 type/字段残留
kubectl --kubeconfig=/tmp/kubeconfig delete secret regcred -n "$NS" --ignore-not-found
kubectl --kubeconfig=/tmp/kubeconfig create secret docker-registry regcred \
--docker-server="$REGISTRY" \
--docker-username="$USER" \
--docker-password="$PASS" \
-n "$NS"
# 校验 .dockerconfigjson 非空
LEN=$(kubectl --kubeconfig=/tmp/kubeconfig get secret regcred -n "$NS" \
-o jsonpath='{.data.\.dockerconfigjson}' | wc -c)
if [ "${LEN// /}" -lt 10 ]; then
echo "ERROR: regcred 创建后 .dockerconfigjson 异常(len=$LEN"
exit 1
fi
echo "regcred OK in $NS (dockerconfigjson len≈$LEN)"
# 强制 Deployment 使用 imagePullSecrets(集群存量可能缺失)
kubectl --kubeconfig=/tmp/kubeconfig patch deployment "$APP" -n "$NS" \
--type=strategic \
-p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"regcred"}]}}}}'
echo "patched deployment/$APP imagePullSecrets=regcred"
- name: Deploy to K8s
run: |
set -euo pipefail
ENV="${{ inputs.environment }}"
NS="lpt-$ENV"
IMAGE_TAG="${IMAGE_TAG:-}"
if [ -z "$IMAGE_TAG" ] && [ -f image_tag.txt ]; then
IMAGE_TAG="$(cat image_tag.txt)"
fi
if [ -z "$IMAGE_TAG" ] && [ -f "${{ runner.temp }}/image_tag.txt" ]; then
IMAGE_TAG="$(cat "${{ runner.temp }}/image_tag.txt")"
fi
if [ -z "$IMAGE_TAG" ]; then
echo "ERROR: IMAGE_TAG 为空,无法部署"
exit 1
fi
# 确认 Deployment 已挂 regcred
PULL_SECRET=$(kubectl --kubeconfig=/tmp/kubeconfig get deployment "$APP" -n "$NS" \
-o jsonpath='{.spec.template.spec.imagePullSecrets[0].name}' 2>/dev/null || true)
if [ "$PULL_SECRET" != "regcred" ]; then
echo "ERROR: deployment/$APP 未配置 imagePullSecrets=regcred(当前='$PULL_SECRET'"
exit 1
fi
echo "Deploying $REGISTRY/$APP:$IMAGE_TAG -> namespace $NS"
kubectl --kubeconfig=/tmp/kubeconfig set image "deployment/$APP" \
"$APP=$REGISTRY/$APP:$IMAGE_TAG" \
-n "$NS" --record
kubectl --kubeconfig=/tmp/kubeconfig rollout status "deployment/$APP" \
-n "$NS" --timeout=5m
- name: Debug on failure
if: failure()
run: |
ENV="${{ inputs.environment }}"
NS="lpt-$ENV"
echo "=== Deployment Status ==="
kubectl --kubeconfig=/tmp/kubeconfig get deployment "$APP" -n "$NS" -o wide || true
echo ""
echo "=== imagePullSecrets on Deployment ==="
kubectl --kubeconfig=/tmp/kubeconfig get deployment "$APP" -n "$NS" \
-o jsonpath='{.spec.template.spec.imagePullSecrets}' || true
echo ""
echo "=== regcred secret ==="
kubectl --kubeconfig=/tmp/kubeconfig get secret regcred -n "$NS" -o yaml 2>&1 | head -20 || true
echo ""
echo "=== Pod Status ==="
kubectl --kubeconfig=/tmp/kubeconfig get pods -n "$NS" -l "app=$APP" || true
echo ""
echo "=== Recent Events ==="
kubectl --kubeconfig=/tmp/kubeconfig get events -n "$NS" --sort-by='.lastTimestamp' | tail -20 || true
echo ""
echo "=== Pod Describe (latest) ==="
POD=$(kubectl --kubeconfig=/tmp/kubeconfig get pods -n "$NS" -l "app=$APP" --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1].metadata.name}' 2>/dev/null || true)
if [ -n "${POD:-}" ]; then
kubectl --kubeconfig=/tmp/kubeconfig describe pod "$POD" -n "$NS" || true
echo ""
echo "=== Pod Logs (latest) ==="
kubectl --kubeconfig=/tmp/kubeconfig logs "$POD" -n "$NS" --tail=50 || true
fi
- name: Rollback on failure
if: failure()
run: |
set -euo pipefail
ENV="${{ inputs.environment }}"
kubectl --kubeconfig=/tmp/kubeconfig rollout undo "deployment/$APP" -n "lpt-$ENV" || true
kubectl --kubeconfig=/tmp/kubeconfig rollout status "deployment/$APP" -n "lpt-$ENV" || true