gitlab和jenkins结合,基于k8s平台实现ci/cd功能简单测试。
1. Jenkins Pipeline节点
系统管理 —> 节点管理 —> 新建节点
关键配置项:
- Executor数量:可以简单设置为小于等于节点上CPU核心数的整数值;
- 远程工作目录:在agent节点上授权Jenkins使用的工作目录,建议使用绝对路径;
- 标签:节点特性标识;
- 用法:控制Jenkins如何在该agent上安排构建任务;
- 启动方式:master识别该agent主机并与其建立双向连接的方式,选定后,需要给定该方式下的具体配置;
- 可用性:master与agent间的连接保持机制;

添加连接凭据:
在agent主机上设置工作目录,授权给jenkins用户,并给jenkins用户设定登录口令:
# usermod -s /bin/bash jenkins# mkdir -p /appdata/jenkins# chown -R jenkins:jenkins /appdata/jenkins# passwd jenkins
如果是通过公钥来认证连接,添加公钥后,将私钥文件导入到jenkins凭据中:
# su - jenkins# mkdir .ssh# echo "PUB_CONTENT" > .ssh/authorized_keys# chmod 700 .ssh# chmod 640 .ssh/authorized_keys

pipeline中使用agent指令显式指定执行位置:pipeline {agent {label "node1"}stages {stage('ShowAgent'){steps{echo "The node:${env.NODE_NAME}."echo "The node label: ${env.NODE_LABELS}."}}stage('Checkout'){steps{echo 'Fetch codes from SCM'}}stage('Build'){steps{echo 'Building..'}}}post {always{mail to: 'test@126.com',subject: "Status of pipeline ${currentBuild.fullDisplayName}",body: "${env.BUILD_URL} has result ${currentBuild.result}"}}}

agent可接受多种形式的参数:
- any: 任何可用节点;
- node: 用于pipeline顶端时表示不定义默认的agent,这就需要为每个stage单独指定;
- label { label “
- node { label “
- docker: 在指定的容器中允许pipeline或stage代码,该容器动态创建并运行于预配置的可运行容器的node上,或能够匹配到指定label的node上,可用参数有:image、label、args、registryUrl和registryCredentialsId;
- dockerfile:功能上类似于上面docker参数,但容器镜像通过指定的docker进行构建;该参数要求Jenkinsfile必须从Multibrach Pipeline或Pipeline from SCM中加载,可用参数:filename、dir、label、additionalBuildArgs、args、registryUrl和registryCredentialsId;
- kubernetes: 于Kubernetes集群上指定的Pod中运行stage或pipeline代码,该参数同样要求Jenkinsfile必须从Multibrach Pipeline或Pipeline from SCM中加载;需要在kubernetes参数重指定Pod模版;
参考:https://www.jenkins.io/doc/book/pipeline/syntax/
2.Jenkins Pipeline与docker集成
在计划运行Docker容器的各Jenkins节点上设置:
- 安装并设定好docker环境;
- Jenkins安装Docker插件,pipeline插件自2.5版本以后就内置了docker插件;
将jenkins用户加入到docker组,# usermod -aG docker jenkins
重启jenkins服务
重启jenkins服务
pipeline {agent nonestages{stage('Back-end'){agent{docker {image 'openjdk:18-slim'}}steps{sh 'java --version'}}stage('Front-end'){agent{docker {image 'node:alpine'}}steps{sh 'node --version'}}}}
以docker {}为agent时,除了image外,还有其他参数:
label:默认,docker容器可运行于任何配置了docker环境的主机上,而label选项可基于标签过滤出一组特定的主机来运行docker agent;
- args:在创建容器的命令上,传递的自定义参数,例如,使用”-v Contain_Path:Host_Path”来使用存储卷;
- registryUrl: 特定镜像registry服务的URL;
- registryCredentialsId: 存储有认证到镜像registry上的Credential的ID;
指定凭证认证到死有registry中来获取镜像:
agent {image 'dockerhub.test.com/test_zky/spring-boot-helloworld'label 'docker_host'registryUrl 'https://dockerhub.test.com'registryCredentialsId 'dockerhub-user'}
在jenkins上添加镜像库的凭证:
- 添加默认的Registry指向,系统管理 —> 系统配置:

各配置参数简要说明:
- Docker Label: pipeline中的agent没有指定label选项时,将以此处指定的label为默认值;
- Docker registry URL: 使用的Docker Registry服务的地址;
- Registry Credentials: 认证到目标Registry服务的凭证;
- 配置Jenkins全局凭证,添加registry的账号密码:
3.Jenkins Pipeline与kubernetes集成
Jenkins支持以Pod形式运行Slave节点,实现规模可伸缩的Jenkins Cluster
- 相应的slave的功能由Pod模版通过镜像、存储卷等配置进行定义
- 需要在Jenkins上安装kubernetes插件
3.1 配置kubernetes集群
系统管理 —> 节点管理 —> Configure Clouds
注意: Kubernetes地址、jenkins地址和jenkins通道相关的svc信息都需要在kubernetes上通过相关的svc了解;
3.2 配置Pod模版

该模式默认会使用jenkins\inbound-agent镜像做为slave Pod的基础容器;添加的容器将作为第二、第三容器使用;
3.3 简单测试Pod pipeline
pipeline {agent {kubernetes {inheritFrom 'jenkins-slave'}}stages{stage('hello'){steps{sh 'java -version'}}}}
3.4 在Pod中运行maven构建工具
新增一个pod模版,它可以使用maven的镜像,联合默认的jenkins-slave镜像,运行一个多容器Pod

注意:需要提前创建好PVC
pipeline {agent {kubernetes {inheritFrom 'maven-3.8'}}stages {stage('Build') {steps {container('maven') {sh 'mvn -version'}}}}}
3.5 在Pod中提供docker环境
在容器中构建docker镜像,需要以docker in docker的方式进行

pipeline {agent {kubernetes {inheritFrom 'maven-and-docker'}}stages {stage('maven version') {steps {container('maven') {sh 'mvn -version'}}}stage('docker info') {steps {container('docker') {sh 'docker info'}}}}}
4.Jenkins Pipeline与Gitlab集成
4.1 Gitlab通知触发自动构建
spring-boot-helloworld示例:
拉取地址:https://github.com/iKubernetes/spring-boot-helloWorld.git (马哥教育)
Gitlab Webhook指pipeline关联的Gitlab Repository上的代码出现变更时,由Gitlab将相关事件通知给Jenkins,从而触发Jenkins执行构建操作;
- 避免了pollSCM的频繁轮询依然存在滞后可能性的问题;
- 依赖于Gitlab插件和Git插件;
配置要求:
- 前提:Gitlab和Jenkins同在本地网络时,需要以管理员权限设置“外发请求”,启用“允许Webhook和服务队本地网络的请求”;
- 授予Jenkins访问Gitlab上仓库中特定用户的代码权限;
- Jenkins基于SSH协议获取代码仓库中的内容,因而需要事先配置Jenkins能基于SSH密钥接入GItlab;
- Gitlab API访问授权
- 配置Gitlab API访问认证(Access Token)及操作权限;
- 配置Jenkins启用/project端点认证,配置它能通过配置的Access Token接入Gitlab API;
- Jenkins pipeline项目的通知授权
- 创建pipeline任务,选择使用的“Gitlab Connection”,并选定使用”Build when a change is pushed to Gitlab.”触发器;
- 而且为构建触发器生成Secret token;
- 配置Gitlab Repository能通过Webhook,基于该Secret Token触发构建;
具体配置相关文档:https://docs.gitlab.com/ce/integration/jenkins.html
- 以Gitlab管理员的身份,设置系统在外发请求中,允许Webhook和服务对本地网络的请求;

- 为Gitlab用户添加SSH公钥,复制公钥文件的内容,贴在Gitlab上的用户账号配置属性中:

- 在Jenkins上通过凭证添加SSH私钥以认证到Gitlab

- 在Gitlab上创建Access Token,User Account —> Setting —> Access Tokens

- 将Gitlab Token添加为jenkins Credential

- 在Jenkins上授权启用/project端点以创建Gitlab连接,系统管理 —> 系统配置:

- 配置Jenkins项目可经由Gitlab上的事件触发
- 在Jenkins的pipeline和freestyle类型的项目上,选择使用的Gitlab connection;
- 选中”Build when a change is pushed to Gitlab”,并按需勾选允许的触发事件;
还应该配置如何通知给Gitlab;
- Freestyle项目可以选择通过Post-build Actions指定;
Pipeline项目只能通过pipeline代码指定;
pipeline {agent anystages {stage('gitlab') {steps {echo 'Notify Gitlab'updateGitlabCommitStatus name: 'build',state:'pending'updateGitlabCommitStatus name: 'build',state:'success'}}}}

点击上图的“高级”按钮,在Jenkins项目上生成Secret Token,该Token将被Gitlab用作触发时的认证信息;

- 在Gitlab上对应代码仓库的配置菜单上,Setting —> Webhooks
- 创建一个Webhook,指向前面配置的Jenkins项目及其相应的Secret Token
- Webhook定义完成后,可手动测试触发机制;选择支持的某类触发事件中的一种,即可触发一次Pipeline的构建操作;
- 整个出发及构建链路连通后,即可于Jenkins上的相关项目的详情中看到,被Gitlab出发的构建都会标记为”Started by Gitlab by xxx”


测试自动触发,向Gitlab上的代码仓库推送代码变更测试即可
pipeline {environment {appName = "dockerhub.test.com/test_zky/spring-boot-helloworld"appVersion = "0.9.4"}agent {kubernetes {inheritFrom "maven-and-docker"}}stages {stage('Source'){steps {git branch: 'develop', credentialsId: 'gitlab-ssh-private-key', url:'ssh://git@gitlab.gitlab.svc.cluster.local/zky/spring-boot-helloworld.git'}}stage('Build') {steps {container('maven') {sh 'mvn clean test package'}}}stage('Building app image') {steps {container('docker') {script {dockerimage = docker.build appName + ':' + appVersion}}}}}}
4.2 自动推送Docker镜像入库
将拥有镜像仓库“写”权限的认证信息保存位Jenkins的凭据,以确保能够在pipeline中推送镜像至仓库中

pipeline {environment {appName = "dockerhub.test.com/test_zky/spring-boot-helloworld"appVersion = "0.9.4"registry = "https://dockerhub.test.com"registryCredential = "dockerhub-user"dockerimage = ""}agent {kubernetes {inheritFrom "maven-and-docker"}}stages {stage('Build') {steps {container('maven') {sh 'mvn clean test package'}}}stage('Building app image') {steps {container('docker') {script {dockerimage = docker.build appName + ':' + appVersion}}}}stage('Push app image') {steps {container('docker') {script {docker.withRegistry(registry,registryCredential) {dockerimage.push()}}}}}}}
4.3 Jenkinsfile入库
将前面示例中的pipeline代码保存于仓库根目录中的Jenkinsfile文件中,即可由Jenkins自行检出并加载;
- 轻量级检出,可让Jenkins仅检出Jenkinsfile文件,而非整个仓库;
5.Jenkins CD流水线
- 以Jenkins为CD工具:
- 原则上:代码仓库与配置仓库分离,CI Server与CD Server分离;
- 折衷方案:代码仓库与配置仓库分离,但仍使用同一个Jenkins实例:
- 代码仓库:spring-boot-helloworld
- 配置仓库:spring-boot-helloworld-deployment
- 使用kubectl直接调用清单进行部署,需要事先配置可运行kubectl命令的Pod模版

- 安装 kubernetes CLI 插件
- 将具有部署目标资源权限的账户及认证信息添加微Jenkins上的认证凭据
- 将”kubectl config view —raw”的结果复制后,保存于本地桌面上的文件;
- 修改其Cluster的地址为集群内部的可用地址https://kubernetes.default.svc.cluster.local:443;
- 在Jenkins上添加类型为”Secret File”类型的凭据,并加在前面生成的文件;

使用如下Pipeline代码
- 从指定的仓库获取代码
而后借助于kubectl基于相应的kubeconfig项目标集群执行应用部署或更新
pipeline {agent {kubernetes {label 'kubectl'}}stages {stage('Source'){steps {git branch: 'master', credentialsId: 'gitlab-ssh-private-key', url:'ssh://git@gitlab.gitlab.svc.cluster.local/zky/spring-boot-helloworld-deployment.git'}}stage('Deploy'){steps{container('kubectl'){withKubeConfig([credentialsId: 'k8s-cluster-admin-kubeconfig']){sh 'kubectl apply -f deploy/'}}}}}}
参考:马哥教育 gitops课程
