CI/CD

CI/CD包含这几个含义:

  • CI 持续集成(Continuous Integration)
  • CD 持续交付(Continuous Delivery)
  • CD 持续交付(Continuous Delivery)

整个过程可以简单的如下图所示。当程序发生变更时,开发者只需要推送代码到git仓库,后续编译构建,部署到生产服务器的一系列动作全交给CI/CD这个自动化流程来完成。听起来是不是很爽。
在这里插入图片描述

准备

话不多说,如下,我将介绍如何使用Gitlab + jenkins + Docker来实现CI/CD。

我使用了三台服务器:

  • 一台是百度云的服务器,下面演示的时候,我会遮蔽其IP地址,用A.A.A.A来表示其IP地址。配置:2h 4g。用来部署gitlab。需要注意的是,在容器中运行gitlab,服务器的运行内存最好是2g以上,官方给的建议也是2g,如果小于2g,整个服务器的内存会被gitlab给占满,连xshell也无法登录连接。

  • 一台是阿里云的服务器,下面演示的时候,我会遮蔽其IP地址,用B.B.B.B来表示其IP地址。配置:2h 2g。用来部署jenkins,jenkins不是很占运行内存,2h 2g也足够了。

  • 一台是ucloud的服务器,下面演示的时候,我会遮蔽其IP地址,用C.C.C.C来表示其IP地址。配置:2h 2g。用来部署程序。

服务器操作系统全是Centos 8。我使用xshell连接各台服务器。百度云的那台服务器,我使用了其8080端口,阿里云的那台服务器,我使用了8888端口,ucloud那台服务器,我使用了8090端口。因此还要开启对应端口的防火墙,不然无法访问 !!!

如果是首次购买服务器,价格都还挺便宜的,所以每家厂商都买了些。

演示用的程序是一个go程序,相当于是一个http server。当在浏览器端发起 http:\\服务器ip:8090\hello 请求时,浏览器界面会返回一个hello

代码如下:

package main

import (
	"fmt"
	"net/http"
)

func hello(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "hello\n")
}

func headers(w http.ResponseWriter, req *http.Request) {
	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
}

func main() {
	http.HandleFunc("/hello", hello)
	http.HandleFunc("/headers", headers)
	http.ListenAndServe(":8090", nil)
}

整个工程的结构如下:
在这里插入图片描述
详细请参见gitee仓库:Gitee代码仓库地址

安装Gitlab并进行相应配置

我在百度云的服务器上运行Gitlab的Docker镜像,百度云服务器公网IP地址用A.A.A.A来表示。

首先是在服务器上安装Docker,至于安装的步骤可以参考我的另一篇文章:初识Docker

1. 下载并运行Gitlab镜像

docker run -d \
--hostname localhost \
-p 8080:80 -p 2222:22 \
--name gitlab \
--restart always \
--volume /tmp/gitlab/config:/etc/gitlab \
--volume /tmp/gitlab/logs:/var/log/gitlab \
--volume /tmp/gitlab/data:/var/opt/gitlab \
gitlab/gitlab-ce:13.3.8-ce.0

2. 登录gitlab

当gitlab镜像成功运行起来以后,可以使用docker ps命令进行查看,确认已经成功运行了就可以开始访问了。

在这里插入图片描述
由于我用的是百度云的那台服务器来部署gitlab,所以ip地址也就是我那台百度云服务器的公网ip地址。

第一次登陆,GitLab 会要求我们设置管理员密码,我们输入管理员密码后点击确认即可,之后 GitLab 会自动跳转到登录页面。默认的管理员用户名:admin@example.com,密码为我们第一次登录时设置的密码。输入用户名和用户密码,点击登录即可登录到系统中
在这里插入图片描述

3. 配置SSH

在百度云的那台服务器上执行如下命令生成SSH的公私玥。email@example.com可以替换为自己的邮箱

ssh-keygen -o -t rsa -b 2048 -C "email@example.com"

执行成功以后,会在当前路径下生成一个 .ssh 文件夹,里面有自己的公私玥。我是以 root 用户登录的服务器,生成的 .ssh 文件夹则会放在 /root/ 这个目录下。
在这里插入图片描述
进入 .ssh 这个文件夹,复制 id_rsa.pub 这个文件中的内容,也就是图中的那一大段内容。如果不了解公私玥这个概念,可以去了解一下非对称加密
在这里插入图片描述
SSH keys 中粘贴刚才复制的公钥。
在这里插入图片描述
为了避免有时候出现使用SSH clone代码时出现没有权限的提示,还需要进行如下配置:

  • 步骤1:编辑 /etc/gitlab/gitlab.rb 文件

进入gitlab容器。

[root@baidu-host ~]# docker ps
CONTAINER ID   IMAGE                          COMMAND             CREATED        STATUS                  PORTS                                                 NAMES
4465da3e97e8   gitlab/gitlab-ce:13.3.8-ce.0   "/assets/wrapper"   41 hours ago   Up 41 hours (healthy)   443/tcp, 0.0.0.0:2222->22/tcp, 0.0.0.0:8080->80/tcp   gitlab
[root@baidu-host ~]# docker exec -it gitlab /bin/bash
root@localhost:/# vim /etc/gitlab/gitlab.rb

/etc/gitlab/gitlab.rb 文件中输入如下内容:

A.A.A.A 对应我的百度云服务器的ip地址

gitlab_rails['gitlab_shell_ssh_port'] = 2222
external_url 'http://A.A.A.A'

在这里插入图片描述

  • 步骤2:编辑*/etc/gitlab/gitlab.rb*文件
root@localhost:/# vim /opt/gitlab/embedded/service/gitlab-rails/config/gitlab.yml

查看配置文件中的host名字是否为在运行docker时配置的主机名,如果不是则进行修改。
在这里插入图片描述
修改ssh_port为2222
在这里插入图片描述

  • 步骤三:在容器内部进行重启
root@localhost:/# cd /bin/
root@localhost:/# gitlab-ctl restart

然后刷新下浏览器就可以了。

4. 创建一个工程

在这里插入图片描述

5. 推送代码到gitlab仓库

在百度云的那台服务器上新建了一个文件夹,用来存放代码。编写的代码就放里面。

先clone gitlab这个工程中的代码,然后将我提供的gitee仓库中的代码复制过来放在这个文件夹中,然后pull到gitlab仓库中。
在这里插入图片描述
推送成功以后gitlab的仓库中就有了如下内容。
在这里插入图片描述

安装Jenkis并进行相应配置

Jenkins我运行在了阿里云的服务器上,其IP地址用B.B.B.B来表示。同样也要在这个服务器上安装Docker。

1. 下载Jenkins镜像并运行

docker run -d --name=jenkins \
-p 8888:8080 \
-u root \
--restart always \ n
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-v /tmp/jenkins_home:/var/jenkins_home \
jenkins/jenkins:lts

2. 访问Jekins

访问的IP地址:http://服务器ip地址:8888/ 我的Jenkins是部署在阿里云服务器上,所以这里填上阿里云服务器的ip地址。

第一次登录时需要需要输入密钥。在运行jenkins镜像时,将 /tmp/jenkins_home 映射到了Jenkins的这个路径 /var/jenkins_home。所以在阿里云的服务器上应该时这样进行访问 :
cat /var/jenkins_home/secrets/initialAdminPassword
然后将该文件中的密码复制到到管理员密码中。

在这里插入图片描述
选择安装推荐的插件
在这里插入图片描述
等所有组件初始完
在这里插入图片描述
创建管理员
在这里插入图片描述
在系统管理 -> 插件管理 -> 可选插件处,搜索 GitLab 和 Docker ,分别安装相关插件。

  • 安装gitlab相关插件
    在这里插入图片描述
  • 安装docker相关插件
    在这里插入图片描述
  • 安装SSH相关插件
    在这里插入图片描述

3. 创建Jenkins任务

在新建任务这一栏选择 构建一个自由风格的软件项目
在这里插入图片描述

4. 配置工程

在这里插入图片描述

配置源码管理

向我下面这样输入以后,一开始可能会有红色的提示。
比如下面这样的红色提示,如图1。当配置好以后,就像图2一样是没有任何错误的提示的。

图1 :
在这里插入图片描述
图2
在这里插入图片描述
选择添加
在这里插入图片描述
然后如下图所示。
在这里插入图片描述
在这里插入图片描述

配置构建触发器

当我们往gitlab 仓库中推送代码时,Jenkin能自动根据gitlab中代码的版本变化自动重新构建,靠的就是这个构建触发器。

在这里插入图片描述
生成token
在这里插入图片描述
复制这段token

回到gitlab,在hello工程的设置中选择 Webhooks
在这里插入图片描述
在URL这一栏填上Jenkins任务的URL,在配置构建触发器的第一张图片中就有显示。Secret Token填上刚才点击Generate生成的Token。然后点击 Add webhook 保存
在这里插入图片描述

配置Shell脚本

在Shell脚本中用来指定我们的应用究竟该怎么构建。

由于需要将构建后生成的镜像推送到镜像仓库,然后用来部署应用的服务器会从该镜像仓库中pull镜像并运行。所以需要先在doccker hub中创建一个仓库,没有Docker hub账号的可以自己先创建一个,然后记住自己的用户名和用户密码,下面需要在shell脚本中写入。
在这里插入图片描述

在这里插入图片描述
然后在里面输入shell。
在这里插入图片描述
shell脚本:

# 需要推送的镜像名称
IMAGE_NAME="zylsimon/devops-demo" 

# 获取当前构建的版本号
GIT_VERSION=`git describe --always --tag`

# 生成完整的镜像 URL 变量,用于构建和推送镜像
REPOSITORY=docker.io/${IMAGE_NAME}:${GIT_VERSION} 

# 构建Docker镜像 
docker build -t $REPOSITORY -f Dockerfile . 

# 登录镜像仓库,username 跟 password 为目标镜像仓库的用户名和密码
docker login --username=用户名 --password=用户密码 docker.io

# 推送 Docker 镜像到目标镜像仓库
docker push $REPOSITORY 

# 将部署所需要的指令写入当前路径下./shell/release文件中
rm -rf ./shell
mkdir -p ./shell 
echo "docker login --username=用户名 --password=用户密码" >> ./shell/release
echo "docker pull $REPOSITORY" >> ./shell/release
echo "docker kill hello" >> ./shell/release
echo "docker rm -f hello" >> ./shell/release
echo "docker run --rm --name=hello -p 8090:8090 -d $REPOSITORY" >> ./shell/release
配置自动部署

当jenkins为我们完成了自动构建,并将构建好的镜像推送到我们的Docker Hub之后,我们还需要它为我们完成自动部署的功能。

当时安装的 Publish Over SSH ,就和我们的自动部署有关。

在jenkins的系统配置中,配置一台服务器,构建好的程序将要部署在这台服务器上。
在这里插入图片描述

在Publish over SSH这个模块进行配置,还记得我一开始就交代了吗,我用了三台服务器,一台百度云的服务器用来部署gitlab,一台阿里云的服务器用来部署jenkins,一台ucloud的服务器用来部署应用程序。
在这里插入图片描述
配置好以后点击保存。

回到我们hello工程的配置。
选择 Send files or execute commands over SSH
在这里插入图片描述
进行如下配置
在这里插入图片描述
到此,所有的配置已经结束。

测试

首先,在ucloud服务中运行了一个容器,这个容器是基于上述的go程序构建以后发布到docker hub仓库中的,就当作这个是程序的旧的版本,然后我们需要做出更新,用新版本替换掉这个旧的版本。
在这里插入图片描述
然后访问,此时输入的IP地址为ucloud服务器的ip地址,端口号为8090,需要注意首先要开启该端口对应的防火墙,不然无法访问。
在这里插入图片描述
我的代码是放在百度云的服务器中的,查看一下此时的版本号,与docker中 zylsimon/devops-demo 镜像的 tag 号保持一致。
在这里插入图片描述
编辑main.go,做一点改动,然后重新推送到gitlab代码仓库。
在这里插入图片描述

[root@baidu-host hello]# git add . && git commit -m "修改main.go v8" && git push -u origin master
[master 719bbcc] 修改main.go v8
 1 file changed, 1 insertion(+), 1 deletion(-)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 297 bytes | 297.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
To ssh://localhost:2222/root/hello.git
   540656b..719bbcc  master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
[root@baidu-host hello]# 

然后查看jenkins的工程,发现已经开始构建了。
在这里插入图片描述
出现蓝色的小球表示构建成功。
在这里插入图片描述
在ucloud上查看,发现运行中的容器的已经发生改变了,原来的容器是基于zylsimon/devops-demo:540656b这个镜像的,现在运行的容器是基于 zylsimon/devops-demo:719bbcc 这个镜像的,719bbcc 对应着git托管程序的版本号。

ucloud:
在这里插入图片描述
百度云服务器:
在这里插入图片描述
再次访问时,发现网页内容已经发生了变化。访问的是ucloud对应的ip地址。
在这里插入图片描述
到此,便大功告成了,虽然配置Gitlab,配置jenkins时都还有些复杂,但是当配置好以后,作为一名开发者只需要往git中推送代码,剩下的步骤,包括构建,部署全部交给jenkins来完成,是不是让人感觉一阵清爽,这便是CI/CD的魅力所在。

参考

CI/CD:容器化后如何实现持续集成与交付? 郭少

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐