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 块定义了整个流水线中完成的所有的工作。

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

1.2 脚本化流水线基础

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

  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
[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

2.3 实施步骤

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 
<h1>this is docker test!</h1>

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

[root@git lamp]# cat run.sh 
#!/bin/sh
/usr/sbin/httpd -D DFOREGROUND  
/bin/bash

2.3.2 Jenkins上创建流水线

新建任务–> 选择多分支流水线–>确定

2.3.3 配置python-dev流水线

配置分支源

配置构建配置及触发器

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

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"]
}

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   <none>              3c7a9de58917        22 minutes ago      670MB
192.168.154.50:5000/liyi888/lamp   <none>              cc79ccb4392b        About an hour ago   670MB
192.168.154.50:5000/liyi888/lamp   <none>              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
  • 部署主机上已经下载了刚构建的镜像
[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容器

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流水线上的仓库地址

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 
<h1>this is docker test!</h1>
<h1>this is docker test!</h1>
<h1>this is docker test!</h1>
[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会自动构建。

[[6.Docker基础]] [[1. Git分布式版本控制]] [[3. Jenkins持续集成]]