前言
在持續集成和部署中,我們通常需要部署多個實例或組件到Kubernetes集群中。通過Jenkins的管道腳本,我們可以自動化這個過程。在本文中,我將演示如何使用Jenkins Pipeline及單個YAML模板文件(.tpl)來部署多個類似的Kubernetes組件,而不需要為每個組件提供單獨的模板文件。
問題背景
Jenkins Pipeline 腳本優化實踐:從繁瑣到簡潔批量生成 Kubernetes 部署模板:從 1 到20順序模板
pipeline { agent none // Use none at the top level, each stage will define its own agent. environment { REGISTRY = "xxxx/master-metaspace" KUBE_CONFIG = "--namespace=master-metaspace --context=master" KUBE_YAML_PATH = "/home/jenkins/workspace/yaml/master-metaspace" // Assume that 'data' is defined elsewhere or injected as a parameter. BASE_WORKSPACE = "xxxxxxx" // 定義一個基礎工作空間路徑 } stages { stage("GetCode") { agent { label "build01" } steps { script { checkout scm: [ $class: 'GitSCM', branches: [[name: env.branchName]], extensions: [[$class: 'CloneOption', depth: 1, noTags: false, shallow: true]], userRemoteConfigs: [[credentialsId: 'xxxx', url: env.gitHttpURL]] ] } } } stage("Docker Builds") { parallel { stage('Build dataloader-game-ucenter') { agent { label "build01" } when { environment name: 'dataloader', value: 'true' } steps { buildAndPushDockerImage("dataloader-game-ucenter", env.data, env.BASE_WORKSPACE) } } stage('Build datawriter-game-ucenter') { agent { label "build01" } when { environment name: 'datawriter', value: 'true' } steps { buildAndPushDockerImage("datawriter-game-ucenter", env.data, env.BASE_WORKSPACE) } } stage('Build game-ucenter') { agent { label "build01" } when { environment name: 'game-ucenter', value: 'true' } steps { buildAndPushDockerImage("game-ucenter", env.data, env.BASE_WORKSPACE) } } } } stage('Development Deployment') { parallel { stage("Deploy datawriter-game-ucenter") { when { environment name: 'datawriter-game-ucenter', value: 'true' } agent { label "huaweiyun-xx" } steps { deployToKubernetes("datawriter-game-ucenter") } } stage("Deploy dataloader-game-ucenter") { when { environment name: 'dataloader', value: 'true' } agent { label "huaweiyun-xx" } steps { deployToKubernetes("dataloader-game-ucenter") } } stage("Deploy game-ucenter") { when { environment name: 'game-ucenter', value: 'true' } agent { label "huaweiyun-xx" } steps { deployToKubernetes("game-ucenter-1") deployToKubernetes("game-ucenter-2") deployToKubernetes("game-ucenter-3") deployToKubernetes("game-ucenter-4") ............................ } } } } } } // Define methods outside pipeline to avoid repetition def buildAndPushDockerImage(String imageName, String tag, String workspacePath) { sh "cd ${workspacePath} && echo 'Current directory: $(pwd)'" // 使用基礎工作空間變量 sh "cd ${workspacePath}/${imageName}&& docker build --build-arg NODE_ENV=$imageName -t $REGISTRY/$imageName:$tag ." withCredentials([usernamePassword(credentialsId: 'xxxxx', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) { sh "docker login -u $dockerUser -p $dockerPassword $REGISTRY" sh "docker push $REGISTRY/$imageName:$tag" } } def deployToKubernetes(String kubernetesComponent) { String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl" String outputFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.yaml" sh "sed -e 's/{data}/$data/g' $templateFile > $outputFile" sh "sudo kubectl apply -f $outputFile $KUBE_CONFIG" }
默認jenkins pipeline如上,我們有多個相似的游戲用戶中心服務game-ucenter-*運行在Kubernetes集群中,它們都使用非常相似的Kubernetes YAML配置文件,配置文件之間的差異主要是一些標識符的不同(例如,服務的序號)。在傳統的做法中,維護一系列幾乎一樣的模板文件(如game-ucenter-1.tpl, game-ucenter-2.tpl 等)將非常低效且易出錯。
為了精簡流程和提高效率,我們需要一個方法來通過單一模板生成多個配置文件,并由此部署多個不同的服務實例。
解決方案
使用Jenkins Pipeline中的sed命令和循環結構,我們可以從單一模板生成多個Kubernetes配置文件,并相應地部署每個服務實例。參照generate_templates.sh腳本
#!/bin/bash # Define the name of the template file. TEMPLATE_FILE="game-ucenter.tpl" # Check if the template file exists. if [ ! -f "$TEMPLATE_FILE" ]; then echo "Template file $TEMPLATE_FILE does not exist." exit 1 fi # Loop to create files from game-ucenter-2 to pvp-game-20 based on the template. for i in $(seq 1 20); do # Define the name of the new file. NEW_FILE="game-ucenter-${i}.yaml" # Copy the template to the new file. cp $TEMPLATE_FILE $NEW_FILE # Use 'sed' to replace 'game-ucenter-1' with 'game-ucenter-N' and save inline (-i option). sed -i "s/game-ucenter/game-ucenter-${i}/g" $NEW_FILE echo "Created file: $NEW_FILE" done echo "All files created successfully."
步驟 1: 定義Jenkins Pipeline
在我們的Jenkins腳本中,我們首先定義了基礎環境變量和兩個函數:buildAndPushDockerImage 和 deployToKubernetes。這些函數將用于構建Docker鏡像并部署到Kubernetes
def buildAndPushDockerImage(String imageName, String tag, String workspacePath) { sh "cd ${workspacePath} && echo 'Current directory: $(pwd)'" // 使用基礎工作空間變量 sh "cd ${workspacePath}/${imageName}&& docker build --build-arg NODE_ENV=$imageName -t $REGISTRY/$imageName:$tag ." withCredentials([usernamePassword(credentialsId: 'xxx', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) { sh "docker login -u $dockerUser -p $dockerPassword $REGISTRY" sh "docker push $REGISTRY/$imageName:$tag" } } def deployToKubernetes(String kubernetesComponent) { String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl" String outputFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.yaml" sh "sed -e 's/{data}/$data/g' $templateFile > $outputFile" sh "sudo kubectl apply -f $outputFile $KUBE_CONFIG" }
步驟 2: 修改deployToKubernetes函數
接下來,我們需要修改deployToKubernetes函數,以便它能夠接受組件名稱,并使用單一模板文件創建具體的配置文件。
def deployToKubernetes(String kubernetesComponent, int instance=1, int totalInstances=1) { // 檢查實例值 if (instance < 1) { error("實例數必須大于0") } // 根據 instance 的值來定義資源的名稱和文件名 String nameSuffix = totalInstances > 1 ? "-${instance}" : "" // 總是添加后綴,除非只有一個實例 String outputFileName = "${kubernetesComponent}${nameSuffix}.yaml" String templateFile = "${KUBE_YAML_PATH}/${kubernetesComponent}.tpl" String outputFile = "${KUBE_YAML_PATH}/${outputFileName}" String nameReplacement = "${kubernetesComponent}${nameSuffix}" sh """ cat "${templateFile}" | sed 's/{data}/${data}/g' | sed 's/name: ${kubernetesComponent}/name: ${nameReplacement}/g' | sed 's/app: ${kubernetesComponent}/app: ${nameReplacement}/g' > "${outputFile}" """ // 使用 KUBE_CONFIG 應用 Kubernetes 配置 sh "kubectl apply -f ${outputFile} ${KUBE_CONFIG}" }
對于單實例的業務,例如Deploy dataloader-game-ucenter,我們不需要傳遞實例編號。
stage("Deploy dataloader-game-ucenter") { when { environment name: 'dataloader', value: 'true' } agent { label "huaweiyun-xx" } steps { deployToKubernetes("dataloader-game-ucenter") } }
對于多實例。我這里生成 規則優點強迫癥了。如果多實例我生成的規則要求符合game-ucenter-1,game-ucenter-2,game-ucenter-3......順序,當單個實例的時候則保持原來的不加標簽:
stage("Deploy game-ucenter") { when { environment name: 'game-ucenter', value: 'true' } agent { label "k8s-node-06" } steps { script { int instances = 2 // 假設我們有2個實例 for (int i = 1; i <= instances; i++) { def componentName = "game-ucenter" deployToKubernetes("game-ucenter", i, instances) } } } }
步驟 3: 準備模板文件
我們的模板文件game-ucenter.tpl將包含通用的Kubernetes服務或部署定義,使用占位符game-ucenter-1game-ucenter-2來標識應該被替換的地方。
# game-ucenter-1.tpl (示例部分) apiVersion: apps/v1 kind: Deployment metadata: name: game-ucenter spec: replicas: 1 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: game-ucenter template: metadata: labels: app: game-ucenter spec: containers: - name: game-ucenter image: xxxx/xxx/game-ucenter:{data} envFrom: - configMapRef: name: deploy ports: - containerPort: 80 resources: requests: memory: "4096M" cpu: "2000m" limits: memory: "4096M" cpu: "2000m" livenessProbe: httpGet: scheme: HTTP path: /test.html port: 80 initialDelaySeconds: 20 periodSeconds: 120 successThreshold: 1 failureThreshold: 3 readinessProbe: httpGet: scheme: HTTP path: /test.html port: 80 initialDelaySeconds: 20 periodSeconds: 120 imagePullSecrets: - name: xxx --- apiVersion: v1 kind: Service metadata: name: game-ucenter labels: app: game-ucenter spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: game-ucenter # ...
步驟 4: 執行Jenkins Pipeline
當Jenkins Pipeline運行到"Development Deployment"階段時,它將循環創建和應用game-ucenter-1.yaml到game-ucenter-2.yaml的配置文件,從而部署2個game-ucenterdeployment服務實例。
并保證單個實例的原有命名規則:
通過這一方法,我們不再需要為每個服務實例維護一個單獨的模板文件,而是可以通過一個模板文件和Jenkins Pipeline的自動化來簡化服務部署工作。這樣做不僅提升了效率,也降低了出錯的風險。
注意:
以上代碼和命令為示例性質,可能需要根據您具體的Jenkins環境和Kubernetes集群進行相應的調整。在生產環境中部署之前,請確保進行充分的測試。
審核編輯:湯梓紅
-
模板
+關注
關注
0文章
108瀏覽量
20560 -
腳本
+關注
關注
1文章
389瀏覽量
14858 -
jenkins
+關注
關注
0文章
28瀏覽量
5154 -
kubernetes
+關注
關注
0文章
224瀏覽量
8712
原文標題:解決方案
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論