目录
3、gitlab更新,jenkins自动扫描,自动开始构建
4、docker构建镜像完成,slave可以看到最新的images
5、docker推送镜像完成,harbor新增刚才推送的镜像
Jenkins Pipeline 提供了一套可扩展的工具,用于将“简单到复杂”的交付流程实现为“持续交付即代码”。Jenkins Pipeline 的定义通常被写入到一个文本文件(称为 Jenkinsfile
)中,该文件可以被放入项目的源代码控制库中。
本文通过单分支流水线入门,然后进行多分支流水线任务实战,最终实现流程:git代码提交----gitlab更新代码库----jenkins自动扫描到有更新----jenkins自动构建任务----docker构建镜像库----推送至harbor----k8s获取新的image----apply容器
一、 jenkins单分支流水线构建
1、把现在的库克隆到本地
[root@k8s-node2 ~]# git clone http://gitlab.rui.com/root/myblog.git
正克隆到 'myblog'...
Username for 'http://gitlab.rui.com': root
Password for 'http://root@gitlab.rui.com':
remote: Enumerating objects: 175, done.
remote: Counting objects: 100% (175/175), done.
remote: Compressing objects: 100% (124/124), done.
remote: Total 175 (delta 45), reused 175 (delta 45), pack-reused 0
接收对象中: 100% (175/175), 549.86 KiB | 0 bytes/s, done.
处理 delta 中: 100% (45/45), done.
2、添加单分支流水线
3、添加gitlab的webhook
4、配置流水线的构建任务模式
5、Jenkinsfile配置SCM
jenkins有两个方式定义 Pipeline
1、直接写在 web ui 项目配置里
2、提交到 SCM,在项目配置中指定其位置
scm可以自动获取gitlab的分支信息,这样我们可以把Jenkinsfile文件直接放在git分支里面,更新时不会覆盖现有的配置,实现版本控制
[root@k8s-node2 myblog]# pwd
/root/myblog
[root@k8s-node2 myblog]# cat Jenkinsfile
pipeline {
agent { label '23'}
stages {
stage('printenv') {
steps {
echo 'Hello World'
sh 'printenv'
}
}
stage('check') {
steps {
checkout scm
}
}
#stage('check') {
# steps {
# checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-user', url: 'http://gitlab.luffy.com/root/myblog.git']]])
# }
# }
stage('build-image') {
steps {
retry(2) { sh 'docker build . -t myblog:latest'}
}
}
stage('send-msg') {
steps {
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=d7d8a3e17742d2153de5223ec6b9ba7ea24fe6616495c9318e11f82751cb0d09' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
"text": {
"content": "jenkins流水线测试:myblog镜像构建完成"
}
}'
"""
}
}
}
}
6、后台进行push操作
1、添加默认的用户和邮箱
[root@k8s-node2 myblog]# vim .git/config
。。。
[user]
email=rui@qq.com
name=rui
2、查看本地哪些文件有更新需要提交
[root@k8s-node2 myblog]# git status
# 位于分支 master
# 未跟踪的文件:
# (使用 "git add <file>..." 以包含要提交的内容)
#
# Jenkinsfile
提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
3、添加文件到本地git缓存区
[root@k8s-node2 myblog]# git add Jenkinsfile
4、推送修改到本地git库中
[root@k8s-node2 myblog]# git commit -m "添加jenkinsfile文件用于测试自动构建"
[master 3c5766c] 添加jenkinsfile文件用于测试自动构建
1 file changed, 40 insertions(+)
create mode 100644 Jenkinsfile
5、提交代码到远程gitlab仓库
[root@k8s-node2 myblog]# git push -u origin master
Username for 'http://gitlab.rui.com': root
Password for 'http://root@gitlab.rui.com':
Counting objects: 4, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 899 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To http://gitlab.rui.com/root/myblog.git
f40692e..3c5766c master -> master
分支 master 设置为跟踪来自 origin 的远程分支 master。
7、代码提交后,jenkins自动开始构建任务
二、Jenkins多分支流水线构建
实际生产不可能直接提交代码至master分支,需要同时为开发和产品环境交付不同的结果。项目的交付会根据Jenkins构建不同的Git分支而有所区别。也就是说,所构建的分支决定你的流水线会执行哪一个交付阶段。
另外,当前流水线任务还存在几个痛点,我先提出每个痛点以及对应的解决方式,最终给出一份完整的Jenkinsfile文件并注解。
1、需要部署harbor
部署个harbor用于镜像的push和k8s部署
Linux搭建自己的Docker镜像仓库-阿里云开发者社区介绍如何在自己的服务器搭建docker镜像仓库https://developer.aliyun.com/article/719971
2、钉钉告警token明文显示
目前流水线任务配置中,最终结果钉钉通知的token还是明文,jenkins类似k8s的secret也有两种加密认证的方式,token认证和用户密码加密认证,jenkins界面设置全局凭证后,jenkinsfile可以直接调用变量。
# JenkinsFile文件添加全局变量
environment {
DINGTALK_CREDS = credentials('dingTalk')
}
# 调用
这实际设置了下面的三个环境变量:
- `DINGTALK_CREDS_CREDS` - 包含一个以冒号分隔的用户名和密码,格式为 `username:password`。
- `DINGTALK_CREDS_CREDS_USR` - 附加的一个仅包含用户名部分的变量。
- `DINGTALK_CREDS_PSW` - 附加的一个仅包含密码部分的变量。
应用举例:
curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}'
3、目前只有master分支
为了测试多分支构建,创建一个develop新分支
$ git checkout develop
分支 develop 设置为跟踪来自 origin 的远程分支 develop。
切换到一个新分支 'develop'
$ git status
# 位于分支 develop
无文件要提交,干净的工作区
3、创建多分支流水线任务
多分支流水线配置扫描的gitlab地址、频率以及发现分支的规则,无需手动指定git的分支信息,jenkins会自动每分钟扫描一次,或者符合规则的分支的变动。
4、通知gitlab构建状态
Jenkins端做了构建,可以通过gitlab通过的api将构建状态通知过去,作为开发人员发起Merge Request或者合并Merge Request的依据之一。
注意一定要指定gitLabConnection('gitlab'),不然没法认证到Gitlab
jenkinsfile文件配置:
gitLabConnection('gitlab')
updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
我们可以访问gitlab,然后找到commit记录,查看同步状态
提交merge request,也可以查看到相关的任务状态,可以作为项目owner合并代码的依据之一
5、k8s自动获取最新的镜像地址
# 把容器部署的yaml放在项目同级deploy目录
[root@k8s-node2 myblog]# tree deploy/
deploy/
├── configmap.yaml
├── deploy-myblog.yaml
├── ingress.yaml
├── secret.yaml
└── svc-myblog.yaml
# 修改deploy-myblog.yaml镜像地址为变量
image: {{IMAGE_URL}}
# Jenkinsfile文件每次构建后修改镜像地址
stage('K8s集群部署容器:') {
steps {
sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' deploy/*"
script{
env.BUILD_TASKS += env.STAGE_NAME + "OK!" + env.TAB_STR
}
}
}
6、Jenkinsfile文件配置详解
综合以上提出的问题,最终给出一份实际可行的jenkinsfile文件
pipeline {
agent { label '23'} # 选择任务构建的slave节点标签
options {
buildDiscarder(logRotator(numToKeepStr: '10')) # 清理策略,保存最近10次构建
disableConcurrentBuilds() # jenkins禁止并行构建
timeout(time: 20, unit: 'MINUTES') # 超时时间
gitLabConnection('gitlab') # 构建结果通知gitlab
}
environment {
IMAGE_REPO = "192.168.0.121:5000/myblog/myblog" # 镜像仓库环境变量
DINGTALK_CREDS = credentials('dingTalk') # 钉钉全局凭证用于token加密调用
TAB_STR = "\n \n "
} # 没啥意思,用于展示美观
stages {
stage('配置环境变量:') {
steps {
script{
sh "git log --oneline -n 1 > gitlog.file" # 自定义环境变量用于钉钉告警展示
env.GIT_LOG = readFile("gitlog.file").trim()
}
sh 'printenv'
}
}
stage('检测GIT分支:') {
steps {
checkout scm # scm自动获取gitlab的分支信息
updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success') # 通知构建完成状态给gitlab
script{
env.BUILD_TASKS = env.STAGE_NAME + "OK!" + env.TAB_STR
}
}
}
stage('Docker构建镜像:') {
steps {
retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'} # 失败再次执行,两次失败才报错停止,防止网络等原因影响
updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
script{
env.BUILD_TASKS += env.STAGE_NAME + "OK!" + env.TAB_STR # env.BUILD_TASKS获取每次的stage('Docker构建镜像:')的值
}
}
}
stage('Docker推送镜像:') {
steps {
retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
script{
env.BUILD_TASKS += env.STAGE_NAME + "OK!" + env.TAB_STR
}
}
}
stage('K8s集群部署容器:') {
steps {
sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' deploy/*" # GIT_COMMIT数值当作镜像tag,并且替换至dep.yaml中
timeout(time: 1, unit: 'MINUTES') {
sh "kubectl apply -f deploy/"
}
updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
script{
env.BUILD_TASKS += env.STAGE_NAME + "OK!" + env.TAB_STR
}
}
}
}
post { # 构建结果返回几个状态值,根据不同的状态值配置输出
success {
echo 'Congratulations!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \ # 此处钉钉token已加密,用变量代替
-H 'Content-Type: application/json' \
-d '{
"msgtype": "markdown",
"markdown": {
"title":"myblog",
"text": "^v^ 构建成功 ^v^ \n**项目名称**:rui \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"
}
}'
"""
}
failure {
echo 'Oh no!'
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
-H 'Content-Type: application/json' \
-d '{
"msgtype": "markdown",
"markdown": {
"title":"myblog",
"text": "-_-# 构建失败 -_-# \n**项目名称**:rui \n**Git log**: ${GIT_LOG} \n**构建分支**: ${BRANCH_NAME} \n**构建地址**:${RUN_DISPLAY_URL} \n**构建任务**:${BUILD_TASKS}"
}
}'
"""
}
always {
echo 'I will always say Hello again!'
}
}
}
三、开始把流程走通
1、修改代码,提交至gitlab
[root@k8s-node2 myblog]# git status
[root@k8s-node2 myblog]# git add Jenkinsfile
[root@k8s-node2 myblog]# git commit -m 'jenkins多分支自动构建镜像自动部署通关测试'
[root@k8s-node2 myblog]# git push origin develop