From a0e3ac7b8d0bb55c66fdbc73f0ec6a9c5c6966d3 Mon Sep 17 00:00:00 2001 From: chenjw28 <792430652@qq.com> Date: Tue, 3 Mar 2026 11:29:30 +0800 Subject: [PATCH] init --- Jenkinsfile_dev | 215 +++++++++++++++++++++++++++++++++++++++++++++++ Jenkinsfile_prod | 215 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 Jenkinsfile_dev create mode 100644 Jenkinsfile_prod diff --git a/Jenkinsfile_dev b/Jenkinsfile_dev new file mode 100644 index 0000000..c2e904e --- /dev/null +++ b/Jenkinsfile_dev @@ -0,0 +1,215 @@ +pipeline { + agent any + + environment { + GITLAB_URL = 'https://gitlab.xpaas.lenovo.com' + GITLAB_REPO = 'artificial-intelligence-platform/lenovo-ipc' + GITLAB_CREDENTIALS_ID = 'git-ipc' + + REGISTRY_URL = '10.128.62.130:8843' + REGISTRY_CREDENTIALS_ID = 'docker-registry-130' + + IMAGE_NAME = 'more_dots' + FULL_IMAGE_NAME = "${REGISTRY_URL}/${IMAGE_NAME}" + + SKIP_BUILD = 'false' + K8S_NAMESPACE = 'more-dots' + + CLUSTER_CONFIG_ID = 'k3s-cluster1-config' + CLUSTER_NAME = 'cluster1' + } + + parameters { + choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: '选择部署环境') + choice(name: 'BUILD_POLICY', choices: ['auto', 'force_build', 'skip_build'], description: '构建策略:auto=按代码变更判断') + } + + stages { + stage('Checkout') { + steps { + git( + url: "${GITLAB_URL}/${GITLAB_REPO}.git", + credentialsId: GITLAB_CREDENTIALS_ID, + branch: 'master' + ) + script { + env.GIT_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim() + env.SOURCE_TREE = sh(script: 'git rev-parse HEAD:more_dots', returnStdout: true).trim() + env.IMAGE_TAG = env.SOURCE_TREE.take(12) + + echo "GIT_COMMIT: ${env.GIT_COMMIT}" + echo "SOURCE_TREE: ${env.SOURCE_TREE}" + echo "IMAGE_TAG: ${env.IMAGE_TAG}" + echo "FULL_IMAGE_NAME: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + } + } + } + + stage('Check Code Changes') { + steps { + script { + if (params.BUILD_POLICY == 'force_build') { + env.SKIP_BUILD = 'false' + echo "BUILD_POLICY=force_build,强制构建" + } else if (params.BUILD_POLICY == 'skip_build') { + env.SKIP_BUILD = 'true' + echo "BUILD_POLICY=skip_build,跳过构建" + } else { + def prev = env.GIT_PREVIOUS_SUCCESSFUL_COMMIT ?: '' + if (!prev?.trim()) { + echo "未找到上次成功构建提交,默认执行构建" + env.SKIP_BUILD = 'false' + } else { + int rc = sh( + script: "git diff --quiet ${prev} HEAD -- more_dots", + returnStatus: true + ) + env.SKIP_BUILD = (rc == 0) ? 'true' : 'false' + } + } + + echo "代码变更检查结果: SKIP_BUILD=${env.SKIP_BUILD}" + } + } + } + + stage('Build Docker Image') { + when { + expression { env.SKIP_BUILD != 'true' } + } + steps { + dir('more_dots') { + sh """ + docker build --progress=plain \ + --build-arg PIP_OPTIONS=\"--no-hash-check\" \ + -t ${IMAGE_NAME}:${env.IMAGE_TAG} . + """ + } + } + } + + stage('Push to Registry') { + when { + expression { env.SKIP_BUILD != 'true' } + } + steps { + script { + withCredentials([usernamePassword( + credentialsId: REGISTRY_CREDENTIALS_ID, + usernameVariable: 'REGISTRY_USER', + passwordVariable: 'REGISTRY_PASS' + )]) { + sh ''' + set -eux + echo "登录到镜像仓库 ${REGISTRY_URL}..." + printf '%s' "$REGISTRY_PASS" | docker login "$REGISTRY_URL" -u "$REGISTRY_USER" --password-stdin + ''' + } + + sh ''' + set -eux + echo "打标签: ${IMAGE_NAME}:${IMAGE_TAG} -> ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + docker tag "${IMAGE_NAME}:${IMAGE_TAG}" "${FULL_IMAGE_NAME}:${IMAGE_TAG}" + + echo "推送镜像到仓库..." + docker push "${FULL_IMAGE_NAME}:${IMAGE_TAG}" + + echo "镜像推送完成: ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + ''' + } + } + } + + stage('Deploy to k3s') { + steps { + script { + if (!fileExists('more_dots/k8s/deployment.yaml')) { + error "错误: more_dots/k8s/deployment.yaml 文件不存在于代码仓库中" + } + + def fullImageWithTag = "${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + deployToCluster(CLUSTER_CONFIG_ID, fullImageWithTag, params.DEPLOY_ENV) + } + } + } + } + + post { + always { + script { + sh ''' + docker logout "${REGISTRY_URL}" || true + docker rmi "${FULL_IMAGE_NAME}:${IMAGE_TAG}" || true + ''' + } + cleanWs() + echo "构建结束。镜像标签: ${env.IMAGE_TAG}" + echo "完整镜像: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + echo "是否跳过构建: ${env.SKIP_BUILD}" + echo "部署环境: ${params.DEPLOY_ENV}" + echo "目标集群: ${CLUSTER_NAME}" + } + failure { + echo "构建失败,请检查日志" + } + } +} + +def deployToCluster(String clusterConfigId, String fullImageWithTag, String deployEnv) { + withCredentials([ + file(credentialsId: clusterConfigId, variable: 'KUBECONFIG'), + usernamePassword(credentialsId: REGISTRY_CREDENTIALS_ID, + usernameVariable: 'REGISTRY_USER', + passwordVariable: 'REGISTRY_PASS') + ]) { + sh ''' + set -eux + + KUBECTL_PATH=$(command -v kubectl 2>/dev/null || true) + if [ -z "$KUBECTL_PATH" ]; then + for p in /usr/local/bin/kubectl /usr/bin/kubectl /bin/kubectl; do + if [ -x "$p" ]; then + KUBECTL_PATH="$p" + break + fi + done + fi + + if [ -z "$KUBECTL_PATH" ]; then + echo "kubectl 未找到,请检查 Jenkins 节点环境" + exit 1 + fi + + echo "使用kubectl路径: $KUBECTL_PATH" + echo "部署到集群: ${CLUSTER_NAME}" + echo "部署环境: ${DEPLOY_ENV}" + echo "镜像: ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + echo "命名空间: ${K8S_NAMESPACE}" + + k() { + sudo "$KUBECTL_PATH" --kubeconfig="$KUBECONFIG" "$@" + } + + k get namespace "${K8S_NAMESPACE}" || k create namespace "${K8S_NAMESPACE}" + + k create secret docker-registry regcred-130 \ + --docker-server="${REGISTRY_URL}" \ + --docker-username="${REGISTRY_USER}" \ + --docker-password="${REGISTRY_PASS}" \ + --namespace="${K8S_NAMESPACE}" \ + --dry-run=client -o yaml | k apply -f - + + sed -e "s|image:.*more_dots:.*|image: ${FULL_IMAGE_NAME}:${IMAGE_TAG}|g" \ + -e "s|value: \".*\"|value: \"${DEPLOY_ENV}\"|g" \ + more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml + + k apply -f /tmp/deployment-${K8S_NAMESPACE}.yaml -n "${K8S_NAMESPACE}" + + echo "等待部署完成..." + k rollout status deployment/more-dots -n "${K8S_NAMESPACE}" --timeout=300s + + echo "部署完成,查看pod状态:" + k get pods -n "${K8S_NAMESPACE}" -l app=more-dots + ''' + } +} diff --git a/Jenkinsfile_prod b/Jenkinsfile_prod new file mode 100644 index 0000000..9db459c --- /dev/null +++ b/Jenkinsfile_prod @@ -0,0 +1,215 @@ +pipeline { + agent any + + environment { + GITLAB_URL = 'https://gitlab.xpaas.lenovo.com' + GITLAB_REPO = 'artificial-intelligence-platform/lenovo-ipc' + GITLAB_CREDENTIALS_ID = 'git-ipc' + + REGISTRY_URL = '10.128.62.130:8843' + REGISTRY_CREDENTIALS_ID = 'docker-registry-130' + + IMAGE_NAME = 'more_dots' + FULL_IMAGE_NAME = "${REGISTRY_URL}/${IMAGE_NAME}" + + SKIP_BUILD = 'false' + K8S_NAMESPACE = 'more-dots' + + CLUSTER_CONFIG_ID = 'k3s-cluster2-config' + CLUSTER_NAME = 'cluster2' + } + + parameters { + choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: '选择部署环境') + choice(name: 'BUILD_POLICY', choices: ['auto', 'force_build', 'skip_build'], description: '构建策略:auto=按代码变更判断') + } + + stages { + stage('Checkout') { + steps { + git( + url: "${GITLAB_URL}/${GITLAB_REPO}.git", + credentialsId: GITLAB_CREDENTIALS_ID, + branch: 'master' + ) + script { + env.GIT_COMMIT = sh(script: 'git rev-parse HEAD', returnStdout: true).trim() + env.SOURCE_TREE = sh(script: 'git rev-parse HEAD:more_dots', returnStdout: true).trim() + env.IMAGE_TAG = env.SOURCE_TREE.take(12) + + echo "GIT_COMMIT: ${env.GIT_COMMIT}" + echo "SOURCE_TREE: ${env.SOURCE_TREE}" + echo "IMAGE_TAG: ${env.IMAGE_TAG}" + echo "FULL_IMAGE_NAME: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + } + } + } + + stage('Check Code Changes') { + steps { + script { + if (params.BUILD_POLICY == 'force_build') { + env.SKIP_BUILD = 'false' + echo "BUILD_POLICY=force_build,强制构建" + } else if (params.BUILD_POLICY == 'skip_build') { + env.SKIP_BUILD = 'true' + echo "BUILD_POLICY=skip_build,跳过构建" + } else { + def prev = env.GIT_PREVIOUS_SUCCESSFUL_COMMIT ?: '' + if (!prev?.trim()) { + echo "未找到上次成功构建提交,默认执行构建" + env.SKIP_BUILD = 'false' + } else { + int rc = sh( + script: "git diff --quiet ${prev} HEAD -- more_dots", + returnStatus: true + ) + env.SKIP_BUILD = (rc == 0) ? 'true' : 'false' + } + } + + echo "代码变更检查结果: SKIP_BUILD=${env.SKIP_BUILD}" + } + } + } + + stage('Build Docker Image') { + when { + expression { env.SKIP_BUILD != 'true' } + } + steps { + dir('more_dots') { + sh """ + docker build --progress=plain \ + --build-arg PIP_OPTIONS=\"--no-hash-check\" \ + -t ${IMAGE_NAME}:${env.IMAGE_TAG} . + """ + } + } + } + + stage('Push to Registry') { + when { + expression { env.SKIP_BUILD != 'true' } + } + steps { + script { + withCredentials([usernamePassword( + credentialsId: REGISTRY_CREDENTIALS_ID, + usernameVariable: 'REGISTRY_USER', + passwordVariable: 'REGISTRY_PASS' + )]) { + sh ''' + set -eux + echo "登录到镜像仓库 ${REGISTRY_URL}..." + printf '%s' "$REGISTRY_PASS" | docker login "$REGISTRY_URL" -u "$REGISTRY_USER" --password-stdin + ''' + } + + sh ''' + set -eux + echo "打标签: ${IMAGE_NAME}:${IMAGE_TAG} -> ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + docker tag "${IMAGE_NAME}:${IMAGE_TAG}" "${FULL_IMAGE_NAME}:${IMAGE_TAG}" + + echo "推送镜像到仓库..." + docker push "${FULL_IMAGE_NAME}:${IMAGE_TAG}" + + echo "镜像推送完成: ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + ''' + } + } + } + + stage('Deploy to k3s') { + steps { + script { + if (!fileExists('more_dots/k8s/deployment.yaml')) { + error "错误: more_dots/k8s/deployment.yaml 文件不存在于代码仓库中" + } + + def fullImageWithTag = "${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + deployToCluster(CLUSTER_CONFIG_ID, fullImageWithTag, params.DEPLOY_ENV) + } + } + } + } + + post { + always { + script { + sh ''' + docker logout "${REGISTRY_URL}" || true + docker rmi "${FULL_IMAGE_NAME}:${IMAGE_TAG}" || true + ''' + } + cleanWs() + echo "构建结束。镜像标签: ${env.IMAGE_TAG}" + echo "完整镜像: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + echo "是否跳过构建: ${env.SKIP_BUILD}" + echo "部署环境: ${params.DEPLOY_ENV}" + echo "目标集群: ${CLUSTER_NAME}" + } + failure { + echo "构建失败,请检查日志" + } + } +} + +def deployToCluster(String clusterConfigId, String fullImageWithTag, String deployEnv) { + withCredentials([ + file(credentialsId: clusterConfigId, variable: 'KUBECONFIG'), + usernamePassword(credentialsId: REGISTRY_CREDENTIALS_ID, + usernameVariable: 'REGISTRY_USER', + passwordVariable: 'REGISTRY_PASS') + ]) { + sh ''' + set -eux + + KUBECTL_PATH=$(command -v kubectl 2>/dev/null || true) + if [ -z "$KUBECTL_PATH" ]; then + for p in /usr/local/bin/kubectl /usr/bin/kubectl /bin/kubectl; do + if [ -x "$p" ]; then + KUBECTL_PATH="$p" + break + fi + done + fi + + if [ -z "$KUBECTL_PATH" ]; then + echo "kubectl 未找到,请检查 Jenkins 节点环境" + exit 1 + fi + + echo "使用kubectl路径: $KUBECTL_PATH" + echo "部署到集群: ${CLUSTER_NAME}" + echo "部署环境: ${DEPLOY_ENV}" + echo "镜像: ${FULL_IMAGE_NAME}:${IMAGE_TAG}" + echo "命名空间: ${K8S_NAMESPACE}" + + k() { + sudo "$KUBECTL_PATH" --kubeconfig="$KUBECONFIG" "$@" + } + + k get namespace "${K8S_NAMESPACE}" || k create namespace "${K8S_NAMESPACE}" + + k create secret docker-registry regcred-130 \ + --docker-server="${REGISTRY_URL}" \ + --docker-username="${REGISTRY_USER}" \ + --docker-password="${REGISTRY_PASS}" \ + --namespace="${K8S_NAMESPACE}" \ + --dry-run=client -o yaml | k apply -f - + + sed -e "s|image:.*more_dots:.*|image: ${FULL_IMAGE_NAME}:${IMAGE_TAG}|g" \ + -e "s|value: \".*\"|value: \"${DEPLOY_ENV}\"|g" \ + more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml + + k apply -f /tmp/deployment-${K8S_NAMESPACE}.yaml -n "${K8S_NAMESPACE}" + + echo "等待部署完成..." + k rollout status deployment/more-dots -n "${K8S_NAMESPACE}" --timeout=300s + + echo "部署完成,查看pod状态:" + k get pods -n "${K8S_NAMESPACE}" -l app=more-dots + ''' + } +}