def RELEASE_VERSION = env.BUILD_NUMBER
currentBuild.displayName = RELEASE_VERSION
println "Original Release Version: ${RELEASE_VERSION}"
/**
* 拆分管道脚本,将远程查询命令单独执行,以确保在返回异常exit code时中断pipeline
* @param REMOTE_ACQUIRE 远程查询命令
* @param EDIT 本地编辑命令
* @return
*/
def sh_pipe(REMOTE_QUERY, EDIT) {
ret = sh(returnStdout: true, script: "${REMOTE_QUERY} > temp")
return sh(returnStdout: true, script: "cat ./temp | ${EDIT}").trim()
}
def update_values (DEVOPS_CICD_REPOSITORY_NAME, DEVOPS_CICD_BRANCH, SVC) {
// sh script: "update_values方法开始执行"
sh script: "echo update_values方法开始执行"
sh script: "rm -rf devops_cicd && mkdir devops_cicd"
sh script: "git clone -b ${DEVOPS_CICD_BRANCH} ${GERRIT_REPO_URL}/${DEVOPS_CICD_REPOSITORY_NAME}"
sh script: "rm -rf k8s-values && mkdir k8s-values"
sh script: "cp -rf ./devops_cicd/k8s-values/${SVC} ./k8s-values/"
sh script: "rm -rf ./devops_cicd"
// sh script: "update_values方法执行完毕"
}
def render_config_map_data (SVC, DEPLOY_ENVIRONMENT, RGN) {
OPERATION_FLAG = "error parameter"
if ("${DEPLOY_ENVIRONMENT}" == 'dev2' || "${DEPLOY_ENVIRONMENT}" == 'staging2' || "${DEPLOY_ENVIRONMENT}" == 'uat2' || "${DEPLOY_ENVIRONMENT}" == 'uat3' || "${DEPLOY_ENVIRONMENT}" == 'uat4' || "${DEPLOY_ENVIRONMENT}" == 'uat5' || "${DEPLOY_ENVIRONMENT}" == 'uat6' || "${DEPLOY_ENVIRONMENT}" == 'pet2' || "${DEPLOY_ENVIRONMENT}" == 'pet3') {
// 多环境参数, 如uat2,uat3, dev2,staging2等
OPERATION_FLAG = "multiple environment parameter"
}
if ("${DEPLOY_ENVIRONMENT}" == 'dev' || "${DEPLOY_ENVIRONMENT}" == 'uat' || "${DEPLOY_ENVIRONMENT}" == 'staging' || "${DEPLOY_ENVIRONMENT}" == 'pet' || "${DEPLOY_ENVIRONMENT}" == 'prd') {
// 单环境参数
OPERATION_FLAG = "single environment parameter"
}
// 判断devops_cicd仓库中有无存放对应环境配置的文件夹
VERSION_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT} ] && echo 'true' || echo 'false'")
if (!VERSION_DIR_EXIST_FLAG.toBoolean()) {
OPERATION_FLAG = "error parameter"
}
// 判断devops_cicd仓库中Global文件夹是否存在
GLOBAL_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${SVC}/global ] && echo 'true' || echo 'false'")
// 判断devops_cicd仓库中每个环境的common文件夹是否存在
COMMON_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/common ] && echo 'true' || echo 'false'")
// 判断devops_cicd仓库中每个环境的每个区域下的config文件是否存在
CONFIG_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/config ] && echo 'true' || echo 'false'")
RENDER_FILE_ARG = ""
if (OPERATION_FLAG == 'single environment parameter') {
RENDER_FILE_ARG += GLOBAL_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/global " : ""
RENDER_FILE_ARG += COMMON_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/common " : ""
RENDER_FILE_ARG += CONFIG_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/config " : ""
} else if (OPERATION_FLAG == 'multiple environment parameter'){
VER_COMMON_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/common ] && echo 'true' || echo 'false'")
VER_CONFIG_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/config ] && echo 'true' || echo 'false'")
RENDER_FILE_ARG += GLOBAL_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/global " : ""
RENDER_FILE_ARG += VER_COMMON_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/common " : "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/common "
RENDER_FILE_ARG += VER_CONFIG_DIR_EXIST_FLAG.toBoolean() ? "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/config " : "--from-file=./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/config "
}
if (OPERATION_FLAG != 'error parameter') {
sh script: "kubectl create configmap ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-tmp-config \
${RENDER_FILE_ARG} \
--dry-run -o=yaml > ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-tmp.yaml"
sh script: "yq read ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-tmp.yaml data > ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-config-map-data.yaml"
sh script: "yq prefix -i ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-config-map-data.yaml configMap.data"
}
}
/**
* 网络初始化:导入service、istio(gateway/virtualService), Note: 每个服务在所有区建立同名namespace,service将导入所有区
* @param ENV 集群环境,用于指定K8S集群
* @param RGN 部署区域
* @param DEPLOY_ENV 部署环境,用于区分staging、uat2、uat3、pet等环境
* @param ISTIO_RGN Istio主区
* @return
*/
def networking_init(ENV, RGN, DEPLOY_ENV, ISTIO_RGN) {
if ("${DEPLOY_DEPART}" == ("BASIC_CLOUD")) {
// 基础云service仅导入部署区
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${params.KUBE_CONTEXT}"
} else {
// 业务云service导入所有区:
if ("${ENV}".contains("dev")) {
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.ap-southeast-1"
} else if ("${ENV}".contains("pet")) {
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.ap-southeast-1"
} else if ("${ENV}".contains("uat")) {
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.ap-southeast-1"
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.us-east-1"
} else if ("${ENV}".contains("staging")) {
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.ap-southeast-1"
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.us-east-1"
} else if ("${ENV}".contains("prd")) {
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.ap-southeast-1"
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.us-east-1"
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/service.yaml --context ${ENV}.eu-west-1"
}
}
sh script: "kubectl apply -f ./k8s-values/${env.SERVICE}/${DEPLOY_ENV}/${RGN}/networking/istio.yaml --context ${ENV}.${ISTIO_RGN}"
sh script: "echo networking init successfully"
}
def helm_upgrade (ENV, ISTIO_RGN, SVC, DEPLOY_ENVIRONMENT, RGN, VER, NSP) {
// 获取K8S namespace
K8S_NSP = sh(returnStdout: true, script: "yq read ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml app.namespace").trim()
// 获取服务名称
PREVIOUS_DEPLOY = sh_pipe("kubectl get deployment -n ${K8S_NSP} --context ${params.KUBE_CONTEXT}", "grep '${env.SERVICE}' | cut -d ' ' -f 1")
// 服务第一次部署时,无需对pod扩容
if (PREVIOUS_DEPLOY) {
// 获取线上版本的副本数配置
ONLINE_MIN_REPLICAS = sh_pipe("kubectl get hpa ${PREVIOUS_DEPLOY} -o yaml -n ${K8S_NSP} --context ${params.KUBE_CONTEXT}", "yq read - 'spec.minReplicas'")
ONLINE_MAX_REPLICAS = sh_pipe("kubectl get hpa ${PREVIOUS_DEPLOY} -o yaml -n ${K8S_NSP} --context ${params.KUBE_CONTEXT}", "yq read - 'spec.maxReplicas'")
CURRENT_REPLICAS = sh_pipe("kubectl get deployment ${PREVIOUS_DEPLOY} -o yaml -n ${K8S_NSP} --context ${params.KUBE_CONTEXT}", "yq read - 'spec.replicas'")
println("ONLINE_MIN_REPLICAS: ${ONLINE_MIN_REPLICAS}")
println("ONLINE_MAX_REPLICAS: ${ONLINE_MAX_REPLICAS}")
println("CURRENT_REPLICAS: ${CURRENT_REPLICAS}")
// 将该副本数更新到滚动更新所使用values中replicaCount字段的值
sh script: "yq write -i ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml 'replicaCount' ${CURRENT_REPLICAS}"
// HPA配置选择线上与CICD配置之间的较大值
CICD_HPA_MIN = sh(returnStdout: true, script: "yq read ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml autoscaling.minReplicas").trim()
CICD_HPA_MAX = sh(returnStdout: true, script: "yq read ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml autoscaling.maxReplicas").trim()
println("CICD_HPA_MIN: ${CICD_HPA_MIN}")
println("CICD_HPA_MAX: ${CICD_HPA_MAX}")
if (Integer.parseInt(ONLINE_MIN_REPLICAS) > Integer.parseInt(CICD_HPA_MIN)) {
sh script: "yq write -i ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml 'autoscaling.minReplicas' ${ONLINE_MIN_REPLICAS}"
}
if (Integer.parseInt(ONLINE_MAX_REPLICAS) > Integer.parseInt(CICD_HPA_MAX)) {
sh script: "yq write -i ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml 'autoscaling.maxReplicas' ${ONLINE_MAX_REPLICAS}"
}
}
OPERATION_FLAG = "error parameter"
if ("${DEPLOY_ENVIRONMENT}" == 'dev2' || "${DEPLOY_ENVIRONMENT}" == 'staging2' || "${DEPLOY_ENVIRONMENT}" == 'uat2' || "${DEPLOY_ENVIRONMENT}" == 'uat3' || "${DEPLOY_ENVIRONMENT}" == 'uat4' || "${DEPLOY_ENVIRONMENT}" == 'uat5' || "${DEPLOY_ENVIRONMENT}" == 'uat6' || "${DEPLOY_ENVIRONMENT}" == 'pet2' || "${DEPLOY_ENVIRONMENT}" == 'pet3') {
// 多环境参数, 如uat2,uat3, dev2,staging2等
OPERATION_FLAG = "multiple environment parameter"
}
if ("${DEPLOY_ENVIRONMENT}" == 'dev' || "${DEPLOY_ENVIRONMENT}" == 'uat' || "${DEPLOY_ENVIRONMENT}" == 'staging' || "${DEPLOY_ENVIRONMENT}" == 'pet' || "${DEPLOY_ENVIRONMENT}" == 'prd') {
// 单环境参数
OPERATION_FLAG = "single environment parameter"
}
// 当为单环境参数时,用这个参数判断“服务/单环境名称/区域”路径是否存在
DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN} ] && echo 'true' || echo 'false'")
// 当为多环境参数时,用这个参数判断“服务/多环境名称/区域”路径是否存在
NEW_DIR_EXIST_FLAG = sh(returnStdout: true, script: "[ -d ./k8s-values/${env.SERVICE}/${DEPLOY_ENVIRONMENT}/${RGN} ] && echo 'true' || echo 'false'")
// 网络配置初始化
sh script: "echo networking init"
networking_init(ENV, RGN, DEPLOY_ENVIRONMENT, ISTIO_RGN)
// 根据集群版本不同,kube-context值不同
if (OPERATION_FLAG == 'single environment parameter' && DIR_EXIST_FLAG.toBoolean()) {
sh script: "AWS_DEFAULT_REGION=ap-southeast-1 AWS_PROFILE=uat helm upgrade \
--install ${SVC} prd-tplink-nbu/${SVC} \
--version ${VER} \
--values ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml \
--values ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-config-map-data.yaml \
--namespace ${NSP} \
--kube-context ${params.KUBE_CONTEXT} \
--timeout 600s \
--wait"
} else if (OPERATION_FLAG == 'multiple environment parameter' && NEW_DIR_EXIST_FLAG.toBoolean()) {
NEW_NSP = sh (returnStdout: true, script: "echo \$(cat ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml | grep 'namespace' | sed 's/namespace://')").trim()
sh script: "AWS_DEFAULT_REGION=ap-southeast-1 AWS_PROFILE=uat helm upgrade \
--install ${SVC} prd-tplink-nbu/${SVC} \
--version ${VER} \
--values ./k8s-values/${SVC}/${DEPLOY_ENVIRONMENT}/${RGN}/values.yaml \
--values ${SVC}-${DEPLOY_ENVIRONMENT}-${RGN}-config-map-data.yaml \
--namespace ${NEW_NSP} \
--kube-context ${params.KUBE_CONTEXT} \
--timeout 600s \
--wait"
} else {
sh script: "echo version ${VER} will not deploy to ${DEPLOY_ENVIRONMENT} ${RGN}"
}
}
pipeline {
agent any
environment {
PIPELINE_DIR = "./build-${env.BUILD_ID}"
SERVICE = 'omada-sale-assistant'
}
parameters {
choice(
name: 'DEPLOY_ENVIRONMENT',
choices: ['dev', 'uat', 'uat2', 'uat3', 'uat4', 'uat5', 'uat6', 'pet', 'pet2', 'pet3', 'staging', 'prd'],
description: '部署的环境'
)
string(
name: 'DEPLOY_VERSION',
defaultValue: '',
description: '请输入要部署的3位版本号'
)
string(
name: 'DEPLOY_PASSWORD',
defaultValue: '',
description: '当进行生产环境部署时,请在此处输入生产环境部署密钥'
)
choice(
name: 'DEPLOY_REGION',
choices: ['ap-southeast-1', 'us-east-1', 'eu-west-1'],
description: '部署的区域'
)
string(
name: 'DEVOPS_CICD_BRANCH',
defaultValue: 'master',
description: 'devops_cicd使用的分支'
)
string(
name: 'DEVOPS_CICD_REPOSITORY_NAME',
defaultValue: 'SMB/solution/devops_cicd',
description: 'devops_cicd仓库名称'
)
choice(
name: 'KUBE_CONTEXT',
choices: ['dev-v2.ap-southeast-1', 'uat-v2.ap-southeast-1', 'uat-v2.us-east-1'],
description: 'K8S集群'
)
}
options {
timestamps()
}
stages {
stage('Sync Up Release') {
steps {
echo "Sync up ${env.SERVICE} release ..."
script {
println "Major Deploy Version: ${params.DEPLOY_VERSION}"
sh script: 'AWS_DEFAULT_REGION=ap-southeast-1 AWS_PROFILE=uat helm repo update'
RELEASE_VERSION = sh(returnStdout: true, script: "helm search repo prd-tplink-nbu/${env.SERVICE} --version ${params.DEPLOY_VERSION} | grep -w 'prd-tplink-nbu/${env.SERVICE}' | head -1 | cut -f 2").trim()
if (RELEASE_VERSION == '') {
error "helm chart ${env.SERVICE}-${params.DEPLOY_VERSION}.tgz doesn't exist"
}
env.BUILD_NUMBER = RELEASE_VERSION
currentBuild.displayName = RELEASE_VERSION
println "Latest Release Version: ${RELEASE_VERSION}"
}
echo 'Creating build directories ...'
sh script: "mkdir ${env.PIPELINE_DIR}"
}
}
stage('Promote Stage') {
steps {
input id: "promote", message: "Promote to ${params.DEPLOY_ENVIRONMENT}-${params.DEPLOY_REGION}?"
}
}
stage('Deploy Stage') {
steps {
sleep 3
echo "Deploying ${env.SERVICE} Release v${RELEASE_VERSION} to ${params.DEPLOY_ENVIRONMENT}-${params.DEPLOY_REGION} ..."
dir("${env.PIPELINE_DIR}") {
load "$JENKINS_HOME/tmpEnvVariable.groovy"
script {
update_values ("${params.DEVOPS_CICD_REPOSITORY_NAME}", "${params.DEVOPS_CICD_BRANCH}", "${env.SERVICE}")
if ("${params.KUBE_CONTEXT}".contains("cloud")) {
DEPLOY_DEPART = "BASIC_CLOUD"
// 判断基础云istio主区,与部署区域相同
ISTIO_RGN = params.DEPLOY_REGION
} else {
DEPLOY_DEPART = "NBU_CLOUD"
// 判断业务云服务istio主区
if (params.DEPLOY_ENVIRONMENT == "prd") {
ISTIO_RGN = "eu-west-1"
} else if ("${params.DEPLOY_ENVIRONMENT}".contains("dev")) {
// dev集群主区为亚太区
ISTIO_RGN = "ap-southeast-1"
} else {
// 其余uat集群主区为美国区
ISTIO_RGN = "us-east-1"
}
}
// 仅保留部署环境中的字母部分,主要用于istio主区场景下拼接集群参数
ENV = "${params.DEPLOY_ENVIRONMENT}".replaceAll("[^(a-z)]", "")
// 红蓝环境ENV定为uat
if (params.DEPLOY_ENVIRONMENT == "redblue") {
ENV = "uat"
}
// 若部署集群为v2集群,则环境后添加-v2后缀。
if ("${params.KUBE_CONTEXT}".contains("v2")) {
ENV = "${ENV}" + "-v2"
} else if ("${params.KUBE_CONTEXT}".contains("cloud")) {
// 若部署集群为基础云集群,环境添加-cloud后缀
ENV = "${ENV}" + "-cloud"
}
echo "ENV: ${ENV}"
echo "Deployed to ${params.DEPLOY_ENVIRONMENT}-${params.DEPLOY_REGION}"
if ("${params.DEPLOY_ENVIRONMENT}" == 'dev' || "${params.DEPLOY_ENVIRONMENT}" == 'dev2') {
render_config_map_data ("${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}")
helm_upgrade ("${ENV}", "${ISTIO_RGN}", "${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}", "${RELEASE_VERSION}", "default")
} else if ("${params.DEPLOY_ENVIRONMENT}" == 'uat' || "${params.DEPLOY_ENVIRONMENT}" == 'uat2' || "${params.DEPLOY_ENVIRONMENT}" == 'uat3' || "${params.DEPLOY_ENVIRONMENT}" == 'uat4' || "${params.DEPLOY_ENVIRONMENT}" == 'uat5' || "${params.DEPLOY_ENVIRONMENT}" == 'uat6') {
render_config_map_data ("${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}")
helm_upgrade ("${ENV}", "${ISTIO_RGN}", "${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}", "${RELEASE_VERSION}", "default")
} else if ("${params.DEPLOY_ENVIRONMENT}" == 'pet' || "${params.DEPLOY_ENVIRONMENT}" == 'pet2' || "${params.DEPLOY_ENVIRONMENT}" == 'pet3') {
render_config_map_data ("${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}")
helm_upgrade ("${ENV}", "${ISTIO_RGN}", "${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}", "${RELEASE_VERSION}", "pet")
} else if ("${params.DEPLOY_ENVIRONMENT}" == 'staging' || "${params.DEPLOY_ENVIRONMENT}" == 'staging2' || "${params.DEPLOY_ENVIRONMENT}" == 'staging3'){
render_config_map_data ("${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}")
helm_upgrade ("${ENV}", "${ISTIO_RGN}", "${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}", "${RELEASE_VERSION}", "staging")
} else if ("${params.DEPLOY_ENVIRONMENT}" == 'prd') {
render_config_map_data ("${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}")
helm_upgrade ("${ENV}", "${ISTIO_RGN}", "${env.SERVICE}", "${params.DEPLOY_ENVIRONMENT}", "${params.DEPLOY_REGION}", "${RELEASE_VERSION}", "default")
} else {
echo "Internal error"
exit -1
}
}
}
}
}
stage('Test Stage') {
steps {
echo "Test Successful on ${params.DEPLOY_ENVIRONMENT}-${params.DEPLOY_REGION}"
}
}
}
}
给我详细讲一下上面这段脚本的逻辑
最新发布