共计 13847 个字符,预计需要花费 35 分钟才能阅读完成。
这篇文章给大家介绍 k8s+docker 如何部署 jenkins+gitlab 实现 CICD,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
CICD 核心概念
CICD 是持续集成(continuous integration,CI),持续交付(continuous delivery,CD),持续部署(continuous Deployment,CD)的简称。
指在开发过程中自动执行一系列脚本来减低开发引入 bug 的概率,在新代码从开发到部署的过程中,尽量减少人工的介入。
1,持续集成
持续集成指的是,频繁地(一天多次)将代码集成到主干。
它的好处有两个:
1)快速发现错误:每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。
2)防止分支大幅偏离主干:如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。
持续集成的目的:
让产品可以快速迭代同时还能保持高质量,它的核心措施是:代码集成到主干之前,必须通过自动化测试,只要有一个测试用例失败,就不能集成。
Martin Fowler 说过,持续集成并不能消除 Bug,而是让它们非常容易发现和改正。
2,持续交付
持续交付指的是频繁的将软件的新版本交付给质量团队或用户,以供评审,如果评审通过,代码就进入生产阶段。
持续交付可以看作是持续集成的下一步,强调的是,不管怎样更新,软件是随时随地可以交付的。
3,持续部署
持续部署是持续交付的下一步,指的是代码通过评审之后,自动部署到生产环境。
持续部署的目标是:代码在任何时候都是可以部署的,可以进入生产阶段。
持续部署的前提是能自动化完成测试,构建,部署等步骤。
持续部署与持续交付的区别,可以参考下图:
Docker,kubernetes 的 CICD 实现思路
jenkins 是一个比较流行的持续集成工具。
GitLab 是存储镜像的镜像仓库。
流程详解:
由客户端将代码 push 推送到 git 仓库,gitlab 上配置了一个 webHook 的东西可以触发 Jenkins 的构建。进入到 Jenkins 虚线范围内,它所做的事情非常多,从 mvn 构建代码,对代码进行静态分析,做单元测试,测试通过之后就可以 build 镜像,镜像构建成功后就把镜像 push 推送到 Harbor 镜像仓库中,镜像 push 推送到镜像仓库后,我们就可以调用 kubernetes 集群的 restAPI 更新服务,而后 kubernetes 接收到了更新的指令,从 Harbor 镜像仓库 pull 拉取镜像,从而完成服务的更新与重启,最后我们从客户端来访问 kubernetes 集群的服务。
项目实践
项目环境:
主机操作系统 ip 地址 k8s01(master)Centos 7.3172.16.1.30k8s02(node01)Centos 7.3172.16.1.31k8s03 (node02)Centos 7.3172.16.1.32jenkins+gitlab+dockerCentos 7.3172.16.1.33 项目实施:
本文所用到的安装包和插件我已上传至百度网盘:链接:https://pan.baidu.com/s/17mDLgSZ218a-zYhjYddhiA
提取码:nyxh
1,部署 kubernetes 集群(前三台主机):
部署 kubernetes 集群可参考博文 kubeadm 部署 kubernetes 集群
# 确保 k8s 集群正常运行:[root@master ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master Ready master 112d v1.15.0
node01 Ready none 112d v1.15.0
node02 Ready none 112d v1.15.0
2,集群中部署 harbor 私有仓库 **
可以选择任意一台服务器,这里选择 master 作为 harboar 私有仓库。详细配置可参考博文 kubernetes 部署 Harbor 私有仓库
[root@master ~]# yum -y install yum-utils device-mapper-persistent-data lvm2
[root@master ~]# curl -L https://github.com/docker/compose/releases/download/1.25.0-rc4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
[root@master ~]# chmod +x /usr/local/bin/docker-compose
[root@master harbor]# wget https://storage.googleapis.com/harbor-releases/release-1.7.0/harbor-offline-installer-v1.7.4.tgz
[root@master harbor]# tar xf harbor-offline-installer-v1.7.4.tgz
[root@master harbor]# cd harbor/
[root@master harbor]# vim harbor.cfg
[root@master harbor]# ./install.sh # 执行安装脚本
[Step 4]: starting Harbor ...
Creating network harbor_harbor with the default driver
Creating harbor-log ... done
Creating redis ... done
Creating registryctl ... done
Creating harbor-adminserver ... done
Creating harbor-db ... done
Creating registry ... done
Creating harbor-core ... done
Creating harbor-portal ... done
Creating harbor-jobservice ... done
Creating nginx ... done
✔ ----Harbor has been installed and started successfully.----
Now you should be able to visit the admin portal at http://172.16.1.30.
For more details, please visit https://github.com/goharbor/harbor .
# 登录 web 界面新建仓库,URL:http://172.16.1.30
默认用户名:admin 密码:Harbor12345
# 修改 docker 配置文件(且重启 docker)并登录 harbor:(集群中的三个节点做相同操作)
[root@master harbor]# vim /usr/lib/systemd/system/docker.service
[root@master harbor]# systemctl daemon-reload
[root@master harbor]# systemctl restart docker
[root@master harbor]# docker login -uadmin -pHarbor12345 172.16.1.30:80
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
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
#node01 和 node02 操作同上(都需登录 harbor)
# 在 harbor 服务器(master)上,将镜像上传到私有仓库:
[root@master harbor]# docker pull nginx:latest
[root@master harbor]# docker tag nginx:latest 172.16.1.30:80/cicd/nginx:v1.0
[root@master harbor]# docker push 172.16.1.30:80/cicd/nginx:v1.0
The push refers to repository [172.16.1.30:80/cicd/nginx]
12fdf55172df: Pushed
002a63507c1c: Pushed
1c95c77433e8: Pushed
v1.0: digest: sha256:099019968725f0fc12c4b69b289a347ae74cc56da0f0ef56e8eb8e0134fc7911 size: 948
# 创建认证登录密钥,以保证 kubernetes 能够拉取 harbor 仓库中的私有镜像:
[root@master harbor]# kubectl create secret docker-registry login --docker-server=172.16.1.30:80 --docker-username=admin --docker-password=Harbor12345
secret/login created
[root@master harbor]# kubectl get secrets
NAME TYPE DATA AGE
default-token-wswg2 kubernetes.io/service-account-token 3 113d
login kubernetes.io/dockerconfigjson 1 33s
# 选择集群中的某个节点测试是否能够从 Harbor 私有仓库中拉取镜像:
[root@node01 ~]# docker pull 172.16.1.30:80/cicd/nginx:v1.0
v1.0: Pulling from cicd/nginx
1ab2bdfe9778: Pull complete
a17e64cfe253: Pull complete
e1288088c7a8: Pull complete
7ee7d3fe92e1: Pull complete
Digest: sha256:763562fbc544806c1305304da23d36d0532f082325a1c427996474e304313801
Status: Downloaded newer image for 172.16.1.30:80/cicd/nginx:v1.0
[root@node01 ~]# docker images | grep 172.16.1.30
172.16.1.30:80/cicd/nginx v1.0 c6ad7233ab97 10 minutes ago 126MB
ok,证明 kubernetes 和 Harbor 私有仓库部署完毕。接下来部署 jenkins+gitlab,并配置联动。
3,部署 jenkins+gitlab
# 在最后一台主机 172.16.1.33 上进行操作。
1),基本环境准备
# 关闭防火墙:
[root@docker-cicd ~]# systemctl stop firewalld
[root@docker-cicd ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
# 禁用 selinux:
[root@docker-cicd ~]# vim /etc/sysconfig/selinux
2)部署 jenkins 服务
[root@docker-cicd ~]# mkdir CICD
[root@docker-cicd ~]# cd CICD/
[root@docker-cicd CICD]# tar zxf jdk-8u131-linux-x64.tar.gz
[root@docker-cicd CICD]# mv jdk1.8.0_131/ /usr/java
#设置全局变量:[root@docker-cicd CICD]# vim /etc/profile
在最后添加以下配置项:export JAVA_HOME=/usr/java
export JRE_HOME=/usr/java/jre
export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
[root@docker-cicd CICD]# source /etc/profile # 使其环境变量生效
[root@docker-cicd CICD]# java -version # 验证 java 环境
java version 1.8.0_131
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
# 安装 tomcat
[root@docker-cicd CICD]# tar zxf apache-tomcat-7.0.54.ta
[root@docker-cicd CICD]# mv apache-tomcat-7.0.54 /usr/tomcat7
[root@docker-cicd CICD]# cd /usr/tomcat7/webapps/
[root@docker-cicd webapps]# ls
docs examples host-manager manager ROOT
[root@docker-cicd webapps]# rm -rf * # 删除 tomcat 网页目录原有文件
#将 jenkins war 包上传至 tomcat 的网页根目录下
[root@docker-cicd webapps]# ls
jenkins.war
# 修改 tomcat 的字符集:[root@docker-cicd webapps]# vim /usr/tomcat7/conf/server.xml
# 在 tomcat 中定义 jenkins 的家目录(/data/jenkins)[root@docker-cicd webapps]# vim /usr/tomcat7/bin/catalina.sh
export CATALINA_OPTS= -DJENKINS_HOME=/data/jenkins
export JENKINS_JAVA_OPTIONS= -Djava.awt.headless=true -Dhudson.ClassicPluginStrategy.noBytecodeTransformer=true
# 启动 tomcat(即启动 jenkins)
[root@docker-cicd webapps]# /usr/tomcat7/bin/catalina.sh start
Using CATALINA_BASE: /usr/tomcat7
Using CATALINA_HOME: /usr/tomcat7
Using CATALINA_TMPDIR: /usr/tomcat7/temp
Using JRE_HOME: /usr/java/jre
Using CLASSPATH: /usr/tomcat7/bin/bootstrap.jar:/usr/tomcat7/bin/tomcat-juli.jar
Tomcat started.
[root@docker-cicd webapps]# ss -anput | grep 8080
tcp LISTEN 0 100 :::8080 :::* users:((java ,pid=41682,fd=46))
# 浏览器登录 jenkins web 界面,在 web 界面中配置安装 jenkins
URL:http://172.16.1.33:8080/jenkins
[root@docker-cicd webapps]# cat /data/jenkins/secrets/initialAdminPassword
36ceb6eeb1bc46af8ce20935b81d8fe8
将管理员密码粘贴上后,点击“继续”。
# 左边是自动安装,右边是自定义安装,我们选择安装推荐的插件。
选择离线安装,断掉网络失败后,点击继续。
登录界面如下:
# 安装必要插件
1)首先安装中文插件:系统管理 —– 插件管理 —– avalilable(可选) 然后搜索 localization-zh-cn
安装成功后,重新启动 jenkins,可以发现界面已经支持中文了:
# 还需安装 3 个插件,搜索 gitlab 安装:Gitlab Authentication、GitLab、Gitlab Hook
安装过程可能较慢,耐心等待,
插件下载成功后,勾选重启 jenkins 选项即可:
如果网络问题导致无法下载成功,还可以在服务器目录下进行上传插件:/var/lib/jenkins/plugins 这个目录是存放所有安装的插件。(插件已上传至网盘)
3)部署 gitlab 服务
[root@docker-cicd CICD]# rpm -ivh gitlab-ce-11.9.8-ce.0.el6.x86_64.rpm
warning: gitlab-ce-11.9.8-ce.0.el6.x86_64.rpm: Header V4 RSA/SHA1 Signature, key ID f27eab47: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:gitlab-ce-11.9.8-ce.0.el6 ################################# [100%]
# 为了解决端口冲突,修改 gitlab 配置文件:
[root@docker-cicd CICD]# vim /etc/gitlab/gitlab.rb
因没有部署 dns,所以 url 修改为本机 ip,80 默认是 http 服务的端口,unicorn[‘port’]默认是 8080,同样与上边的 jenkins8080 端口冲突,所以分别修改为 81 和 8081。
# 初始化并启动 gitlab:[root@docker-cicd CICD]# gitlab-ctl reconfigure
# 确定 81 端口正常监听:[root@docker-cicd CICD]# netstat -anput | grep -w 81
tcp 0 0 0.0.0.0:81 0.0.0.0:* LISTEN 47382/nginx: master
# 浏览器登录 gitlab,并在 web 界面中进行配置
URL:http://172.16.1.33:81/
登录 gitlab 后需要先设置一个密码再登录,这里设置 1234.com(需要符合密码复杂性要求,最少 8 位),用户默认为 root。
# 配置 ssh 密钥认证:
部署 jenkins 和 gitlab 这两个服务的联动,需要经过 ssh 验证。
首先在 gitlab 上绑定 jenkins 服务器的 ssh 公钥(因为是部署在同一台服务器上,所以绑定自己的公钥)
[root@docker-cicd ~]# ssh-keygen -t rsa
[root@docker-cicd ~]# cat /root/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDW7s9qm08DaiShtnjBbUUwOpFYmvYaqUuqrIrXHrvcGGQDlte6Ug0R7/K5Igz4HKsjZIFCCblzgH2VLIk6FM0L+eccKnW8/uSywQcKclgK3gqiTRBDiqSt4NqYQz1R8hEW3KbXkXXUIU8kJ3svehxzG0Y8lUrMy7zEhkJ6vod7z5wcJeayzVfkro6Xd4TMiRrasXilApRiIr1Sr9Z9dWgWQkCCM85pQeZZirsZ/w4fT6gwRpP1kTtRBggDnXGi7lfWkMbKYljKMuG4jp92K8mRBLyjsg6Lkq0hkKAOToftwmpCx8CA/05LhMexvDnJXyFg/o+8yG+o0qmrlSvojl+N root@docker-cicd
复制这个公钥,然后登陆 gitlab,点击右上角的设置:
# 在 gitlab 上创建一个代码仓库:
输入一个仓库的名字 权限选择公共的(public)然后直接点击创建:
点击新建一个 new.file:
创建完成后,在本地测试是否能够拉取仓库中的文件:
[root@docker-cicd ~]# git clone git@172.16.1.33:root/my-test-project.git
[root@docker-cicd ~]# cd my-test-project/
[root@docker-cicd my-test-project]# ls
index.html
[root@docker-cicd my-test-project]# cat index.html
print: hello world!!
4)配置 jenkins 和 gitlab 联动
该 URL 链接:
# 执行构建操作:
#!/bin/bash
#定义变量(存放数据的目录)backupcode= /data/backcode/$JOB_NAME/$BUILD_NUMBER
#创建该目录
mkdir -p $backupcode
#对 jenkins 家目录(/data/jenkins)下的 workspace/ 设置所需拥有的权限
chmod 644 $JENKINS_HOME /workspace/ $JOB_NAME /*
#使用 rsync 工具拷贝并同步数据
rsync -acP $JENKINS_HOME /workspace/ $JOB_NAME /* $backupcode
#以下操作是编写一个 Dockerfile 文件(将修改的内容拷贝到新镜像中)
echo FROM 172.16.1.30:80/cicd/nginx:v1.0 $JENKINS_HOME /workspace/Dockerfile # 源镜像就使用私有仓库中镜像
echo COPY ./ $JOB_NAME /* /usr/share/nginx/html/ $JENKINS_HOME /workspace/Dockerfile
#删除旧版本的镜像(因为存在会持续不断的进行构建)docker rmi 172.16.1.30:80/cicd/nginx:v2.0
#使用 docker build 通过该 dockerfile 构建新版本镜像
docker build -t 172.16.1.30:80/cicd/nginx:v2.0 / $JENKINS_HOME /workspace/.
#将新生成的新镜像 push 到私有仓库上
docker push 172.16.1.30:80/cicd/nginx:v2.0
#删除之前版本的 deployment 资源(nginx 应用)ssh root@172.16.1.30 kubectl delete deployment nginx
#重新创建 nginx 应用(这次从仓库中拉取的镜像是新生成的镜像)ssh root@172.16.1.30 kubectl apply -f /root/yaml/nginx.yaml
注意:/root/yaml/nginx.yaml 此路径是自定义的,后边需要在该目录下创建 nginx 的 YAML 文件(路径保持一致,否则会导致构建失败)
这里面写的是 jenkins 构建时会执行的 shell 脚本,这个脚本才是实现持续集成核心,它实现了下端 kubernetes 自动更新容器的操作。
注意:脚本中所定义的内容,得根据你们自己当前的环境进行定义(比如主机地址,私有仓库镜像和存放文件路径都是不同的),脚本编写较易,可根据自己的需求进行修改。
# 编写完脚本后不要保存,下面的这个插件很重要,就是他实现自动化更新的 webhook 插件,首先复制下图的 jenkins URL 地址,然后去 gitlab 上绑定 webhook:
复制 url 后点击保存:
## 登录 github 进行操作
点击添加后,可以看到有报错提示:gitlab 默认设置不允许向自己发送 webhook(因为我们是部署在一台服务器上),如下图所示:
## 修改全局配置,勾选允许发送本地请求:
# 修改成功后,重新添加 web hook:
# 添加完成后,会出现一个版块,测试连接:
证明 jenkins 与 gitlab 联动成功。
# 如果添加 webhook 出现以下报错信息,则需要在 jenkins 上的“全局安全配置”中开启匿名访问权限,然后重新添加。报错信息如下图:
5)配置 jenkins 免密登录 kubernetes 集群
配置免密登录的目的是为了在构建时,能够去执行 master 中的 YAML 文件。
# 将 jenkins 主机上的密钥对拷贝给 master 节点,以实现能够免密登录集群中的 master:[root@docker-cicd ~]# ssh-copy-id root@172.16.1.30
到此,集成环境部署完毕,接下来进行测试。
5,测试部署环境
在 gitlab 上新建代码,删除代码,修改代码,都会触发 webhook 进行自动部署。最终会作用在所有的 nginx 容器中,也就是我们的 web 服务器。
# 首先将 jenkins 和 gitlab 这台主机登录 harbor 私有仓库:
1)安装 docker:
[root@docker-cicd ~]# cd /etc/yum.repos.d/
[root@docker-cicd yum.repos.d]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker-cicd yum.repos.d]# yum repolist # 查看可用的 repo 源
[root@docker-cicd yum.repos.d]# yum -y install docker-ce
[root@docker-cicd yum.repos.d]# systemctl start docker
[root@docker-cicd yum.repos.d]# systemctl enable docker
[root@docker-cicd yum.repos.d]# docker -v
Docker version 19.03.6, build 369ce74a3c
2)修改 docker 配置文件:
[root@docker-cicd yum.repos.d]# vim /usr/lib/systemd/system/docker.service
# 重新加载 docker 服务:[root@docker-cicd yum.repos.d]# systemctl daemon-reload
[root@docker-cicd yum.repos.d]# systemctl restart docker
3)登录 harbor 仓库:
[root@docker-cicd ~]# docker login -uadmin -pHarbor12345 172.16.1.30:80
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
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
4)在 master 上创建在 shell 脚本中定义的 nginx 应用的 YAML 文件(部署 web 服务):
[root@master ~]# mkdir yaml
[root@master ~]# cd yaml/
[root@master yaml]# vim nginx.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2 # 定义两个副本
template:
metadata:
labels:
web: nginx
spec:
containers:
- name: nginx
image: 172.16.1.30:80/cicd/nginx:v2.0 # 镜像指定私有仓库中的镜像(注意:版本为在 jenkins 上新构建的版本) imagePullPolicy: Always # 定义镜像策略(每次创建 pod 时,总是从仓库中重新拉取镜像) ports:
- containerPort: 80
imagePullSecrets: # 添加 imagePullSecrets 字段,指定刚才创建的登录密钥(login) - name: login
apiVersion: v1 # 创建 service 资源(映射 web 端口为 31234)kind: Service
metadata:
name: nginx-svc
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 31234
selector:
web: nginx
# 在 gitlab 上修改或新建代码(例如修改之前创建的 index.html 文件)
# 点击提交后,会触发 webhook,进行构建:
控制台输出信息中会显示构建过程中的详细信息,如果在构建的过程中那个环节出现了问题,也能在信息中准确的查看到,如下图所示:
# 浏览器访问 web 服务(nginx),URL:http://172.16.1.30:31234
# 在 gitlab 上重新修改代码:
// 修改内容: h2 hello world, This is two build /h2
再次触发 webhook,重新构建:
# 重新通过浏览器访问 nginx 服务:
# 第三次在 gitlab 上修改代码:
// 修改代码为:h2 hello world, This is three build /h2
# 重新通过浏览器访问 nginx:
# 在服务器本地查看上面构建的项目和文件:
[root@docker-cicd ~]# cd /data/
[root@docker-cicd data]# ls
backcode jenkins #backcode 为我们创建的存放构建项目的目录,一个为 jenkins 的家目录
[root@docker-cicd data]# cd backcode/test/
[root@docker-cicd test]# ls # 在当前目录下存放了所构建的项目
10 11 12 3 4 5 6 7 8 9
[root@docker-cicd test]# cat 12/index.html # 而目录中的内容正是我们所构建的代码
h2 hello world, This is three build /h2
[root@docker-cicd test]# cd ../../jenkins/workspace/
[root@docker-cicd workspace]# ls
Dockerfile test
[root@docker-cicd workspace]# cat test/index.html
h2 hello world, This is three build /h2
#在 jenkins 家目录下存放了 Dcokerfile 文件和最新构建的代码
至此,CICD 项目部署完毕,Kubernetes 中的 web 应用,会通过 jenkins+gitlab 的自动构建,无需人工的介入,自动部署并更新 web 界面,减少了在生产中出现的 bug 的概率,等待时间及更高的产品质量。
关于 k8s+docker 如何部署 jenkins+gitlab 实现 CICD 就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。