CI/CD配置手册
snow chuai汇总、整理、撰写---2024/03/21
1. 拓扑
+-----------------------+ +-----------------------+ +----------------------+
| [ Gitlab Node ] | | [ Jenkins Node ] | | [ Harbor Node ] |
| [gitlab.1000y.cloud] | | [jenkins.1000y.cloud] | |[k8srepos.1000y.cloud]|
+-----------+-----------+ +-----------+-----------+ +------+---------------+
eth0|192.168.1.26 eth0|192.168.1.27 eth0|192.168.1.249
|---------------------------+----------------------|
|
eth0|192.168.1.11~16
+-----------+-----------+
| [kubernetes cluster] |
+-----------------------+
前提:
1. kubernetes集群部署完成
2. Harbor节点部署完成且成功与kubernetes集群成功对接
|
2. 安装Docker-CE
1) 安装Docker-CE
[root@jenkins ~]# yum install yum-utils device-mapper-persistent-data lvm2 -y
[root@jenkins ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@jenkins ~]# sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
[root@jenkins ~]# yum makecache fast
[root@jenkins ~]# yum install docker-ce -y
2) 添加Harbor证书
[root@jenkins ~]# scp k8srepos.1000y.cloud:/etc/pki/CA/cacert.pem .
[root@jenkins ~]# cat cacert.pem >> /etc/pki/tls/certs/ca-bundle.crt
3) 配置加速器
[root@jenkins ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://3laho3y3.mirror.aliyuncs.com"],
"insecure-registries": ["https://srv7.1000y.cloud"]
}
4) 启动Docker
[root@jenkins ~]# systemctl restart docker
5) 登陆Harbor
[root@jenkins ~]# docker login k8srepos.1000y.cloud
Username: admin # Harbor节点的账户
Password: # Harbor节点账户的密码
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
6) 测试
[root@jenkins ~]# docker pull k8srepos.1000y.cloud/k8s/nginx
Using default tag: latest
latest: Pulling from k8s/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
Status: Downloaded newer image for k8srepos.1000y.cloud/k8s/nginx:latest
k8srepos.1000y.cloud/k8s/nginx:latest
[root@jenkins ~]# docker rmi k8srepos.1000y.cloud/k8s/nginx:latest
Untagged: k8srepos.1000y.cloud/k8s/nginx:latest
Untagged: k8srepos.1000y.cloud/k8s/nginx@sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
Deleted: sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
Deleted: sha256:b625d8e29573fa369e799ca7c5df8b7a902126d2b7cbeb390af59e4b9e1210c5
Deleted: sha256:7850d382fb05e393e211067c5ca0aada2111fcbe550a90fed04d1c634bd31a14
Deleted: sha256:02b80ac2055edd757a996c3d554e6a8906fd3521e14d1227440afd5163a5f1c4
Deleted: sha256:b92aa5824592ecb46e6d169f8e694a99150ccef01a2aabea7b9c02356cdabe7c
Deleted: sha256:780238f18c540007376dd5e904f583896a69fe620876cabc06977a3af4ba4fb5
Deleted: sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f
|
3. 部署Jenkins
1) 安装Jenkins
[root@jenkins ~]# docker run -d -u root --name=jenkins --restart=always -p 8080:8080 -p 50000:50000 \
-v /data/jenkins:/var/jenkins_home k8srepos.1000y.cloud/k8s/jenkins:2.450-jdk11
2) 修改Jenkins插件为国内源
[root@jenkins ~]# vim /data/jenkins/hudson.model.UpdateCenter.xml
<?xml version='1.1' encoding='UTF-8'?>
<sites>
<site>
<id>default</id>
将https:......改为如下内容
<url>https://mirror.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json</url>
</site>
</sites>
3) 如已有准备好的插件,可直接进行复制
[root@jenkins ~]# curl -O http://registry.1000y.cloud/repos/k8s-cicd/jenkins-plugins.tar.gz
[root@jenkins ~]# tar xfz jenkins-plugins.tar.gz
[root@jenkins ~]# cp -Rp plugins/* /data/jenkins/plugins/
[root@jenkins ~]# docker restart jenkins
4) 访问及初始化配置Jenkins
[浏览器]===>http://jenkins.1000y.cloud:8080
[root@jenkins ~]# cat /data/jenkins/secrets/initialAdminPassword
e3b883c88a874a8784cd658d076e3be9
5) 安装Jenkins必要的CI/CD所需的插件
# 如果没有进行 docker restart jenkins, 但已经复制保存的插件到jenkins。也可通过浏览器输入: http://jenkins.1000y.cloud:8080/restart 来重启jenkins
通过搜索,勾选所需要的插件:
插件清单:
Git
Git Parameter
Git Pipeline for Blue Ocean
GitLab
Credentials
Credentials Binding
Blue Ocean
Blue Ocean Pipeline Editor
Blue Ocean Core JS
Pipeline SCM API for Blue Ocean
Dashboard for Blue Ocean
Build With Parameters
Dynamic Extended Choice Parameter
Extended Choice Parameter
List Git Branches Parameter
Pipeline
Pipeline: Declarative
Kubernetes
Kubernetes CLI
Kubernetes Credentials
Image Tag Parameter
|
4. 部署GitLab
4.1 配置MAIL Server
[root@gitlab ~]# vim /etc/postfix/main.cf
......
......
......
......
......
......
开启113行,注释116行,改成如下:
inet_interfaces = all
#inet_interfaces = $myhostname
#inet_interfaces = $myhostname, localhost
#inet_interfaces = localhost
......
......
......
......
......
......
[root@gitlab ~]# systemctl restart postfix
|
4.2 安装及配置Gitlab
1) 安装Gitlab
[root@gitlab ~]# curl -O https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh
[root@gitlab ~]# sh script.rpm.sh
[root@gitlab ~]# yum install gitlab-ce -y
# 或直接写repo文件
[root@node1 ~]# vim /etc/yum.repos.d/gitlab-ce.repo
[gitlab-ce]
name=Gitlab-CE
baseurl=http://192.168.1.254/repos/gitlab-ce/yum/el7/
enabled=1
gpgcheck=0
2) 修改Gitlab安装配置文件
[root@gitlab ~]# vim /etc/gitlab/gitlab.rb
......
......
......
......
......
......
# 将32行改为如下内容(填写你自己的FQDN)
external_url 'http://gitlab.1000y.cloud'
......
......
......
......
......
......
3) 安装Gitlab
[root@gitlab ~]# gitlab-ctl reconfigure
......
......
......
......
......
......
Notes:
Default admin account has been configured with following details:
Username: root
Password: You didn't opt-in to print initial root password to STDOUT.
# 提示初始化密码所存放的位置
Password stored to /etc/gitlab/initial_root_password. This file will be cleaned up in first reconfigure run after 24 hours.
NOTE: Because these credentials might be present in your log files in plain text, it is highly recommended to reset the password following https://docs.gitlab.com/ee/security/reset_user_password.html#reset-your-root-password.
gitlab Reconfigured!
[root@gitlab ~]# cat /etc/gitlab/initial_root_password | grep Password:
Password: wBlTUPr+On2bnkYK1SXvxLb2YseFA3N+OWVZz8Bx8q8=
2) 配置Gitlab
[浏览器]=>http://gitlab.1000y.cloud
密码修改后,将会自动强制重新登陆
3) 创建一个Gitlab群组
组名为 kubernetes,类型为: 私有
3) 创建一个Porject
# 项目名称: spring-boot-project
|
5. Jenkins与Gitlab互联测试
1) 设定Jenkins端ssh密钥
[root@jenkins ~]# ssh-keygen -q -N '' -C "snowchuai@1000y.cloud"
Enter file in which to save the key (/root/.ssh/id_rsa): # 回车
2) 复制jenkins ssh公钥至Gitlab
(1) Jenkins端操作
[root@jenkins ~]# cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNyNXAc/hgI72ZseiDj9lj5Uwnfh4isAUVzmERQ6jzcm/vjCo3Ok5vC6bu4YDYJ953yerL5XWkqyCGWF
xKF/Or/gFwz7EfeFtTOIkYbSC39kOadawkOOp66oODwQVe3/8AOuKIYMf9ywo1E4t4EkmcJerW9FQrI0AU0jJEnN1WA1Vg7V9QcayXMCTdI2IC/p0ta6WQ
3IhRjIjdF8T23sGepc9gj4C8VO6Cr8hBdkE7aEosAmR3CMInkOi1w9ou6tMFmR/8vScdNEkExs3XpmkhqE68U6mKYxzsRgyk/xvvkpRHS2VK89twKlmMpI
wg4D+RW6VArqWzallSDLtDX4Zr snowchuai@1000y.cloud
(2) Gitlab WEB UI端操作
3) Jenkins端测试
[root@jenkins ~]# yum install git -y
[root@jenkins ~]# git clone git@gitlab.1000y.cloud:kubernetes/spring-boot-project.git
Cloning into 'spring-boot-project'...
The authenticity of host 'gitlab.1000y.cloud (192.168.1.27)' can't be established.
ECDSA key fingerprint is SHA256:uoSm+T/hW98A1OoH1Mxb4AJS8FPylojFSEhI2J4la+Q.
ECDSA key fingerprint is MD5:98:0c:c1:97:25:ca:bd:ae:a0:6d:98:6b:15:b8:d9:2e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitlab.1000y.cloud,192.168.1.27' (ECDSA) to the list of known hosts.
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
[root@jenkins ~]# curl -O http://registry.1000y.cloud/repos/k8s-cicd/spring-boot-project.tar.gz
[root@jenkins ~]# tar xf spring-boot-project
[root@jenkins ~]# cd spring-boot-project/
[root@jenkins spring-boot-project]# git add .
[root@jenkins spring-boot-project]# git commit -am "Spring Boot Project"
[main c85538c] Spring Boot Project
......
......
......
......
......
......
create mode 100644 target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar.original
[root@jenkins spring-boot-project]# git push origin main
Counting objects: 34, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (23/23), done.
Writing objects: 100% (32/32), 40.05 MiB | 11.48 MiB/s, done.
Total 32 (delta 0), reused 0 (delta 0)
To git@gitlab.1000y.cloud:kubernetes/spring-boot-project.git
103aa20..c85538c main -> main
4) Gitlab端测试
5) Jenkins端--Jenkins容器测试与Gitlab SSH连接
# 本测试必须操作,后期CI/CD测试时,也需要Jenkins容器能够SSH连接Gitalb。如果前期没有导入gitlab服务器的ssh host key,则会触发报错信息
[root@jenkins ~]# docker exec -it jenkins /bin/bash
root@e5ff65a88997:/# ssh gitlab.1000y.cloud
The authenticity of host 'gitlab.1000y.cloud (192.168.1.27)' can't be established.
ED25519 key fingerprint is SHA256:lBeG3WSuUw3S+DEBV1RC+XCEbPEwKdruOp0+95TKc8c.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'gitlab.1000y.cloud' (ED25519) to the list of known hosts.
root@gitlab.1000y.cloud's password: # 输入gitlab.1000y.cloud的root密码
Last login: Fri Mar 22 13:37:38 2024 from 192.168.1.28
[root@gitlab ~]#
|
6. 配置Jekins
6.1 Jenkins添加凭证
1) 取消插件告警
2) 加添凭证
(1) 添加kubernetes凭证
(2) 添加HarBor凭证
(3) 添加Gitlab凭证---[添加Jenkins SSH私钥]
|
6.2 Jenkins Agent配置
1) 取消插件告警
# 通常情况下,Jenkins Slave 会通过 Jenkins Master 节点的 50000 端口与之通信,所以需要开启 Agent 的 50000 端口。
|
6.3 定义Jenkins Slave节点并配置
1) 定义标签
# 1. 实际使用时,没有必要把整个 Kubernetes 集群的节点都充当创建 Jenkins Slave Pod 的节点, 可以选择任意的一个或多个节点作为创建 Slave Pod 的节点。
2. 本章节选择kubernetes节点中srv6.1000y.cloud[角色: Worker/Node]主机作为 Jenkins Slave 节点
[root@srv1 ~]# kubectl label node srv6.1000y.cloud build=true
node/srv6.1000y.cloud labeled
[root@srv1 ~]# kubectl get nodes -l build=true
NAME STATUS ROLES AGE VERSION
srv6.1000y.cloud Ready <none> 4d6h v1.28.2
2) 为worker节点安装docker-ce
# Pod的生成要需Dockerfile进行制作,所以必须安装Docker
[root@srv6 ~]# yum install yum-utils device-mapper-persistent-data lvm2 -y
[root@srv6 ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@srv6 ~]# sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo
[root@srv6 ~]# yum makecache fast
[root@srv6 ~]# yum install docker-ce -y
[root@srv6 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://3laho3y3.mirror.aliyuncs.com"],
"insecure-registries": ["https://srv7.1000y.cloud"]
}
[root@srv6 ~]# systemctl enable --now docker
[root@srv6 ~]# docker login k8srepos.1000y.cloud
Username: admin # Harbor节点的账户
Password: # Harbor节点账户的密码
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
3) 创建Jenkins工作目录
[root@srv6 ~]# mkdir /opt/workspace
[root@srv6 ~]# chmod 777 /opt/workspace
|
6.4 Jenkins与kubernetes集群对接
# Kubernetes 可以叫做 “kubernetes-study"
|
7. CI/CD平台设计
8. CI/CD实现
8.1 创建Jenkinsfile
1. Jenkinsfile已保存在目录中
2. 如打算手工创建,可点击代码首页的“+”号,然后点击 New file
|
8.2 Jenkinsfile详解
1) 详解1---顶层的 Agent,定义的是 Kubernetes 的 Pod 作为 Jenkins 的 Slave
pipeline{
agent{
# 定义使用Kubernetes作为agent
kubernetes {
# 这里选择的云为之前在 Jenkins 上配置的名字
cloud 'kubernetes-study'
slaveConnectTimeout 1200
# 将 workspace 改为 hostPath,因为该 Slave 会固定节点创建,如果有存储可用,可以改为 PVC 的模式
workspaceVolume hostPathWorkspaceVolume(hostPath: "/opt/workspace", readOnly: false)
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
# jnlp 容器,用于和 Jenkins 主节点通信,注意:这里的jnlp容器中的jdk版本需要和安装的Jenkins容器中的jdk保持版本一致
- name: jnlp
image: k8srepos.1000y.cloud/k8s/inbound-agent:bookworm-jdk11
imagePullPolicy: IfNotPresent
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
volumeMounts:
- name: "localtime"
mountPath: "/etc/localtime"
readOnly: false
# build 容器,包含执行构建的命令,比如 Java 的需要 mvn 构建,就可以用一个 maven 的镜像
- name: build # 容器的名字,流水线的 stage 可以直接使用该名字
# 使用 Maven 镜像,包含 mvn 工具。NodeJS 可以用 node 的镜像
image: k8srepos.1000y.cloud/k8s/maven:3.5.3
imagePullPolicy: IfNotPresent
tty: true
command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumeMounts:
- name: "localtime"
mountPath: "/etc/localtime"
readOnly: false
# Pod 单独创建了一个缓存的 volume,将其挂载到了 maven 插件的缓存目录,默认是 /root/.m2
- name: "cachedir"
mountPath: "/root/.m2"
readOnly: false
# 发版容器,因为最终是发版至 Kubernetes 上的,所以需要有一个 kubectl 命令
- name: kubectl
# 镜像的版本可以替换为其它的版本,也可以不进行替换,因为只是执行 set 命令,所以版本是兼容的
image: k8srepos.1000y.cloud/k8s/citools/kubectl:self-1.17
imagePullPolicy: IfNotPresent
tty: true
command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumeMounts:
- name: "localtime"
mountPath: "/etc/localtime"
readOnly: false
# 用于生成镜像的容器,需要包含 docker 命令
- name: docker
image: k8srepos.1000y.cloud/k8s/citools/docker:19.03.9-git
imagePullPolicy: IfNotPresent
tty: true
command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
volumeMounts:
- name: "localtime"
mountPath: "/etc/localtime"
readOnly: false
# 由于容器没有启动 docker 服务,所以将宿主机的 docker 经常挂载至容器即可
- name: "dockersock"
mountPath: "/var/run/docker.sock"
readOnly: false
restartPolicy: "Never"
# 固定节点部署,也就是说这里我们一般部署,只需要一个节点去执行流水线操作,所以这里固定一个节点,在需要使用的 node 节点上添加该配置的标签
nodeSelector:
build: "true"
securityContext: {}
volumes:
- name: "dockersock"
hostPath:
path: "/var/run/docker.sock"
- name: "localtime"
hostPath:
path: "/usr/share/zoneinfo/Asia/Shanghai"
- name: "cachedir"
hostPath:
path: "/opt/m2"
'''
}
2) 详解2---拉取代码的 stage,这个 stage 是一个并行的 stage,因为考虑了该流水线是手动触发还是提交代码后自动触发
stage("Pulling Code"){
parallel {
stage('Pulling Code by Jenkins'){
when {
expression {
# 假如 env.gitlabBranch 为空,则该流水线为手动触发,那么就会执行该 stage,如果不为空则会执行同级的另外一个 stage
env.gitlabBranch == null
}
}
steps {
# 这里使用的是 git 插件拉取代码,BRANCH 变量取自于前面介绍的 parameters 配置
# git@gitlab.1000y.cloud:kubernetes/spring-boot-project.git 代码地址
# credentialsId: 'gitlab-key' 之前在 Jenkins 上创建的拉取代码的 key
git(changelog: true, poll: true, url: 'git@gitlab.1000y.cloud:kubernetes/spring-boot-project.git', branch: "${BRANCH}", credentialsId: 'gitlab-key')
script {
# 定义一些变量用于生成镜像的 Tag
# 获取最近一次提交的 Commit ID
COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
# 赋值给 TAG 变量,后面的 docker build 可以取到该 TAG 的值
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
stage('Pulling Code by trigger'){
when {
expression {
# 如果 env.gitlabBranch 不为空,说明该流水线是通过 webhook 触发,则此时执行该 stage,上述的 stage 不再执行。此时 BRANCH 变量为空
env.gitlabBranch != null
}
}
steps {
# 以下配置和上述一致,只是此时 branch: env.gitlabBranch 取的值为 env.gitlabBranch
git(changelog: true, poll: true, url: 'git@gitlab:kubernetes/spring-boot-project.git', branch: env.gitlabBranch, credentialsId: 'gitlab-key')
script {
COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
TAG = BUILD_TAG + '-' + COMMIT_ID
println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}"
}
}
}
}
}
3) 详解3---生成对应的的镜像,此时可以使用 Pod 模板的 docker 容器
stage("Docker build for creating image"){
# 首先取出 HARBOR 的账号密码(也就是之前在Jenkins上配置的认证信息)
environment {
HARBOR_USER = credentials('HARBOR_ACCOUNT')
}
steps {
# 指定使用 docker 容器
container(name: "docker"){
sh """
echo "===================开始构建Docker镜像及推送==================="
echo ${HARBOR_USER_USR} ${HARBOR_USER_PSW} ${TAG}
# 执行build命令,Dockerfile会在后面创建,也是放在代码仓库,和 Jenkinsfile 同级
docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} .
# 登陆 Harbor,HARBOR_USER_USR和HARBOR_USER_PSW由上面的environment生成
docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS}
# 将镜像推送至镜像仓库
docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG}
"""
}
}
}
4) 详解4---将该镜像发版至 Kubernetes 集群中,此时使用的是包含 kubectl 命令的容器
stage("Deploying to k8s"){
# 获取连接 Kubernetes 集群的证书(也就是之前在jenkins上配置的认证信息)
environment {
MY_KUBECONFIG = credentials('k8s-kubeconfig')
}
steps {
# 指定使用 kubectl 容器
container(name: "kubectl"){
sh """
echo "===================开始更新Deployment资源镜像==================="
# 直接通过 set 命令更改 Deployment 的镜像即可
/usr/local/bin/kubectl --kubeconfig ${MY_KUBECONFIG} set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n ${NAMESPACE}
"""
}
}
}
}
5) 详解5---Jenkinsfile 中最后的环境变量和 parameters 的配置
# 定义一些全局的环境变量
environment {
COMMIT_ID = ""
HARBOR_ADDRESS = "k8srepos.1000y.cloud" # Harbor地址
REGISTRY_DIR = "k8s" # Harbor的项目目录
IMAGE_NAME = "spring-boot-project" # 镜像的名称
NAMESPACE = "kubernetes" # 该应用部署在 Kubernetes 集群中的哪个命名空间
TAG = "" # 镜像的Tag,在此使用 BUILD_TAG + COMMIT_ID 组成
}
parameters {
# 类似于 choice、input 类型的参数,这里使用 GitParameter 插件
# 该字段会在 Jenkins 页面生成一个选择分支的选项
gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')
}
|
8.3 定义Dockerfile
1) 创建Dockerfile
1. Dockerfile已保存在目录中
2. 如打算手工创建,可点击代码首页的“+”号,然后点击 New file
2) Dockerfile说明
# 基础镜像可以按需修改,可以更改为公司自有镜像
FROM k8srepos.1000y.cloud/k8s/jre:8u211-data
# jar 包名称改成实际的名称,本示例为 spring-cloud-eureka-0.0.1-SNAPSHOT.jar
COPY target/spring-cloud-eureka-0.0.1-SNAPSHOT.jar ./
# 启动 Jar 包
CMD java -jar spring-cloud-eureka-0.0.1-SNAPSHOT.jar
|
8.4 定义Kuberntes资源
1) 撰写资源清单
[root@srv1 ~]# mkdir cicd-test
[root@srv1 ~]# vim cicd-test/test-cicd.yaml
---
apiVersion: v1
kind: Service
metadata:
labels:
app: spring-boot-project
name: spring-boot-project
namespace: kubernetes # 和流水线中定义的变量(NAMESPACE)保持一致
spec:
ports:
- name: web
port: 8761 # 端口按照实际情况进行修改
protocol: TCP
targetPort: 8761 # 端口按照实际情况进行修改
selector:
app: spring-boot-project
sessionAffinity: None
type: NodePort # 这里根据实际情况进行修改,这里测试所以用的 NodePort 类型
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: spring-boot-project
namespace: kubernetes # 和流水线中定义的变量(NAMESPACE)保持一致
spec:
rules:
- host: srv1.1000y.cloud
http:
paths:
- backend:
service:
name: spring-boot-project
port:
number: 8761
path: /
pathType: ImplementationSpecific
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: spring-boot-project # Deployment 标签,和流水线的 set -l 保持一致,用于更新镜像版本
name: spring-boot-project # Deployment 名称
namespace: kubernetes # 和流水线中定义的变量(NAMESPACE)保持一致
spec:
replicas: 1
selector:
matchLabels:
app: spring-boot-project # 匹配 Pod 的标签
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
type: RollingUpdate
template:
metadata:
labels:
app: spring-boot-project # Pod 的标签,需要和上面 selector 保持一致
spec:
containers:
- name: spring-boot-project # 容器的名称,需要和流水线 set 命令的容器名称一致
image: k8srepos.1000y.cloud/k8s/demoapp:v1.4 # 此处使用的 demoapp 作为原始的镜像,通过 Jenkins 构建并发版后,变成 Java 应用镜像
imagePullPolicy: IfNotPresent
env:
- name: TZ
value: Asia/Shanghai
- name: LANG
value: C.UTF-8
ports:
- containerPort: 8761 # 容器端口号,根据实际 java 应用进行修改
name: web
protocol: TCP
lifecycle: {}
livenessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8761 # 端口号和健康检查按照实际情况进行修改
timeoutSeconds: 2
readinessProbe:
failureThreshold: 2
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 8761 # 端口号和健康检查按照实际情况进行修改
timeoutSeconds: 2
resources: # 资源请求按照实际情况修改
limits:
cpu: 994m
memory: 1170Mi
requests:
cpu: 10m
memory: 55Mi
dnsPolicy: ClusterFirst
imagePullSecrets:
- name: harborkey # Harbor 仓库密钥,需要和上述创建的 Secret 一致
restartPolicy: Always
securityContext: {}
serviceAccountName: default
2) 创建kubernetes相关资源
[root@srv1 ~]# kubectl create namespace kubernetes
namespace/kubernetes created
[root@srv1 ~]# kubectl create secret docker-registry harborkey --docker-server=k8srepos.1000y.cloud --docker-username=admin --docker-password=123456 --docker-email=snow@1000y.cloud -n kubernetes
secret/harborkey created
[root@srv1 ~]# kubectl apply -f cicd-test/test-cicd.yaml
service/spring-boot-project created
ingress.networking.k8s.io/spring-boot-project created
deployment.apps/spring-boot-project created
3) 确认kuberntes资源生成
# READY状态0/1是正常
[root@srv1 ~]# kubectl get pod -n kubernetes
NAME READY STATUS RESTARTS AGE
spring-boot-project-7d4f5d769-4pnrw 0/1 Running 0 26s
|
8.5 实现CI/CD
1) 创建Jenkins Job
2) 构建项目---1
# 第一次构建会出现失败,可直接忽略
3) 构建项目---2
# 第一次构建结束后,可以看到 Build Now 变成了 Build with Parameters。点击 Build with Parameters 后,可以读取到 Git 仓库的分支,之后可以选择分支进行手动构建
4) Blue Ocean 查看直观构建流程
5) 确认Harbor仓库已经存在项目所需的镜像
6) 确认kubernetes资源信息
[root@srv1 ~]# kubectl get pod -n kubernetes
NAME READY STATUS RESTARTS AGE
spring-boot-project-6db89f4c5b-ftqzm 1/1 Running 0 8m13s
[root@srv1 ~]# kubectl get deploy spring-boot-project -n kubernetes -o jsonpath='{.spec.template.spec.containers[0].image}'
k8srepos.1000y.cloud/k8s/spring-boot-project:jenkins-spring-boot-project-2-c85538c
[root@srv1 ~]# kubectl get svc -n kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
spring-boot-project NodePort 10.107.221.159 <none> 8761:30694/TCP 23m
7) 结果确认
[浏览器]===>srv1.1000y.cloud:30694
|
8.5 自动触发构建与实现
1) 说明
1. 之前的构建都是采用手动选择分支进行构建的,实际使用时,项目可能有很多,如果都是手动触发可能比较消耗人力。所以推荐可以按需配置自动触发,即提交代码后自动触发 Jenkins 进行构建任务。
2) 自动触发构建
(1) Jenkins配置
(2) Gitlab配置
(3) 测试配置
|
8.6 一次构建多次部署机制实现
1) 说明
1. 上面通过 Gitlab 的事件触发 Jenkins 任务,在实际使用过程中,一般 UAT 和生产环境,一般不需要再次构建,而是选择其他环境产生的镜像进行发版。这里同样以上面的 Java 项目示例
2) 实现
# 创建一个新的 Job,名字为 java-project-uat,类型 Pipeline
3) Pipeline脚本
pipeline{
agent{
kubernetes {
cloud 'kubernetes-study'
slaveConnectTimeout 1200
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
# 只需要配置 jnlp 和 kubectl 镜像即可
- name: jnlp
image: k8srepos.1000y.cloud/k8s/inbound-agent:bookworm-jdk11
imagePullPolicy: IfNotPresent
args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
- name: kubectl
image: k8srepos.1000y.cloud/k8s/citools/kubectl:self-1.17
imagePullPolicy: IfNotPresent
tty: true
command:
- "cat"
env:
- name: "LANGUAGE"
value: "en_US:en"
- name: "LC_ALL"
value: "en_US.UTF-8"
- name: "LANG"
value: "en_US.UTF-8"
restartPolicy: "Never"
nodeSelector:
build: "true"
securityContext: {}
'''
}
}
stages{
stage("Deploy"){
environment {
MY_KUBECONFIG = credentials('k8s-kubeconfig')
}
steps {
container(name: "kubectl"){
sh """
echo ${IMAGE_TAG} # 该变量即为前台选择的镜像
echo "===================开始更新Deployment资源镜像==================="
/usr/local/bin/kubectl --kubeconfig ${MY_KUBECONFIG} set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${IMAGE_TAG} -n ${NAMESPACE}
sleep 3
/usr/local/bin/kubectl --kubeconfig ${MY_KUBECONFIG} get po -l app=${IMAGE_NAME} -n ${NAMESPACE}
"""
}
}
}
}
environment {
HARBOR_ADDRESS = "k8srepos.1000y.cloud"
IMAGE_NAME = "spring-boot-project"
NAMESPACE = "kubernetes"
TAG = ""
}
}
4) 测试
(1) 为Jenkins容器增加对Harbor HTTPS自签证书的信任
# 将harbor的自签证书增加download至Jenkins服务节点
[root@jenkins ~]# docker exec jenkins sh -c "echo | openssl s_client -connect k8srepos.1000y.cloud:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /var/tmp/sonarqube.crt"
depth=0 C = CN, ST = BeiJing, O = 1000y.cloud, OU = tech, CN = k8srepos.1000y.cloud
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = CN, ST = BeiJing, O = 1000y.cloud, OU = tech, CN = k8srepos.1000y.cloud
verify error:num=21:unable to verify the first certificate
verify return:1
depth=0 C = CN, ST = BeiJing, O = 1000y.cloud, OU = tech, CN = k8srepos.1000y.cloud
verify return:1
DONE
# 将导出的证书导入至Jenkins容器,导入的密码为changeit
[root@jenkins ~]# docker exec jenkins sh -c "keytool -import -alias k8srepos \
-file /var/tmp/sonarqube.crt -cacerts -storepass changeit -noprompt -trustcacerts"
Certificate was added to keystore
# 重启Jenkins
[浏览器]===>http://jenkins.1000y.cloud:8080/restart
(2) 测试
[root@srv1 ~]# kubectl get pod -n kubernetes
NAME READY STATUS RESTARTS AGE
spring-boot-project-988d4cccc-bh885 1/1 Running 0 118s
|
如对您有帮助,请随缘打个赏。^-^