This commit is contained in:
Yvan
2026-09-04 15:25:49 +08:00
parent 43db5e5450
commit 372e119e7c
5 changed files with 84 additions and 68 deletions
+33 -12
View File
@@ -19,7 +19,6 @@ pipeline {
KRA_BACKEND_NODEPORT = '30081'
KRA_MYSQL_IMAGE = 'docker.m.daocloud.io/library/mysql:8.4'
KRA_REDIS_IMAGE = 'docker.m.daocloud.io/library/redis:7-alpine'
KRA_SHARED_STORAGE_CLASS = 'longhorn' // 必须支持 ReadWriteMany;按目标集群实际存储类修改
GO_IMAGE = 'docker.m.daocloud.io/golang:1.25'
NODE_IMAGE = 'docker.m.daocloud.io/node:20-slim'
PNPM_VERSION = '10.15.1'
@@ -30,9 +29,10 @@ pipeline {
CRED_KUBECONFIG_DEV = 'kra-rke2-128-kubeconfig'
CRED_KUBECONFIG_PROD = 'kra-rke2-129-kubeconfig'
CRED_MYSQL_PASSWORD = 'kra-mysql-root-password'
CRED_JWT_SIGNING_KEY = 'kra-jwt-signing-key'
// k8s 清单渲染白名单:只替换列出的变量,避免误伤清单内 shell 变量(如 probe 里的 $MYSQL_ROOT_PASSWORD)
K8S_RENDER_VARS = '$KRA_APP $KRA_NAMESPACE $KRA_ENV $KRA_BACKEND_IMAGE $KRA_FRONTEND_IMAGE $KRA_REPLICAS $KRA_FRONTEND_NODEPORT $KRA_BACKEND_NODEPORT $KRA_MYSQL_IMAGE $KRA_REDIS_IMAGE $KRA_SHARED_STORAGE_CLASS $BIN_NAME'
K8S_RENDER_VARS = '$KRA_APP $KRA_NAMESPACE $KRA_ENV $KRA_BACKEND_IMAGE $KRA_FRONTEND_IMAGE $KRA_REPLICAS $KRA_FRONTEND_NODEPORT $KRA_BACKEND_NODEPORT $KRA_MYSQL_IMAGE $KRA_REDIS_IMAGE $BIN_NAME'
}
stages {
@@ -75,13 +75,18 @@ pipeline {
// job 的 SCM branch spec 固定(如 */main),集成触发时按实际推送分支重新检出,
// 保证单 job 同时服务 dev/main 两个环境。
script {
env.KRA_TRIGGER_COMMIT = env.gitlabAfter?.trim()
if (env.KRA_TRIGGER_COMMIT && !(env.KRA_TRIGGER_COMMIT ==~ /[0-9a-fA-F]{40}/)) {
error("Invalid GitLab commit SHA: ${env.KRA_TRIGGER_COMMIT}")
// gitlabAfter 为 push 事件的目标 commit;手动触发时为空。
// 注意:不能把 null 赋给 env.*(会被转成字符串 "null"),这里用局部变量。
def triggerCommit = env.gitlabAfter?.trim()
if (triggerCommit && !(triggerCommit ==~ /[0-9a-fA-F]{40}/)) {
error("Invalid GitLab commit SHA: ${triggerCommit}")
}
if (env.KRA_TRIGGER_COMMIT && env.KRA_TRIGGER_COMMIT.replace('0', '').isEmpty()) {
if (triggerCommit && triggerCommit.replace('0', '').isEmpty()) {
error('GitLab event points to a deleted branch; refusing to deploy')
}
if (triggerCommit) {
env.KRA_TRIGGER_COMMIT = triggerCommit
}
checkout([$class: 'GitSCM',
branches: [[name: "*/${env.KRA_BRANCH}"]],
userRemoteConfigs: [[credentialsId: 'gitlab-root-http', url: 'http://192.168.200.130/root/kra.git']]])
@@ -152,6 +157,7 @@ pipeline {
steps {
withCredentials([file(credentialsId: "${env.KUBECONFIG_CREDENTIALS}", variable: 'KUBECONFIG_FILE'),
string(credentialsId: env.CRED_MYSQL_PASSWORD, variable: 'KRA_MYSQL_ROOT_PASSWORD'),
string(credentialsId: env.CRED_JWT_SIGNING_KEY, variable: 'KRA_JWT_SIGNING_KEY'),
usernamePassword(credentialsId: env.CRED_HARBOR_PUSH, usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASSWORD')]) {
sh '''
set -eu
@@ -159,7 +165,6 @@ pipeline {
umask 077
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
kubectl get storageclass "$KRA_SHARED_STORAGE_CLASS" >/dev/null
kubectl create namespace "$KRA_NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
DOCKER_CONFIG_DIR="$TMP_DIR/docker"
mkdir -p "$DOCKER_CONFIG_DIR"
@@ -169,27 +174,43 @@ pipeline {
--from-file=.dockerconfigjson="$DOCKER_CONFIG_DIR/config.json" \\
--dry-run=client -o yaml | kubectl apply -f -
docker --config "$DOCKER_CONFIG_DIR" logout "$REGISTRY" >/dev/null 2>&1 || true
test -n "$KRA_MYSQL_ROOT_PASSWORD" || { echo 'MySQL root password credential is empty' >&2; exit 1; }
printf '%s' "$KRA_MYSQL_ROOT_PASSWORD" > "$TMP_DIR/mysql-root-password"
kubectl -n "$KRA_NAMESPACE" create secret generic "${APP_NAME}-runtime" \\
--from-file=mysql-root-password="$TMP_DIR/mysql-root-password" \\
--dry-run=client -o yaml | kubectl apply -f -
test -n "$KRA_JWT_SIGNING_KEY" || { echo 'JWT signing key credential is empty' >&2; exit 1; }
if [ "$(printf '%s' "$KRA_JWT_SIGNING_KEY" | wc -l)" -ne 0 ]; then
echo 'JWT signing key credential must be a single line' >&2
exit 1
fi
case "$KRA_JWT_SIGNING_KEY" in
*"'"*) echo "JWT signing key credential must not contain a single quote" >&2; exit 1 ;;
esac
CONFIG_TEMPLATE="$TMP_DIR/config.yaml"
envsubst '$APP_NAME $KRA_ENV' < deploy/k8s/config.example.yaml > "$CONFIG_TEMPLATE"
kubectl -n "$KRA_NAMESPACE" create configmap "${APP_NAME}-config-template" \\
envsubst '$APP_NAME $KRA_ENV $KRA_JWT_SIGNING_KEY' < deploy/k8s/config.example.yaml > "$CONFIG_TEMPLATE"
kubectl -n "$KRA_NAMESPACE" create secret generic "${APP_NAME}-config-template" \\
--from-file=config.yaml="$CONFIG_TEMPLATE" \\
--dry-run=client -o yaml | kubectl apply -f -
kubectl -n "$KRA_NAMESPACE" delete configmap "${APP_NAME}-config-template" --ignore-not-found
export KRA_APP="$APP_NAME"
export KRA_BACKEND_IMAGE="$REGISTRY/$IMAGE_REPO-backend:$IMAGE_TAG"
export KRA_FRONTEND_IMAGE="$REGISTRY/$IMAGE_REPO-frontend:$IMAGE_TAG"
RENDERED_MANIFEST="$TMP_DIR/manifest.yaml"
envsubst "$K8S_RENDER_VARS" < deploy/k8s/kra.yaml > "$RENDERED_MANIFEST"
MYSQL_SERVICE_IP=$(kubectl -n "$KRA_NAMESPACE" get service "${APP_NAME}-mysql" -o jsonpath='{.spec.clusterIP}' 2>/dev/null || true)
if [ -n "$MYSQL_SERVICE_IP" ] && [ "$MYSQL_SERVICE_IP" != 'None' ]; then
echo "${APP_NAME}-mysql already exists as a ClusterIP Service; delete it during a maintenance window before switching to headless mode" >&2
exit 1
fi
kubectl apply --dry-run=server -f "$RENDERED_MANIFEST"
kubectl apply -f "$RENDERED_MANIFEST"
RUNTIME_SECRET_VERSION=$(kubectl -n "$KRA_NAMESPACE" get secret "${APP_NAME}-runtime" -o jsonpath='{.metadata.resourceVersion}')
PATCH_FILE="$TMP_DIR/mysql-patch.json"
printf '{"spec":{"template":{"metadata":{"annotations":{"kra.dev/runtime-secret-version":"%s"}}}}}\n' \\
"$RUNTIME_SECRET_VERSION" > "$PATCH_FILE"
kubectl -n "$KRA_NAMESPACE" patch statefulset "${APP_NAME}-mysql" --type=merge \\
-p "{\"spec\":{\"template\":{\"metadata\":{\"annotations\":{\"kra.dev/runtime-secret-version\":\"$RUNTIME_SECRET_VERSION\"}}}}}"
kubectl -n "$KRA_NAMESPACE" wait --for=jsonpath='{.status.phase}'=Bound \\
"pvc/${APP_NAME}-config" "pvc/${APP_NAME}-uploads" --timeout=5m
--patch-file="$PATCH_FILE"
kubectl -n "$KRA_NAMESPACE" rollout status statefulset/${APP_NAME}-mysql --timeout=10m
kubectl -n "$KRA_NAMESPACE" rollout status deployment/${APP_NAME}-redis --timeout=10m
kubectl -n "$KRA_NAMESPACE" rollout status deployment/${APP_NAME}-backend --timeout=10m