Rancher-2-2-2之Jenkins+rancher+harbor+Gitlab部署应用到生产
关于 Jenkins 结合 rancher 进行应用的持续集成,整个流程事实上并不算复杂,只不过牵扯到的东西,以及需要注意到的地方太多,因此这篇文章就针对全局技能的掌握以及过程中的技巧的应用进行分享。
# 1,环境准备。
这次所做的实验主机系统全部基于CentOS Linux release 7.6.1810 (Core)
。
# 1,关于应用的准备。
应用 | 版本 |
---|---|
Gitlab | latest |
Jenkins | 2.138 |
harbor | 1.7.1 |
rancher | 2.2.2 |
# 2,rancher-cli 的准备。
想要使 Jenkins 与 rancher 打通,需要借助于 rancher-cli 这个工具,具体配置流程参考:rancher-cli 的使用 (opens new window)。
# 3,关于 rancher 环境存储卷的准备。
- 1,创建存储卷。
前边已经搭建 (opens new window)了一个完整可用的 rancher 集群,因为部署应用考虑到一个日志问题,所以这里准备一个存储卷用于应用挂载。
首先进入到将要部署应用的集群(关于集群的规划问题,后续再深入研究摸索)当中,点击应用商店
,选择启用
,搜索到nfs
,点击详情
进行部署。
部署完成之后,可以在集群的工作负载
之中看到对应的服务。
这个时候,还需要进行一些小调整,使得这个服务能够固定地跑在某一个节点之上。我的考虑是这样的,后续所有应用的日志都通过这个服务进行汇总,这样以来开发同学面对应用的时候,就只需要在 Jenkins 界面点击一下部署,然后去到一个统一的位置查看日志就行了,而不用考虑应用在这个过程中做了哪些事情。
所以我在集群的work-2
节点上加了一块儿 500G 的硬盘,并挂载在了data
目录下。
[root@work-2 ~]$df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/centos-root xfs 196G 12G 184G 6% /
devtmpfs devtmpfs 12G 0 12G 0% /dev
tmpfs tmpfs 12G 0 12G 0% /dev/shm
tmpfs tmpfs 12G 12M 12G 1% /run
tmpfs tmpfs 12G 0 12G 0% /sys/fs/cgroup
/dev/sda1 xfs 497M 208M 290M 42% /boot
/dev/sdb1 xfs 500G 33M 500G 1% /data
tmpfs tmpfs 2.4G 0 2.4G 0% /run/user/0
2
3
4
5
6
7
8
9
10
注意
:留意新增的分区文件系统,需要使用xfs
的,否则后期可能会出现 pod 挂载失败的报错。报错内容如下:
Unable to mount volumes for pod "isj-eureka-57fb65b885-wf77q_isj(b0b0594f-715e-11e9-884a-0050568fa4d0)": timeout expired waiting for volumes to attach or mount for pod "isj"/"isj-eureka-57fb65b885-wf77q". list of unmounted volumes=[eureka]. list of unattached volumes=[eureka default-token-9wmpb]
接下来对刚刚在应用商店里部署的 nfs 服务进行一些小小的调整,从而满足我们的需求,点击升级可以更改应用的一些配置信息。
这里主要修改两个地方。
- 主机调度:让 pod 绑定在 work-2 上,从而始终在我们加了硬盘的主机之上。
- 数据卷:卷名可以自定义,主要是挂载路径更改成我们预设的
/data
目录,否则就会跑到它默认的 / srv 目录下了。
调整之后,点击升级就可以了,这样就可以使用这个存储卷了。
在 rancher 中有两个关于存储的名字,一个存储类,一个持久卷。通俗一点理解的话,存储类则像是逻辑卷,持久卷则像是从逻辑卷当中分出来的一个一个存储分区,刚刚安装的这个 nfs 属于存储类,后续需要的话,可以直接从里边划分,非常方便,后边部署应用的时候会用到,这里先说这么多。
- 2,添加持久卷。
上边存储卷配置完成之后还不能用,为了下边部署应用顺利,这里还需要添加一下持久卷。
来到集群的数据卷栏目,配置添加:
点击创建之后,就能在持久卷当中看到一块儿 “磁盘” 挂载了,后边部署应用的时候也都可以使用了。
# 2,安装服务。
各个服务安装流程这里就不详细说明了。不明白的,可以直接点击下边对应的地址进行参考:
- Gitlab (opens new window)
- Jenkins (opens new window)
- Harbor (opens new window)
- Rancher (opens new window)
# 3,进入正式配置。
如上我们已经准备了这么一堆的零件,现在该从何入手,仿佛一时间还有一些懵,这个时候,必然是先从最基础的镜像开始的,这是第一步。
思路大概应该是这样,首先在 Jenkins 主机上将应用代码克隆下来,然后进行编译,接着编写 Dockerfile 构建镜像,然后跑一跑调试下,如果可以那么推到私服,接着就可以在 rancher 当中部署了,最后再整理一下流程当中的步骤,给它落实到 Jenkins 当中即可。
现在就遵照着上边规划的思路,一步一步部署一个应用出来。
# 1,克隆代码,构建应用。
因为最终这些都是落实到 Jenkins 当中的,所以制作镜像也就直接在 Jenkins 身上完成了。
当然,这里的步骤,可以稍微省力的直接在 Jenkins 上进行调试,为了方便,我直接创建一个maven风格
的应用进行配置。
因为开始都是这些老生常谈的几项配置,所以就不再详细叙述,直接通过下边一个截图看配置。
配置当中主要也就那么几个事儿,保留 8 此构建历史,添加文本参数实现代码分支构建的需求,添加选项参数实现部署回滚的需求,添加 git 代码地址,注意分支引用上边文本参数的变量名称,然后就是利用 maven 工具对项目进行编译。
现在可以直接构建一次,让应用包先打出来。
接着去到$WORKSPACE
里边编写 Dockerfile。写完之后进行一下构建,构建完成之后,run 一下看看是否能够正常跑起来,如果可以的话,就可以推到私服,进行部署的操作了。
把刚才说的这段话翻译成 shell 脚本放进 Jenkins,大概就是下边的样子:
#!/bin/bash
source /etc/profile
#
##set color##
echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }
##set color##
#
project="ebei-mudao"
version=`date +%Y%m%d%H%M%S`
echo -------------------------------------
# 进入项目target目录
cd $WORKSPACE/$project-server/target/ && mv $project-server-1.0.jar app.jar
# 创建docker镜像
cat > run.sh << EOF
#!/bin/bash
source /etc/profile
/opt/app.jar run
EOF
cat > app.conf << EOF
MODE=service
APP_NAME=$project-server
EOF
chmod +x run.sh app.jar
cat >Dockerfile << EOF
FROM 192.168.112.69/public/jdk:1.8
MAINTAINER eryajf <liqilong@edspay.com>
ENV LANG en_US.UTF-8
ADD app.jar /opt
ADD run.sh /
ADD app.conf /opt
EXPOSE 8004
ENTRYPOINT [ "sh", "-c", "/run.sh" ]
EOF
# 编译镜像
echoGreen "开始构建当次镜像!"
docker build -t 192.168.112.69/mudao/$project:$version .
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
这里有一些个人小心得,特此表达一下。
1,包名优化。
因为同类应用最后生成的包名如下:
- ebei-a-server-1.0.jar
- ebei-b-server-1.0.jar
- ebei-c-server-1.0.jar
进入到容器之后就不必计较这些分别,所以就统一成了 app.jar,从而让脚本的通用性更强,在后续新增项目的时候,修改更少的代码即能部署,以提高效率。
2,巧用 cat 的特性。
因为 Dockerfile 需要一些文件来辅助,创建这些文件的时候,我用到了cat
这个命令,上边包名优化的时候可以一致,而下边配置内容里边,却又要保证项目名称保持原样,于是调用一开始的project变量
,通过 cat 命令之后,会直接将APP_NAME=$project-server
执行为APP_NAME=ebei-mudao-server
,如此以来,其他应用部署的时候,这个配置就不用改了,只需更改一下开头的 project 对应的名称即可。
# 2,推送镜像,部署应用。
镜像制作完成并测试之后,就可以推送到私服当中了。
[root@jenkins target]$docker push 192.168.112.69/mudao/ebei-mudao:20190428190020
The push refers to a repository [192.168.112.69/mudao/ebei-mudao]
506b28e05d9d: Pushed
0f9f466d3574: Pushed
e2ba34130aac: Pushed
952ea0986f6c: Mounted from mudao/ebei-admin
2d0c92e53222: Mounted from mudao/ebei-admin
129b697f70e9: Mounted from mudao/ebei-admin
20190428190020: digest: sha256:25789d14f7be659c1c21bd4c48a853e147dd5be18b184133a41873526e048cb5 size: 1574
2
3
4
5
6
7
8
9
然后就可以来到 rancher 当中进行应用的部署了,因为 rancher 集成了很友好的 UI 界面,所以常规应用部署直接在 UI 中操作就可以了。
进入到集群中,在工作负载当中点击部署应用,按照下图内容进行配置:
- 1,定义将要部署的应用名称,这里最好与上边脚本中
$project
的值相等,以便于脚本的上下文调用。 - 2,填入刚刚生成的镜像地址。
- 3,选择应用所属的命名空间,第一次可以新建一个。
- 4,填入容器当中应用的端口。
- 5,填入将要映射出来的端口,这个地方建议合理规划与使用。
- 6,通过端口检查来做健康检查,根据应用初始化情况合理设置后边的时间。
- 7,在
添加卷
中选择使用现有的持久卷
,卷名自定义。 - 8,下拉选择一开始准备环境时添加的持久卷。
- 9,根据自己的需求挂载容器目录,我这里是把应用的日志目录挂载了出来。
- 10,定义挂载在持久卷中的目录名称。
接着点击创建,即完成了应用的部署。
部署完成之后,也可以访问一下,点击应用名称下边的端口,即可直接跳转访问。
这样,也就完成了一个应用的部署,剩下的事情,就是将刚刚遗留的一些东西放入到 Jenkins 脚本当中即可。
等等,在进行后边的事情之前,先来看下日志的情况,首先在 rancher 当中可以直接查看。
接着再去我们一开始配置的存储类对应的节点上看看日志是什么状况。
[root@work-2 ebei-mudao]$ pwd
/data/pvc-3a632cf3-698c-11e9-a71b-0050568fa4d0/ebei-mudao
[root@work-2 ebei-mudao]$ ls
api.log error.log root.log
2
3
4
可以看到日志也如一开始预期的出现了,其中pvc-3a632cf3-698c-11e9-a71b-0050568fa4d0
是上边创建的持久卷的名称,ebei-mudao
则是刚刚部署应用时定义的。
# 3,完善脚本,一键部署。
因为上边的脚本已经完成了大部分工作,剩下的无非就是补充一下推送镜像的代码以及部署的代码。
整理之后的代码完整内容如下:
#!/bin/bash
source /etc/profile
#
##set color##
echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }
##set color##
#
project="ebei-mudao"
version=`date +%Y%m%d%H%M%S`
echo -------------------------------------
# 进入项目target目录
cd $WORKSPACE/$project-server/target/ && mv $project-server-1.0.jar app.jar
# 创建docker镜像
cat > run.sh << EOF
#!/bin/bash
source /etc/profile
/opt/app.jar run
EOF
cat > app.conf << EOF
MODE=service
APP_NAME=$project-server
EOF
chmod +x run.sh app.jar
cat >Dockerfile << EOF
FROM 192.168.112.69/public/jdk:1.8
MAINTAINER eryajf <liqilong@edspay.com>
ENV LANG en_US.UTF-8
ADD app.jar /opt
ADD run.sh /
ADD app.conf /opt
EXPOSE 8004
ENTRYPOINT [ "sh", "-c", "/run.sh" ]
EOF
# 编译镜像
echoGreen "开始构建当次镜像!"
docker build -t 192.168.112.69/mudao/$project:$version .
# 上传到docker私服
echoGreen "开始将镜像push到私服!"
docker push 192.168.112.69/mudao/$project:$version
[ $? != 0 ] && echoRed "请注意,在执行push上传时出错,故而退出!" && exit 1
docker rmi 192.168.112.69/mudao/$project:$version
#更新镜像
echoGreen "开始将最新镜像部署到远端!"
rancher kubectl set image deployment/$project $project=192.168.112.69/mudao/$project:$version -n mudao
[ $? != 0 ] && echoRed "请注意,在执行镜像更新时出错,故而退出!" && exit 1
echoGreen "部署完成!"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
简单清晰,放入 Jenkins,然后再次点击一下构建,看看是否能够将新的构建内容部署到 rancher 去。
点击 Jenkins 构建日志看到流程是顺利的。
然后来到 rancher 这边,看到新的应用已经开始部署了。
由于之前配置的策略是滚动: 先启动新Pod,再停止旧Pod
,所以整个部署过程是不会影响到业务的正常访问的。
另一方面,因为整个全局都有在考虑着规范化的问题,所以这样一个应用配置流程走完之后,以后再新增应用的时候,直接 Jenkins 复制 Job,仅需要更改一些代码地址,$project
的变量内容,然后 rancher 上复制应用,对应更改一些地方,一个新的应用就这么上线了,算起来,应该不会超过五分钟的吧,与传统方式对比起来,优势立马就显出来了。
这就是几个零散的工具之间联动的整个流程,特此记录。
突然想感慨一下,有的人稍有成就,便不再努力,混吃等死,堕入深渊,有的人则永不休止,不断精进,最终走向人生巅峰。忽然感觉到,成功的路上,的确不太拥挤。