Jenkins+Gitlab+Docker联动
Jenkins 流水线 (Pipeline) 是一套插件,它支持实现和集成 continuous delivery pipelines 到Jenkins。
流水线提供了一组可扩展的工具,通过 Pipeline domain-specific language (DSL) syntax. 对从简单到复杂的交付流水线 “作为代码” 进行建模。
对Jenkins 流水线的定义被写在一个文本文件中(成为Jenkinsfile),该文件可以被提交到项目的源代码的控制仓库。这是”流水线即代码”的基础; 将CD 流水线作为应用程序的一部分,像其他代码一样进行版本化和审查。 创建 Jenkinsfile
并提交它到源代码控制中提供了一些即时的好处:
- 自动地为所有分支创建流水线构建过程并拉取请求;
- 在流水线上代码复查/迭代 (以及剩余的源代码);
- 对流水线进行审计跟踪;
- 该流水线的真正的源代码, 可以被项目的多个成员查看和编辑。
定义流水线的语法, 无论是在 web UI 还是在 Jenkinsfile 中都是相同的, 通常认为在Jenkinsfile
中定义并检查源代码控制是最佳实践。
下面的流程图是一个 CD 场景的示例,在Jenkins中很容易对该场景进行建模:
一. Pipeline语法
流水线是用户定义的一个CD流水线模型。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段
流水线的语法有两种:
- 声明式
- 脚本化
1.1 声明式流水线基础
在声明式流水线语法中, pipeline 块定义了整个流水线中完成的所有的工作。
- 在任何可用的代理上,执行流水线或它的任何阶段。
- 定义 “Build” 阶段。
- 执行与 “Build” 阶段相关的步骤。
- 定义”Test” 阶段。
- 执行与”Test” 阶段相关的步骤。
- 定义 “Deploy” 阶段。
- 执行与 “Deploy” 阶段相关的步骤。
1.2 脚本化流水线基础
在脚本化流水线语法中, 一个或多个 node 块在整个流水线中执行核心工作。
- 在任何可用的代理上,执行流水线或它的任何阶段。
- 定义 “Build” 阶段。 stage 块在脚本化流水线语法中是可选的。 然而, 在脚本化流水线中实现 stage 块 ,可以清楚的显示Jenkins UI中的每个 stage 的任务子集。
- 执行与 “Build” 阶段相关的步骤。
- 定义 “Test” 阶段。
- 执行与 “Test” 阶段相关的步骤。
- 定义 “Deploy” 阶段。
- 执行与 “Deploy” 阶段相关的步骤。
二. 实验案例
需求:
- Jenkins从gitlab仓库拉取代码及Jenkinsfile文件
- Jenkins通过代码中的Dockerfile构建docker镜像
- Jenkins将构建的docker镜像上传到私有docker仓库
- Jenkins控制部署主机从私有仓库拉取新创建的docker镜像,启动docker容器
实验环境
角色 | 主机地址 | 软件 |
---|---|---|
gitlab | 192.168.154.50:8080 | gitlab 12.8.1 |
jenkins | 192.168.154.60:8080 | jenkins 2.204.3 |
docker registry | 192.168.154.50:5000 | v2 |
deploy host | 192.168.154.50 | docker-ce 19.03.6 |
2.1 基本环境部署
- 关闭主机SElinux
- 配置静态IP
- 安装docker-ce环境
2.2 服务器部署
192.168.154.50 上使用docker安装gitlab
[root@git ~]# docker run -d -p 2222:22 -p 8080:80 -p 8443:443 \
> --volume /home/gitlab/config:/etc/gitlab \
> --volume /home/gitlab/logs:/var/log/gitlab \
> --volume /home/gitlab/data:/var/opt/gitlab \
> --restart always \
> --name gitlab \
> gitlab/gitlab-ce
192.168.154.50 上部署官方使用仓库registry
[root@git ~]# docker run -d -p 5000:5000 --restart always --privileged \
> -v /opt/registry:/var/lib/registry \
> --name registry-server registry:latest
192.168.154.50 上防护墙要放行相应端口
[root@git python-dev]# firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: ens32
sources:
services: dhcpv6-client ssh
ports: 8443/tcp 2222/tcp 8080/tcp 5000/tcp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
192.168.154.60 上使用docker安装Jenkins
``` [root@jenkins ~]# docker run -d -u root —restart always \-p 8080:8080 -p 50000:50000 \ -v jenkins-data:/var/jenkins_home \ -v /var/run/docker.sock:/var/run/docker.sock \ —privileged \ —name jenkins-server \ jenkinsci/blueocean:1.22.0
防火墙放行端口
[root@jenkins ~]# firewall-cmd —add-port=8080/tcp —permanent [root@jenkins ~]# firewall-cmd —add-port=50000/tcp —permanent [root@jenkins ~]# firewall-cmd —reload success
<a name="d10663bb"></a>
### 2.3 实施步骤
<a name="cdbfb610"></a>
#### 2.3.1 gitlab上创建项目
创建项目python-dev,属于development组,并建立develop分支。

开发人员将代码上传到仓库
**Pipeline的Jenkinsfile文件内容**: 这是关键
[root@git python-dev]# vim Jenkinsfile
node { stage(‘Build’) { checkout scm docker.withRegistry(‘http://192.168.154.50:5000‘) {
def customImage = docker.build("liyi888/lamp:latest", "./lamp")
customImage.push()
}
} stage(‘depoly’) { sh ‘’’ ssh root@192.168.154.50 ‘docker stop web | true’ ssh root@192.168.154.50 ‘docker rm web -f | true’ ssh root@192.168.154.50 ‘docker rmi 192.168.154.50:5000/liyi888/lamp:latest -f | true’ ssh root@192.168.154.50 ‘docker pull 192.168.154.50:5000/liyi888/lamp:latest | true’ ssh root@192.168.154.50 ‘docker run -itd —name web -p 32768:80 192.168.154.50:5000/liyi888/lamp:latest’ ‘’’ } }
lamp目录中存放Dockerfile文件等
[root@git python-dev]# tree -C lamp/ lamp/ ├── CentOS-Base.repo ├── Dockerfile ├── epel.repo ├── index.html └── run.sh
0 directories, 5 files
Dockerfile文件内容:
FROM centos:7.7.1908 MAINTAINER liyi888
RUN rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm RUN rpm -ivh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm —force
ADD CentOS-Base.repo /etc/yum.repos.d/ ADD epel.repo /etc/yum.repos.d/
RUN yum install -y httpd httpd-devel RUN yum install -y php70w php70w-mysql php70w-mbstring php70w-mcrypt php70w-gd php70w-imap RUN yum install -y php70w-ldap php70w-odbc php70w-pear php70w-xml php70w-xmlrpc php70w-pdo RUN sed -ri ‘s/#ServerName www.example.com:80/ServerName www.cloud.com/g’ /etc/httpd/conf/httpd.conf
ADD index.html /var/www/html/
ADD run.sh /run.sh RUN chmod 775 /run.sh
EXPOSE 80 CMD [“/run.sh”]
CentOS-Base.repo和epel.repo是两个YUM源文件
[root@git lamp]# cat CentOS-Base.repo [base] name=CentOS-$releasever - Base - mirrors.aliyun.com failovermethod=priority baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/ gpgcheck=1 gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
released updates
[updates] name=CentOS-$releasever - Updates - mirrors.aliyun.com failovermethod=priority baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/ gpgcheck=1 gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
additional packages that may be useful
[extras] name=CentOS-$releasever - Extras - mirrors.aliyun.com failovermethod=priority baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/ gpgcheck=1 gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
[root@git lamp]# cat epel.repo [epel] name=Extra Packages for Enterprise Linux 7 - $basearch baseurl=http://mirrors.aliyun.com/epel/7/$basearch failovermethod=priority enabled=1 gpgcheck=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
index.html是默认首页内容
[root@git lamp]# cat index.html
this is docker test!
run.sh是镜像默认启动脚本
[root@git lamp]# cat run.sh
!/bin/sh
/usr/sbin/httpd -D DFOREGROUND
/bin/bash
<a name="bb147ac8"></a>
#### 2.3.2 Jenkins上创建流水线
新建任务–> 选择多分支流水线–>确定<br />
<a name="b1d001aa"></a>
#### 2.3.3 配置python-dev流水线
配置分支源

配置构建配置及触发器

<a name="213467f8"></a>
#### 2.3.4 配置SSH 部署主机
首选在jenkins上通过`ssh-keygen`命令生成一对秘钥(我这里用的root用户)
然后将公钥通过ssh-copy-id将公钥拷贝到部署主机,务必能免密登录到192.168.154.50。
ssh-copy-id -i ./.ssh/id_rsa.pub root@192.168.154.50
添加全局凭证

添加SSH remote hosts

<a name="aafe5306"></a>
#### 2.3.5 配置私有仓库客户端
Jenkins主机和部署主机均要配置信任私有仓库
[root@jenkins ~]# cat /etc/docker/daemon.json { “registry-mirrors”: [“https://ariq8b1p.mirror.aliyuncs.com“], “insecure-registries”: [“192.168.154.50:5000”] }
<a name="7e410be6"></a>
#### 2.3.6 测试
- 更新仓库代码,比如更新index.html文件的内容;
- Jenkins在轮训间隔到期后,自会自动构建,并按照Jenkinsfile的流水线执行
[root@jenkins ~]# docker exec -it jenkins-server /bin/bash
bash-4.4# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.154.50:5000/liyi888/lamp latest 1c7459020de0 19 minutes ago 670MB
liyi888/lamp latest 1c7459020de0 19 minutes ago 670MB
192.168.154.50:5000/liyi888/lamp
- 部署主机上已经下载了刚构建的镜像
[root@git ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.154.50:5000/liyi888/lamp latest 1c7459020de0 21 minutes ago 670MB 192.168.154.50:5000/liyi888/lamp 8.0 6cd83ae41c41 8 hours ago 670MB gitlab/gitlab-ce latest 719e7e45b1e2 12 days ago 1.89GB 192.168.154.50:5000/registry latest 708bc6af7e5e 6 weeks ago 25.8MB registry latest 708bc6af7e5e 6 weeks ago 25.8MB centos 7.7.1908 08d05d1d5859 3 months ago 204MB
- 部署主机上也已经启动了容器
[root@git ~]# docker ps [root@git ~]# docker port web 80/tcp -> 0.0.0.0:32768
- 浏览器访问web容器<br />
<a name="546b61ec"></a>
#### 2.3.7 配置代码更新自动触发
上面的配置的触发器为间隔轮训,如果不想使用这种方式,就要配置webHOOK。
在gitlab上的仓库上配置即可,格式如下:
http://my-jenkins-host/git/notifyCommit?url=git@gitlab.example.com:group/repository.git&delay=0sec
my-jenkins-host:Jenkins主机地址及端口
git@gitlab.example.com:group/repository.git 这个是你Jenkins流水线上的仓库地址

<a name="d359672d"></a>
#### 2.3.8 更新代码自会自动触发构建
进入本地代码仓库
[root@git python-dev]# pwd /root/administrator-pro/python-dev [root@git python-dev]# ls jenkins Jenkinsfile lamp new.py README [root@git python-dev]# cd lamp/ [root@git lamp]# ls CentOS-Base.repo Dockerfile epel.repo index.html run.sh
修改index.html文件内容并提交到gitlab代码仓库
[root@git lamp]# cat index.html
this is docker test!
this is docker test!
this is docker test!
[root@git lamp]# cd .. [root@git python-dev]# git add . [root@git python-dev]# git commit -m ‘auto push’ [develop 38d9cc0] auto push 1 file changed, 2 insertions(+) [root@git python-dev]# git push origin develop Username for ‘http://192.168.154.50:8080‘: root Password for ‘http://root@192.168.154.50:8080‘: Counting objects: 7, done. Delta compression using up to 4 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 346 bytes | 0 bytes/s, done. Total 4 (delta 2), reused 0 (delta 0) remote: remote: To create a merge request for develop, visit: remote: http://192.168.154.50:8080/development/python-dev/-/merge_requests/new?merge_request%5Bsource_branch%5D=develop remote: To http://192.168.154.50:8080/development/python-dev.git 0fe433a..38d9cc0 develop -> develop [root@git python-dev]# ```Jenkins上的流水线python-dev会自动构建。