项目概述
场景概述
公有云gitlab存放dockerfile,公有云jenkins
现在要求公有gitlab更新时,自动构建dockerfile镜像
并部署到公有、私有两套k8s
现有条件
允许创建新git仓库
jenkins现有shell项目,拉取git代码后构建,使用容器ssh部署到公有环境
主要问题
不允许打vpn
可以用jenkins webhook感知gitlab更新,但jenkins无法连接私有k8s
即私有k8s无法感知gitlab更新
解决方案
创建新的B git,根据容器要求创建helm chart存放在B中
构建声明式jenkinsfile
当gitlab更新时,触发jenkins流水线,读取jenkinsfile
jenkinsfile中先拉取dockerfile与构建镜像
后拉取helm工程文件,修改变量文件的tag,再进行上传,不同的环境使用不同的vlaues文件进行管理
argo分别连接公有和私有k8s与B git,检测到helm工程变化后,自动同步资源文件到k8s
这个图是有点问题的,但懒得改了

细节说明
helm结构优化原则
1.同一应用使用不同分支,不同变量文件,同一模板文件
2.不同分支的目的是为了防止手动修改values时出现错误
3.应用太多时可使用父子chart,增强可扩展性与可维护性
同时需要基于实际上应用的需求,进行配合:
像本例子中,git中的内容只需要使用jenkinsfile的yq进行修改,再上传
不需要进行手动修改,所以将四个环境的values都放在同一个分支下
jenkins流水线git拉取问题
jenkins节点切忌使用git凭证助手
在进行拉取时,会导致git拉取报错——找不到仓库或无权限
如果不知道这是什么,那就不需要额外修改
argo连接k8s
需要通过argoCLI进行连接
或者如果你是helm部署的argo,也可以通过HelmChart资源将kubeconfig传入helm
helm工程
即一个变量文件+一个模板文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| 变量文件 global: common: imagePullSecrets: - name: harbor-token checkerbackend: enabled: true name: checker-backend replicas: 1 image: repository: xxx tag: "xxx" pullPolicy: IfNotPresent env: - name: OSSUTIL value: true service: type: NodePort port: 8080 targetPort: 80 nodePort: 32007 hostAliases: - ip: hostnames: affinity: nodeAffinityKey: "node-role.kubernetes.io/controlplane" template文件 {{- if and .Values.checkerbackend .Values.checkerbackend.enabled }} apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Values.checkerbackend.name }} spec: replicas: {{ .Values.checkerbackend.replicas }} selector: matchLabels: app: {{ .Values.checkerbackend.name }} template: metadata: labels: app: {{ .Values.checkerbackend.name }} spec: imagePullSecrets: {{- range .Values.global.common.imagePullSecrets }} - name: {{ .name }} {{- end }} containers: - name: {{ .Values.checkerbackend.name }} image: "{{ .Values.checkerbackend.image.repository }}:{{ .Values.checkerbackend.image.tag }}" imagePullPolicy: {{ .Values.checkerbackend.image.pullPolicy }} env: {{- range .Values.checkerbackend.env }} - name: {{ .name }} value: {{ .value | quote }} {{- end }} ports: - containerPort: 80 hostAliases: {{- if .Values.checkerbackend.hostAliases }} {{- toYaml .Values.checkerbackend.hostAliases | nindent 10 }} {{- end }} affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: {{ .Values.checkerbackend.affinity.nodeAffinityKey }} operator: In values: - "true" --- apiVersion: v1 kind: Service metadata: name: {{ .Values.checkerbackend.name }} spec: type: {{ .Values.checkerbackend.service.type }} ports: - port: {{ .Values.checkerbackend.service.port }} targetPort: {{ .Values.checkerbackend.service.targetPort }} nodePort: {{ .Values.checkerbackend.service.nodePort }} selector: app: {{ .Values.checkerbackend.name }} {{- end }}
|
Jenkinsfile声明式
几个注意点
1.定义超时时间
2.将时间戳写入临时文件
3.使用withCredentials时,会将账密复制到变量
4.提前安装好yq工具来修改yaml格式文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| pipeline { agent { node { label 'xxxx' } } options { timeout(time: 10, unit: 'MINUTES') } stages { stage('Define Timestamp Tag') { steps { script { def image_version = sh(script: 'date +"%Y%m%d%H%M"', returnStdout: true).trim() writeFile file: '/tmp/image_version.txt', text: image_version } } } stage('Git Clone checker-backend and build docker images') { steps { checkout([ $class: 'GitSCM', branches: [[name: '*/master']], extensions: [], submoduleCfg: [], userRemoteConfigs: [[ url: 'xxxx', credentialsId: 'xxx-alg-key' ]] ]) sh ''' image_version=$(cat /tmp/image_version.txt) echo "[jenkins log]: docker build start." docker build -f Dockerfile -t xxxx:${image_version} . echo "[jenkins log]: docker build end. pushing this image to the remote repo." docker push xxxx:${image_version} echo "[jenkins log]: docker push end." ''' } }
stage('git clone helm') { steps { checkout([ $class: 'GitSCM', branches: [[name: 'xxxx']], extensions: [ [$class: 'CleanBeforeCheckout'] ], submoduleCfg: [], userRemoteConfigs: [[ url: 'xxx.git', credentialsId: 'xxx-public-key' ]] ]) } } stage('make changes and commit') { steps { script { withCredentials([usernamePassword(credentialsId: 'xxx-public-key', passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) { sh ''' git remote set-url origin https://${GIT_USERNAME}:${GIT_PASSWORD}@xxxx.git git checkout xxxx git pull
version=$(cat /tmp/image_version.txt) formatted_version=$(printf '"%s"\n' "$version") echo ".checkerbackend.image.tag = $formatted_version" > /tmp/yq_script.yaml yq eval -i "$(cat /tmp/yq_script.yaml)" helm-checker-backend/values.yaml rm /tmp/yq_script.yaml
git add . git commit -m "checker-backend update $(cat /tmp/image_version.txt)" || true git push origin xxxx ''' } } } } } }
|