jenkins
This commit is contained in:
Vendored
+70
-28
@@ -10,7 +10,7 @@ pipeline {
|
||||
// 项目级参数 —— 基于 kra 模板的新项目只需修改本块。
|
||||
// 这些变量自动 export 到 shell,由 envsubst 白名单渲染进 k8s 清单。
|
||||
// ══════════════════════════════════════════════════════════════════
|
||||
APP_NAME = 'kra' // 派生:服务名/Secret名/库名/hostPath/镜像后缀
|
||||
APP_NAME = 'kra' // 派生:服务名/Secret名/库名/存储声明/镜像后缀
|
||||
IMAGE_REPO = 'library/kra' // Harbor 中镜像仓库路径
|
||||
REGISTRY = '192.168.200.132'
|
||||
BIN_NAME = 'kratos-admin' // Makefile build 的产物名
|
||||
@@ -19,24 +19,20 @@ 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'
|
||||
CACHE_DIR = '/var/lib/kra-ci-cache' // Jenkins 宿主机依赖缓存根目录
|
||||
|
||||
// 集群映射(dev -> 测试集群, main -> 生产集群)
|
||||
DEV_CLUSTER_HOST = '192.168.200.128'
|
||||
PROD_CLUSTER_HOST = '192.168.200.129'
|
||||
|
||||
// Jenkins 凭据 ID(新项目若沿用同一套凭据可不改)
|
||||
CRED_HARBOR_PUSH = 'harbor-library-push'
|
||||
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 $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 $KRA_SHARED_STORAGE_CLASS $BIN_NAME'
|
||||
}
|
||||
|
||||
stages {
|
||||
@@ -51,17 +47,21 @@ pipeline {
|
||||
if (!branch) {
|
||||
branch = env.JOB_NAME.endsWith('-dev') ? 'dev' : 'main'
|
||||
}
|
||||
branch = branch.trim().replaceFirst(/^refs\/heads\//, '')
|
||||
// The backend NodePort service has the longest generated name:
|
||||
// <APP_NAME>-backend-nodeport, which must stay within 63 characters.
|
||||
if (!(env.APP_NAME ==~ /^[a-z0-9](?:[a-z0-9-]{0,44}[a-z0-9])?$/)) {
|
||||
error("APP_NAME must be a lowercase Kubernetes name with at most 46 characters: ${env.APP_NAME}")
|
||||
}
|
||||
echo "gitlabBranch='${env.gitlabBranch ?: ''}' BRANCH_NAME='${env.BRANCH_NAME ?: ''}' -> resolved branch='${branch}'"
|
||||
env.KRA_BRANCH = branch
|
||||
if (branch == 'dev') {
|
||||
env.KRA_NAMESPACE = "${env.APP_NAME}-dev"
|
||||
env.KRA_ENV = 'development'
|
||||
env.KRA_CLUSTER_HOST = env.DEV_CLUSTER_HOST
|
||||
env.KUBECONFIG_CREDENTIALS = env.CRED_KUBECONFIG_DEV
|
||||
} else if (branch == 'main') {
|
||||
env.KRA_NAMESPACE = "${env.APP_NAME}-prod"
|
||||
env.KRA_ENV = 'production'
|
||||
env.KRA_CLUSTER_HOST = env.PROD_CLUSTER_HOST
|
||||
env.KUBECONFIG_CREDENTIALS = env.CRED_KUBECONFIG_PROD
|
||||
} else {
|
||||
error("Unsupported branch: ${branch}. Only dev and main deploy.")
|
||||
@@ -70,13 +70,31 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
stage('Checkout branch') {
|
||||
stage('Checkout triggered commit') {
|
||||
steps {
|
||||
// job 的 SCM branch spec 固定(如 */main),集成触发时按实际推送分支重新检出,
|
||||
// 保证单 job 同时服务 dev/main 两个环境。
|
||||
checkout([$class: 'GitSCM',
|
||||
branches: [[name: "*/${env.KRA_BRANCH}"]],
|
||||
userRemoteConfigs: [[credentialsId: 'gitlab-root-http', url: 'http://192.168.200.130/root/kra.git']]])
|
||||
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}")
|
||||
}
|
||||
if (env.KRA_TRIGGER_COMMIT && env.KRA_TRIGGER_COMMIT.replace('0', '').isEmpty()) {
|
||||
error('GitLab event points to a deleted branch; refusing to deploy')
|
||||
}
|
||||
checkout([$class: 'GitSCM',
|
||||
branches: [[name: "*/${env.KRA_BRANCH}"]],
|
||||
userRemoteConfigs: [[credentialsId: 'gitlab-root-http', url: 'http://192.168.200.130/root/kra.git']]])
|
||||
if (env.KRA_TRIGGER_COMMIT) {
|
||||
sh "git fetch --no-tags origin ${env.KRA_TRIGGER_COMMIT}"
|
||||
sh "git checkout --detach ${env.KRA_TRIGGER_COMMIT}"
|
||||
}
|
||||
env.KRA_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
|
||||
if (env.KRA_TRIGGER_COMMIT && env.KRA_COMMIT != env.KRA_TRIGGER_COMMIT) {
|
||||
error("Checked out ${env.KRA_COMMIT}, expected GitLab commit ${env.KRA_TRIGGER_COMMIT}")
|
||||
}
|
||||
echo "building commit ${env.KRA_COMMIT}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,17 +129,20 @@ pipeline {
|
||||
stage('Build and push images') {
|
||||
steps {
|
||||
script {
|
||||
env.IMAGE_TAG = "${env.KRA_BRANCH}-${env.GIT_COMMIT.take(12)}"
|
||||
env.IMAGE_TAG = "${env.KRA_BRANCH}-${env.KRA_COMMIT.take(12)}"
|
||||
}
|
||||
withCredentials([usernamePassword(credentialsId: env.CRED_HARBOR_PUSH, usernameVariable: 'HARBOR_USER', passwordVariable: 'HARBOR_PASSWORD')]) {
|
||||
sh '''
|
||||
set -eu
|
||||
echo "$HARBOR_PASSWORD" | docker login "$REGISTRY" --username "$HARBOR_USER" --password-stdin
|
||||
docker build --build-arg BIN_NAME="$BIN_NAME" -t "$REGISTRY/$IMAGE_REPO-backend:$IMAGE_TAG" .
|
||||
docker build -t "$REGISTRY/$IMAGE_REPO-frontend:$IMAGE_TAG" web
|
||||
docker push "$REGISTRY/$IMAGE_REPO-backend:$IMAGE_TAG"
|
||||
docker push "$REGISTRY/$IMAGE_REPO-frontend:$IMAGE_TAG"
|
||||
docker logout "$REGISTRY"
|
||||
umask 077
|
||||
DOCKER_CONFIG_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$DOCKER_CONFIG_DIR"' EXIT
|
||||
echo "$HARBOR_PASSWORD" | docker --config "$DOCKER_CONFIG_DIR" login "$REGISTRY" --username "$HARBOR_USER" --password-stdin >/dev/null
|
||||
docker --config "$DOCKER_CONFIG_DIR" build --build-arg BIN_NAME="$BIN_NAME" -t "$REGISTRY/$IMAGE_REPO-backend:$IMAGE_TAG" .
|
||||
docker --config "$DOCKER_CONFIG_DIR" build -t "$REGISTRY/$IMAGE_REPO-frontend:$IMAGE_TAG" web
|
||||
docker --config "$DOCKER_CONFIG_DIR" push "$REGISTRY/$IMAGE_REPO-backend:$IMAGE_TAG"
|
||||
docker --config "$DOCKER_CONFIG_DIR" push "$REGISTRY/$IMAGE_REPO-frontend:$IMAGE_TAG"
|
||||
docker --config "$DOCKER_CONFIG_DIR" logout "$REGISTRY" >/dev/null 2>&1 || true
|
||||
'''
|
||||
}
|
||||
}
|
||||
@@ -131,25 +152,46 @@ 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
|
||||
export KUBECONFIG="$KUBECONFIG_FILE"
|
||||
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 -
|
||||
kubectl -n "$KRA_NAMESPACE" create secret docker-registry harbor-registry \\
|
||||
--docker-server="$REGISTRY" --docker-username="$HARBOR_USER" --docker-password="$HARBOR_PASSWORD" \\
|
||||
DOCKER_CONFIG_DIR="$TMP_DIR/docker"
|
||||
mkdir -p "$DOCKER_CONFIG_DIR"
|
||||
printf '%s' "$HARBOR_PASSWORD" | docker --config "$DOCKER_CONFIG_DIR" login "$REGISTRY" --username "$HARBOR_USER" --password-stdin >/dev/null
|
||||
kubectl -n "$KRA_NAMESPACE" create secret generic harbor-registry \\
|
||||
--type=kubernetes.io/dockerconfigjson \\
|
||||
--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
|
||||
printf '%s' "$KRA_MYSQL_ROOT_PASSWORD" > "$TMP_DIR/mysql-root-password"
|
||||
kubectl -n "$KRA_NAMESPACE" create secret generic "${APP_NAME}-runtime" \\
|
||||
--from-literal=mysql-root-password="$KRA_MYSQL_ROOT_PASSWORD" \\
|
||||
--from-literal=database-source="root:${KRA_MYSQL_ROOT_PASSWORD}@tcp(${APP_NAME}-mysql:3306)/${APP_NAME}?charset=utf8mb4&parseTime=True&loc=Local" \\
|
||||
--from-literal=jwt-signing-key="$KRA_JWT_SIGNING_KEY" \\
|
||||
--from-literal=redis-addr="${APP_NAME}-redis:6379" \\
|
||||
--from-file=mysql-root-password="$TMP_DIR/mysql-root-password" \\
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
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" \\
|
||||
--from-file=config.yaml="$CONFIG_TEMPLATE" \\
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
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"
|
||||
envsubst "$K8S_RENDER_VARS" < deploy/k8s/kra.yaml | kubectl apply -f -
|
||||
RENDERED_MANIFEST="$TMP_DIR/manifest.yaml"
|
||||
envsubst "$K8S_RENDER_VARS" < deploy/k8s/kra.yaml > "$RENDERED_MANIFEST"
|
||||
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}')
|
||||
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
|
||||
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
|
||||
kubectl -n "$KRA_NAMESPACE" rollout status deployment/${APP_NAME}-frontend --timeout=10m
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user