diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..2f712b1 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,231 @@ +pipeline { + agent any + + environment { + // GitLab配置 + GITLAB_URL = 'https://gitlab.xpaas.lenovo.com' + GITLAB_REPO = 'artificial-intelligence-platform/lenovo-ipc' + GITLAB_CREDENTIALS_ID = 'git-ipc' + + // 镜像仓库配置 (10.128.62.130:8843) + 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' + } + + parameters { + choice(name: 'DEPLOY_ENV', choices: ['dev', 'staging', 'prod'], description: '选择部署环境') + choice(name: 'TARGET_CLUSTER', choices: ['cluster1', 'cluster2', 'both'], description: '选择目标集群') + } + + 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 { + 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}..." + echo "${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 { + // 检查 k8s 配置文件是否存在 + if (!fileExists('more_dots/k8s/deployment.yaml')) { + error "错误: more_dots/k8s/deployment.yaml 文件不存在于代码仓库中" + } + + def fullImageWithTag = "${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + def cluster = params.TARGET_CLUSTER + + if (cluster == 'cluster1' || cluster == 'both') { + deployToCluster('k3s-cluster1-config', fullImageWithTag, params.DEPLOY_ENV) + } + + if (cluster == 'cluster2' || cluster == 'both') { + deployToCluster('k3s-cluster2-config', fullImageWithTag, params.DEPLOY_ENV) + } + } + } + } + } + + post { + always { + script { + sh """ + docker logout ${REGISTRY_URL} || true + docker rmi ${FULL_IMAGE_NAME}:${env.IMAGE_TAG} || true + """ + } + cleanWs() + echo "构建结束。镜像标签: ${env.IMAGE_TAG}" + echo "完整镜像: ${FULL_IMAGE_NAME}:${env.IMAGE_TAG}" + echo "是否跳过构建: ${env.SKIP_BUILD}" + echo "部署环境: ${params.DEPLOY_ENV}" + echo "目标集群: ${params.TARGET_CLUSTER}" + } + 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路径 + 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 "部署到集群: ${clusterConfigId}" + echo "部署环境: ${deployEnv}" + echo "镜像: ${fullImageWithTag}" + echo "命名空间: ${K8S_NAMESPACE}" + + # 定义kubectl函数 + k() { + sudo \$KUBECTL_PATH --kubeconfig=${KUBECONFIG} "\$@" + } + + # 检查命名空间 + k get namespace ${K8S_NAMESPACE} || k create namespace ${K8S_NAMESPACE} + + # 创建imagePullSecret + 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: ${fullImageWithTag}|g" \\ + -e "s|value: \".*\"|value: \"${deployEnv}\"|g" \\ + more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml + + echo "部署配置:" + cat /tmp/deployment-${K8S_NAMESPACE}.yaml + + # 应用配置到 more-dots 命名空间 + 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 + """ + } +} \ No newline at end of file diff --git a/Jenkinsfile_dev b/Jenkinsfile_dev index 4dc4e25..d410b03 100644 --- a/Jenkinsfile_dev +++ b/Jenkinsfile_dev @@ -187,7 +187,7 @@ def deployToCluster(String clusterConfigId, String fullImageWithTag) { --namespace="${K8S_NAMESPACE}" \ --dry-run=client -o yaml | k apply -f - - sed -e "s|image:.*more_dots:.*|image: ${FULL_IMAGE_WITH_TAG}|g" \ + sed -E "s|^([[:space:]]*image:).*$|\1 ${FULL_IMAGE_WITH_TAG}|" \ more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml k apply -f /tmp/deployment-${K8S_NAMESPACE}.yaml -n "${K8S_NAMESPACE}" diff --git a/Jenkinsfile_prod b/Jenkinsfile_prod index 3b2c57a..921bb33 100644 --- a/Jenkinsfile_prod +++ b/Jenkinsfile_prod @@ -187,7 +187,7 @@ def deployToCluster(String clusterConfigId, String fullImageWithTag) { --namespace="${K8S_NAMESPACE}" \ --dry-run=client -o yaml | k apply -f - - sed -e "s|image:.*more_dots:.*|image: ${FULL_IMAGE_WITH_TAG}|g" \ + sed -E "s|^([[:space:]]*image:).*$|\1 ${FULL_IMAGE_WITH_TAG}|" \ more_dots/k8s/deployment.yaml > /tmp/deployment-${K8S_NAMESPACE}.yaml k apply -f /tmp/deployment-${K8S_NAMESPACE}.yaml -n "${K8S_NAMESPACE}" diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml index 017f00b..39040f2 100644 --- a/k8s/deployment.yaml +++ b/k8s/deployment.yaml @@ -15,12 +15,9 @@ spec: spec: containers: - name: more-dots - image: harbor.yourdomain.com/library/more_dots:${IMAGE_TAG} + image: 10.128.62.130:8843/more_dots:latest ports: - containerPort: 8000 - env: - - name: ENVIRONMENT - value: ${DEPLOY_ENV} --- apiVersion: v1 kind: Service