itfx/.github/workflows/master.yml
2026-09-02 17:57:30 +08:00

198 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.

# 复制到 itfx 仓库: .github/workflows/deploy.yml
#
# 集群一次性准备(在 42 上):
# GIT_TOKEN=... TCR_USERNAME=... TCR_PASSWORD=... ./scripts/16-setup-kaniko.sh
#
# GitHub Secrets本仓 Settings → Secrets:
# SSH_K3S_HOST — 42 公网 IP
# SSH_K3S_USERNAME — 一般 root
# SSH_K3S_PASSWORD — SSH 密码
#
# 排障:看哪个 step 红了
# 1 print-info — 仅输出变量,几乎不会挂
# 2 check-cluster — SSH / kubeconfig / 节点不通
# 3 check-secrets — 未跑 16-setup-kaniko或 Secret 名不对
# 4 kaniko-build — 拉代码 / Dockerfile / 推 TCR看 Job 日志)
# 5 set-image — Deployment 名或容器名不对
# 6 rollout — 镜像拉不下来 / 探针失败 / 资源不够
#
name: Build and Deploy
on:
push:
branches: [master]
workflow_dispatch:
env:
GIT_URL: https://github.com/xiaoliutral/itfx.git
DOCKERFILE: src/InterfaceForward.Api/Dockerfile
IMAGE_NAME: interfaceforward_api
DEPLOY_NAME: interfaceforward-api
CONTAINER_NAME: interfaceforward-api
TCR_REGISTRY: ccr.ccs.tencentyun.com
TCR_NAMESPACE: ideship
K3S_DIR: /data/k3s
KUBECONFIG: /etc/rancher/k3s/k3s.yaml
NAMESPACE: prod
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# ── 0. 本机算出 TAG / 完整镜像名(不 SSH────────────────
- name: "0. print build info"
id: info
run: |
TAG="${{ github.sha }}"
IMG="${{ env.TCR_REGISTRY }}/${{ env.TCR_NAMESPACE }}/${{ env.IMAGE_NAME }}:${TAG}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "image=${IMG}" >> "$GITHUB_OUTPUT"
echo "======= build info ======="
echo "repo = ${{ github.repository }}"
echo "ref = ${{ github.ref_name }}"
echo "sha = ${TAG}"
echo "git_url = ${{ env.GIT_URL }}"
echo "dockerfile = ${{ env.DOCKERFILE }}"
echo "image = ${IMG}"
echo "deploy = ${{ env.NAMESPACE }}/deploy/${{ env.DEPLOY_NAME }}"
echo "=========================="
# ── 1. SSH + 集群是否通 ─────────────────────────────────
- name: "1. check cluster (SSH + kubectl)"
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_K3S_HOST }}
username: ${{ secrets.SSH_K3S_USERNAME }}
password: ${{ secrets.SSH_K3S_PASSWORD }}
script_stop: true
script: |
set -euo pipefail
export KUBECONFIG="${{ env.KUBECONFIG }}"
echo "==> whoami: $(whoami) @ $(hostname)"
echo "==> kubeconfig: ${KUBECONFIG}"
test -f "${KUBECONFIG}" || { echo "FAIL: 找不到 ${KUBECONFIG}"; exit 1; }
test -d "${{ env.K3S_DIR }}" || { echo "FAIL: 找不到 ${{ env.K3S_DIR }},请把 k3s 清单同步到该目录"; exit 1; }
test -x "${{ env.K3S_DIR }}/scripts/ci-kaniko-build.sh" || {
echo "FAIL: 缺少可执行脚本 ${{ env.K3S_DIR }}/scripts/ci-kaniko-build.sh"
ls -la "${{ env.K3S_DIR }}/scripts/" || true
exit 1
}
echo "==> nodes:"
kubectl get nodes -o wide
echo "==> namespace ${{ env.NAMESPACE }}:"
kubectl get ns "${{ env.NAMESPACE }}"
echo "==> deploy/${{ env.DEPLOY_NAME }}:"
kubectl -n "${{ env.NAMESPACE }}" get deploy "${{ env.DEPLOY_NAME }}" -o wide
# ── 2. Kaniko 凭据是否已创建 ────────────────────────────
- name: "2. check kaniko secrets"
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_K3S_HOST }}
username: ${{ secrets.SSH_K3S_USERNAME }}
password: ${{ secrets.SSH_K3S_PASSWORD }}
script_stop: true
script: |
set -euo pipefail
export KUBECONFIG="${{ env.KUBECONFIG }}"
NS="${{ env.NAMESPACE }}"
echo "==> 检查 Secret由 16-setup-kaniko.sh 创建)"
kubectl -n "$NS" get secret kaniko-git -o jsonpath='{.metadata.name}{" keys="}{.data}{"\n"}' >/dev/null \
&& echo "OK secret/kaniko-git" \
|| { echo "FAIL: 缺少 secret/kaniko-git — 在 42 执行: GIT_TOKEN=... ./scripts/16-setup-kaniko.sh"; exit 1; }
kubectl -n "$NS" get secret kaniko-docker-config >/dev/null \
&& echo "OK secret/kaniko-docker-config" \
|| { echo "FAIL: 缺少 secret/kaniko-docker-config — TCR 账号未写入"; exit 1; }
echo "==> build 节点:"
kubectl get nodes -l role=build -o wide
COUNT="$(kubectl get nodes -l role=build --no-headers 2>/dev/null | wc -l | tr -d ' ')"
if [[ "${COUNT}" == "0" ]]; then
echo "FAIL: 没有 role=build 节点Kaniko Job 会 Pending"
kubectl get nodes --show-labels
exit 1
fi
# ── 3. Kaniko 构建并推 TCR最慢失败看 Job 日志)─────
- name: "3. kaniko build & push"
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_K3S_HOST }}
username: ${{ secrets.SSH_K3S_USERNAME }}
password: ${{ secrets.SSH_K3S_PASSWORD }}
command_timeout: 50m
script_stop: true
script: |
set -euo pipefail
export KUBECONFIG="${{ env.KUBECONFIG }}"
cd "${{ env.K3S_DIR }}"
TAG="${{ steps.info.outputs.tag }}"
echo "==> 开始 Kaniko: ${{ env.IMAGE_NAME }}:${TAG}"
echo " 失败时在 42 执行:"
echo " kubectl -n ${{ env.NAMESPACE }} get job -l app=kaniko"
echo " kubectl -n ${{ env.NAMESPACE }} logs -l job-name=... -c git"
echo " kubectl -n ${{ env.NAMESPACE }} logs -l job-name=... -c kaniko"
./scripts/ci-kaniko-build.sh \
"${{ env.GIT_URL }}" \
"${{ env.DOCKERFILE }}" \
"${{ env.IMAGE_NAME }}" \
"${TAG}" \
"${TAG}"
echo "==> 镜像已推送: ${{ steps.info.outputs.image }}"
# ── 4. 改 Deployment 镜像 ───────────────────────────────
- name: "4. set deployment image"
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_K3S_HOST }}
username: ${{ secrets.SSH_K3S_USERNAME }}
password: ${{ secrets.SSH_K3S_PASSWORD }}
script_stop: true
script: |
set -euo pipefail
export KUBECONFIG="${{ env.KUBECONFIG }}"
NS="${{ env.NAMESPACE }}"
IMG="${{ steps.info.outputs.image }}"
echo "==> 当前镜像:"
kubectl -n "$NS" get deploy "${{ env.DEPLOY_NAME }}" \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="${{ env.CONTAINER_NAME }}")].image}{"\n"}'
echo "==> 设为: ${IMG}"
kubectl -n "$NS" set image "deploy/${{ env.DEPLOY_NAME }}" \
"${{ env.CONTAINER_NAME }}=${IMG}"
echo "==> 已更新:"
kubectl -n "$NS" get deploy "${{ env.DEPLOY_NAME }}" \
-o jsonpath='{.spec.template.spec.containers[?(@.name=="${{ env.CONTAINER_NAME }}")].image}{"\n"}'
# ── 5. 等待滚动发布 ─────────────────────────────────────
- name: "5. wait rollout"
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SSH_K3S_HOST }}
username: ${{ secrets.SSH_K3S_USERNAME }}
password: ${{ secrets.SSH_K3S_PASSWORD }}
command_timeout: 5m
script_stop: true
script: |
set -euo pipefail
export KUBECONFIG="${{ env.KUBECONFIG }}"
NS="${{ env.NAMESPACE }}"
DEP="${{ env.DEPLOY_NAME }}"
echo "==> rollout status..."
if ! kubectl -n "$NS" rollout status "deploy/${DEP}" --timeout=180s; then
echo "FAIL: rollout 超时/失败,诊断信息如下"
kubectl -n "$NS" get deploy,rs,pods -l app="${DEP}" -o wide || \
kubectl -n "$NS" get pods -o wide | grep -E "${DEP}|NAME" || true
kubectl -n "$NS" describe deploy "${DEP}" | tail -60 || true
POD="$(kubectl -n "$NS" get pods -l app="${DEP}" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || true)"
if [[ -n "${POD}" ]]; then
echo "==> events for ${POD}:"
kubectl -n "$NS" describe pod "${POD}" | tail -40 || true
echo "==> logs:"
kubectl -n "$NS" logs "${POD}" --tail=80 || true
fi
exit 1
fi
echo "==> pods:"
kubectl -n "$NS" get pods -o wide | grep -E "${DEP}|NAME" || \
kubectl -n "$NS" get pods -o wide
echo "OK deployed ${{ steps.info.outputs.image }}"