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中很容易对该场景进行建模:

4. Jenkins Gitlab Docker联动 - 图1

一. Pipeline语法

流水线是用户定义的一个CD流水线模型。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段

流水线的语法有两种:

  • 声明式
  • 脚本化

1.1 声明式流水线基础

在声明式流水线语法中, pipeline 块定义了整个流水线中完成的所有的工作。

4. Jenkins Gitlab Docker联动 - 图2

  1. 在任何可用的代理上,执行流水线或它的任何阶段。
  2. 定义 “Build” 阶段。
  3. 执行与 “Build” 阶段相关的步骤。
  4. 定义”Test” 阶段。
  5. 执行与”Test” 阶段相关的步骤。
  6. 定义 “Deploy” 阶段。
  7. 执行与 “Deploy” 阶段相关的步骤。

1.2 脚本化流水线基础

在脚本化流水线语法中, 一个或多个 node 块在整个流水线中执行核心工作。

4. Jenkins Gitlab Docker联动 - 图3

  1. 在任何可用的代理上,执行流水线或它的任何阶段。
  2. 定义 “Build” 阶段。 stage 块在脚本化流水线语法中是可选的。 然而, 在脚本化流水线中实现 stage 块 ,可以清楚的显示Jenkins UI中的每个 stage 的任务子集。
  3. 执行与 “Build” 阶段相关的步骤。
  4. 定义 “Test” 阶段。
  5. 执行与 “Test” 阶段相关的步骤。
  6. 定义 “Deploy” 阶段。
  7. 执行与 “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

    1. [root@git ~]# docker run -d -p 2222:22 -p 8080:80 -p 8443:443 \
    2. > --volume /home/gitlab/config:/etc/gitlab \
    3. > --volume /home/gitlab/logs:/var/log/gitlab \
    4. > --volume /home/gitlab/data:/var/opt/gitlab \
    5. > --restart always \
    6. > --name gitlab \
    7. > gitlab/gitlab-ce
  • 192.168.154.50 上部署官方使用仓库registry

    1. [root@git ~]# docker run -d -p 5000:5000 --restart always --privileged \
    2. > -v /opt/registry:/var/lib/registry \
    3. > --name registry-server registry:latest
  • 192.168.154.50 上防护墙要放行相应端口

    1. [root@git python-dev]# firewall-cmd --list-all
    2. public (active)
    3. target: default
    4. icmp-block-inversion: no
    5. interfaces: ens32
    6. sources:
    7. services: dhcpv6-client ssh
    8. ports: 8443/tcp 2222/tcp 8080/tcp 5000/tcp
    9. protocols:
    10. masquerade: no
    11. forward-ports:
    12. source-ports:
    13. icmp-blocks:
    14. 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

  1. <a name="d10663bb"></a>
  2. ### 2.3 实施步骤
  3. <a name="cdbfb610"></a>
  4. #### 2.3.1 gitlab上创建项目
  5. 创建项目python-dev,属于development组,并建立develop分支。
  6. ![](https://s2.ax1x.com/2020/03/08/3vLWqJ.png#id=GplOh&originHeight=709&originWidth=1872&originalType=binary&ratio=1&status=done&style=none)
  7. 开发人员将代码上传到仓库
  8. **Pipeline的Jenkinsfile文件内容**: 这是关键

[root@git python-dev]# vim Jenkinsfile

node { stage(‘Build’) { checkout scm docker.withRegistry(‘http://192.168.154.50:5000‘) {

  1. def customImage = docker.build("liyi888/lamp:latest", "./lamp")
  2. customImage.push()
  3. }

} 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’ ‘’’ } }

  1. lamp目录中存放Dockerfile文件等

[root@git python-dev]# tree -C lamp/ lamp/ ├── CentOS-Base.repo ├── Dockerfile ├── epel.repo ├── index.html └── run.sh

0 directories, 5 files

  1. 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”]

  1. CentOS-Base.repoepel.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

  1. index.html是默认首页内容

[root@git lamp]# cat index.html

this is docker test!

  1. run.sh是镜像默认启动脚本

[root@git lamp]# cat run.sh

!/bin/sh

/usr/sbin/httpd -D DFOREGROUND
/bin/bash

  1. <a name="bb147ac8"></a>
  2. #### 2.3.2 Jenkins上创建流水线
  3. 新建任务–> 选择多分支流水线–>确定<br />![](https://s2.ax1x.com/2020/03/08/3vjOLF.png#id=OEqKw&originHeight=774&originWidth=1879&originalType=binary&ratio=1&status=done&style=none)
  4. <a name="b1d001aa"></a>
  5. #### 2.3.3 配置python-dev流水线
  6. 配置分支源
  7. ![](https://s2.ax1x.com/2020/03/08/3x3PpR.png#id=B8ged&originHeight=745&originWidth=1885&originalType=binary&ratio=1&status=done&style=none)
  8. 配置构建配置及触发器
  9. ![](https://s2.ax1x.com/2020/03/08/3x8CVS.png#id=C2NDZ&originHeight=599&originWidth=1780&originalType=binary&ratio=1&status=done&style=none)
  10. <a name="213467f8"></a>
  11. #### 2.3.4 配置SSH 部署主机
  12. 首选在jenkins上通过`ssh-keygen`命令生成一对秘钥(我这里用的root用户)
  13. 然后将公钥通过ssh-copy-id将公钥拷贝到部署主机,务必能免密登录到192.168.154.50。

ssh-copy-id -i ./.ssh/id_rsa.pub root@192.168.154.50

  1. 添加全局凭证
  2. ![](https://s2.ax1x.com/2020/03/08/3xtytS.png#id=EG9qz&originHeight=820&originWidth=1891&originalType=binary&ratio=1&status=done&style=none)
  3. 添加SSH remote hosts
  4. ![](https://s2.ax1x.com/2020/03/08/3xNGBq.png#id=mWS3v&originHeight=754&originWidth=1892&originalType=binary&ratio=1&status=done&style=none)
  5. <a name="aafe5306"></a>
  6. #### 2.3.5 配置私有仓库客户端
  7. Jenkins主机和部署主机均要配置信任私有仓库

[root@jenkins ~]# cat /etc/docker/daemon.json { “registry-mirrors”: [“https://ariq8b1p.mirror.aliyuncs.com“], “insecure-registries”: [“192.168.154.50:5000”] }

  1. <a name="7e410be6"></a>
  2. #### 2.3.6 测试
  3. - 更新仓库代码,比如更新index.html文件的内容;
  4. - 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 3c7a9de58917 22 minutes ago 670MB 192.168.154.50:5000/liyi888/lamp cc79ccb4392b About an hour ago 670MB 192.168.154.50:5000/liyi888/lamp 3566e3245712 5 hours ago 670MB nginx latest 6678c7c2e56c 3 days ago 127MB jenkinsci/blueocean latest cabaf2e16a90 7 days ago 561MB centos latest 470671670cac 7 weeks ago 237MB centos 7.7.1908 08d05d1d5859 3 months ago 204MB python 3.5.1 a00e9008965a 3 years ago 698MB

  1. - 部署主机上已经下载了刚构建的镜像

[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

  1. - 部署主机上也已经启动了容器

[root@git ~]# docker ps [root@git ~]# docker port web 80/tcp -> 0.0.0.0:32768

  1. - 浏览器访问web容器<br />![](https://s2.ax1x.com/2020/03/08/3xwpqA.png#id=xIpcx&originHeight=275&originWidth=952&originalType=binary&ratio=1&status=done&style=none)
  2. <a name="546b61ec"></a>
  3. #### 2.3.7 配置代码更新自动触发
  4. 上面的配置的触发器为间隔轮训,如果不想使用这种方式,就要配置webHOOK
  5. 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流水线上的仓库地址

  1. ![](https://s2.ax1x.com/2020/03/08/3x0B0s.png#id=Q03hN&originHeight=823&originWidth=1882&originalType=binary&ratio=1&status=done&style=none)
  2. <a name="d359672d"></a>
  3. #### 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会自动构建。