10.5 Jenkins集成Kubernetes
10.5.1 gitlab上准备部署的yml文件
在gitlab上创建一个pipeline.yml文件,供Jenkins拉取并通知目标服务器执行
apiVersion: apps/v1 kind: Deployment metadata: namespace: test name: pipeline labels: app: pipeline spec: replicas: 2 selector: matchLabels: app: pipeline template: metadata: labels: app: pipeline spec: containers: - name: pipeline image: 192.168.2.211:80/repo/pipeline:v3.0.0 # 在harbor仓库中复制一个镜像取得 command: ["/bin/bash", "-ce", "tail -f /dev/null"] # 保持容器持续运行,而不是一致重启 imagePullPolicy: Always ports: - containerPort: 8080 --- apiVersion: v1 kind: Service metadata: namespace: test labels: app: pipeline name: pipeline spec: selector: app: pipeline ports: - port: 8081 targetPort: 8080 type: NodePort --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: namespace: test name: pipeline spec: ingressClassName: ingress rules: - host: ingress.pipeline.com http: paths: - path: / pathType: Prefix backend: service: name: pipeline port: number: 8081
10.5.2 Harbor私服配置
在尝试用kubernetes的yml文件启动pipeline服务时,会出现Kubernetes无法拉取镜像的问题,这里需要在kubernetes所在的Linux中配置Harbor服务信息,并且保证Kubernetes可以拉取Harbor上的镜像
- 设置Master和Worker的私服地址信息
- 在Kuboard上设置私服密文信息
按照复制指令的位置测试认证,效果如下 :
10.5.3 测试使用效果
执行kubectl命令,基于yml启动服务,并且基于部署后服务的提示信息以及Ingress的设置,直接访问
修改Windows的hosts表后访问,注意"/test’’
10.5.3 Jenkins远程调用
- 将pipeline.yml配置到Gitlab中
- 配置Jenkins的目标服务器,可以将yml文件传输到K8s的Master上
- 修改Jenkinsfile,重新设置流水线任务脚本,并测试效果
查看k8smaster上是否接收到文件:
- 设置Jenkins无密码登录k8s-master
将Jenkins中公钥信息复制到k8s-master的~/.ssh/authorized_keys中,保证远程连接无密码
- 设置执行kubectl的脚本到Jenkinsfile,要写pipeline.yml的绝对路径
红框里的路径一定要写绝对路径,否则会默认去找root所在目录下的pipeiline.yml文件。
- 执行查看效果
可以查看到yml文件是由变化的, 这样k8s就会重新加载
- 查看效果
Ps:这种方式更适应与CD操作,将项目将基于某个版本部署到指定的目标服务器
// 所有脚本命令包含在pipeline{}中 pipeline { // 指定任务在哪个节点执行(Jenkins支持分布式) agent any // 声明全局环境变量方便后面使用,key = 'value'形式,指定变量名=变量值信息 environment{ harborUser = 'admin' harborPassword = 'Harbor12345' harborAddress = '192.168.2.211:80' harborRepo = 'repo' } // 存放所有任务的合集 stages { // 单个任务 stage('任务1:拉取git仓库代码') { // 实现任务的具体流程 steps { checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.2.210/root/test.git']]]) } } // 单个任务 stage('任务2:通过maven构建项目') { // 实现任务的具体流程 steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTest' } } stage('任务3:通过sonarqube做代码质量检测') { steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=7e47cd48d08789e76ba106dd772f9bfaa15d46ff' } } stage('任务4:通过docker制作自定义镜像') { steps { sh '''mv ./target/*.jar ./ docker build -t ${JOB_NAME}:${tag} .''' } } stage('任务5:将自定义镜像推送到harbor') { steps { sh '''docker login -u ${harborUser} -p ${harborPassword} ${harborAddress} docker tag ${JOB_NAME}:${tag} ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag} docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:${tag}''' } } stage('远程执行k8s-master的kubectl命令') { steps { sh 'ssh root@192.168.2.212 kubectl apply -f /usr/local/k8s/pipeline.yml' } } } post { success { dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } failure{ dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:${tag}\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } } }
10.6 基于GitLab的WebHooks
这里要实现自动化的一个CI操作,也就是开发人员Push代码到Git仓库后,Jenkins会自动的构建项目,将最新的提交点代码构建并进行打包部署,这里区别去上述的CD操作,CD操作需要基于某个版本进行部署,而这里每次都是将最新的提交点集成到主干上并测试。
10.6.1 WebHooks通知
- 开启Jenkins的自动构建
构建触发器:
下载插件GitLab
配置构建触发器
2、设置Gitlab的Webhooks
设置network可以访问本地
输入URL,测试报错403
3、关闭Jenkins的Gitlab认证
关闭Jenkins的Gitlab认证,需要插件[GitLab Authentication]
4、再次测试Gitlab
10.6.2 修改配置
修改Jenkinsfile实现基于最新提交点实现持续集成效果,将之前引用${tag}的全部替换成latest
// 所有脚本命令包含在pipeline{}中 pipeline { // 指定任务在哪个节点执行(Jenkins支持分布式) agent any // 声明全局环境变量方便后面使用,key = 'value'形式,指定变量名=变量值信息 environment{ harborUser = 'admin' harborPassword = 'Harbor12345' harborAddress = '192.168.2.211:80' harborRepo = 'repo' } // 存放所有任务的合集 stages { // 单个任务 stage('任务1:拉取git仓库代码') { // 实现任务的具体流程 steps { checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.2.210/root/test.git']]]) } } // 单个任务 stage('任务2:通过maven构建项目') { // 实现任务的具体流程 steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTest' } } stage('任务3:通过sonarqube做代码质量检测') { steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=7e47cd48d08789e76ba106dd772f9bfaa15d46ff' } } stage('任务4:通过docker制作自定义镜像') { steps { sh '''mv ./target/*.jar ./ docker build -t ${JOB_NAME}:latest .''' } } stage('任务5:将自定义镜像推送到harbor') { steps { sh '''docker login -u ${harborUser} -p ${harborPassword} ${harborAddress} docker tag ${JOB_NAME}:latest ${harborAddress}/${harborRepo}/${JOB_NAME}:latest docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:latest''' } } stage('任务6:将pipeline.yml文件通过publish over ssh传到k8smaster上') { steps { sshPublisher(publishers: [sshPublisherDesc(configName: 'k8s', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'pipeline.yml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)]) } } stage('远程执行k8s-master的kubectl命令') { steps { sh 'ssh root@192.168.2.212 kubectl apply -f /usr/local/k8s/pipeline.yml' } } } post { success { dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } failure{ dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } } }
修改pipeline.yml,更改镜像版本
apiVersion: apps/v1 kind: Deployment metadata: namespace: test name: pipeline labels: app: pipeline spec: replicas: 2 selector: matchLabels: app: pipeline template: metadata: labels: app: pipeline spec: containers: - name: pipeline image: 192.168.2.211:80/repo/pipeline:latest # 在harbor仓库中复制一个镜像取得 command: ["/bin/bash", "-ce", "tail -f /dev/null"] # 保持容器持续运行,而不是一致重启 imagePullPolicy: Always ports: - containerPort: 8080 # 省略其他内容…………
10.6.3 自动滚动更新
因为pipeline.yml文件没有改变时,kubectl每次不会重新加载apply,这样会导致Pod中的容器不会动态更新,这里需要使用kubectl的rollout restart命令滚动更新。代码一变化就会自动构建。
设置Jenkinsfle
// 所有脚本命令包含在pipeline{}中 pipeline { // 指定任务在哪个节点执行(Jenkins支持分布式) agent any // 声明全局环境变量方便后面使用,key = 'value'形式,指定变量名=变量值信息 environment{ harborUser = 'admin' harborPassword = 'Harbor12345' harborAddress = '192.168.2.211:80' harborRepo = 'repo' } // 存放所有任务的合集 stages { // 单个任务 stage('任务1:拉取git仓库代码') { // 实现任务的具体流程 steps { checkout([$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'http://192.168.2.210/root/test.git']]]) } } // 单个任务 stage('任务2:通过maven构建项目') { // 实现任务的具体流程 steps { sh '/var/jenkins_home/maven/bin/mvn clean package -DskipTest' } } stage('任务3:通过sonarqube做代码质量检测') { steps { sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=./target/ -Dsonar.login=7e47cd48d08789e76ba106dd772f9bfaa15d46ff' } } stage('任务4:通过docker制作自定义镜像') { steps { sh '''mv ./target/*.jar ./ docker build -t ${JOB_NAME}:latest .''' } } stage('任务5:将自定义镜像推送到harbor') { steps { sh '''docker login -u ${harborUser} -p ${harborPassword} ${harborAddress} docker tag ${JOB_NAME}:latest ${harborAddress}/${harborRepo}/${JOB_NAME}:latest docker push ${harborAddress}/${harborRepo}/${JOB_NAME}:latest''' } } stage('任务6:将pipeline.yml文件通过publish over ssh传到k8smaster上') { steps { sshPublisher(publishers: [sshPublisherDesc(configName: 'k8s', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'pipeline.yml')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)]) } } stage('远程执行k8s-master的kubectl命令') { steps { sh '''ssh root@192.168.2.212 kubectl apply -f /usr/local/k8s/pipeline.yml ssh root@192.168.2.212 kubectl rollout restart deployment pipeline -n test''' } } } post { success { dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 成功构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } failure{ dingtalk( robot: 'Jenkins-DingDing', type: 'MARKDOWN', title: "success: ${JOB_NAME}", text: ["- 失败构建:${JOB_NAME}项目!\n- 版本:latest\n- 持续时间:${currentBuild.durationString}\n- 任务:#${JOB_NAME}"] ) } } }