实现持续集成与交付主要分为五个步骤:

  1. 配置 GitLab SSH 访问公钥,使得我们可以直接通过 SSH 拉取或推送代码到 GitLab。
  2. 将代码通过 SSH 上传到 GitLab。
  3. 在 Jenkins 创建构建任务,使得 Jenkins 可以成功拉取 GitLab 的代码并进行构建。
  4. 配置代码变更自动构建流程,使得代码变更可以触发自动构建 Docker 镜像。
  5. 配置自动部署流程,使得镜像构建完成后自动将镜像发布到测试或生产环境。
一、配置 GitLab SSH 访问公钥,上传代码至Gitlab

在gitlab中创建工程hello-jenkins
创建工程hello-jenkins
为了能够从gitlab上传/下载代码,我们需要先生成 ssh 密钥。我们可以本地使用 ssh-keygen 命令来生成 2048 位的 ras 密钥。如下命令:

ssh-keygen -o -t rsa -b 2048 -C "email@example.com" #邮箱替换为自己的邮箱

按三次回车,使用默认的公钥/秘钥保存路径,以及不设置秘钥密码
执行完上述命令后 ,$HOME/.ssh/ 目录下会自动生成两个文件:id_rsa.pub 文件为公钥文件,id_rsa 文件为私钥文件
我们可以通过 cat 命令来查看公钥文件内容:

cat $HOME/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADASDBAAABAQClnVao+34t6CEWawIpYZQK6NmMcNDZGUYG0Op3B2abkqQpC5X8QKaFs5Jksw2KXc3D80FUHrDb6Nk3c/0Ueqcz30aCIzfUJ3Wi7MSlhaJtfrNC4T80ze5HyqP+ut60j05OaSJf34ew0XZ4WUNJGqu1NQczbX4FXLq/Hwc/vueVYSXMt3ZCq4AKF2foLx/Qilxv6wk4uev7oiVTxxHASCthY83WL2WNjFUF4IqW5Fm+wpjxe3PccIjyi71S/S05b9wOP9dD87vPe18GaHqti3ittOc9x62ossyv0FJjd8VPn1M/N7TPfNVfrZmLVkilPNRj2m3NaZ9a9D/t1A/6U0// email@example.com

然后将公钥文件拷贝到 GitLab 的个人设置 -> SSH Keys 中,点击添加按钮,将我们的公钥添加到 GitLab 中

二、将代码通过 SSH 上传到 GitLab

在本地创建一个名为hello-jenkins的文件夹
创建如下四个文件

  1. main.go(不熟悉go语言的可以试用其他项目代码代替)

    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(":9090", nil)
    }
    
  2. Dockerfile

    FROM golang:1.14 as builder
    WORKDIR /root/projects/jenkins/
    COPY main.go .
    RUN CGO_ENABLED=0 GOOS=linux go build -o ./http-server .
    FROM scratch
    WORKDIR /root/projects
    COPY --from=builder /root/projects/jenkins/http-server .
    CMD ["./http-server"]
    
  3. .gitignore(非必须,使用idea编辑项目会产生.idea文件夹)

    .idea/
    
  4. README.md(非必须)

    Docker+Gitlab+Jenkins CI/CD Demo.
    

执行以下命令将代码上传至Gitlab:

git init #创建本地git仓库
git add . #将工作区代码存到暂存区
git commit -m 'Init hello-jenkins' #将代码提交到本地仓库
git add remote origin git@ip:xxx.git #与远程仓库关联
git push --set-upstream origin master #将代码推送到远程仓库
三、在 Jenkins 创建构建任务
  • 同时,参照步骤二在jenkins服务器生成公钥和私钥

在 Jenkins 中添加一个自由风格的任务
创建jenkins任务
源码管理选择 Git,填写 GitLab 项目的 URL,Jenkins 会提示没有访问 GitLab 的相关权限,点击添加按钮将jenkins服务器私钥添加到 Jenkins 中
添加凭证
选择添加的密钥类型为 “SSH Username with private key”,Username 设置为 jenkins,然后将jenkins服务器私钥粘贴到 Private Key 输入框中,点击添加即可
设置jenkins凭证
同时需要把jenkins服务器公钥添加到gitlab SSH KEYS配置中
返回页面中选择刚刚添加的jenkins凭证
选择凭证
下面我们使用 shell 脚本来构建我们的应用镜像,在构建中增加一个 Shell 类型的构建步骤
在构建中添加执行shell
填入以下信息:

# 第一步,登录镜像仓库,将 USER 替换为目标镜像仓库的用户名,将 PASSWORD 替换为镜像仓库的密码
docker login -u {USER} -p {PASSWORD}
# 第二步,使用 docker build 命令构建镜像(我这里镜像名为ntherd-docker/devops-demo)
docker build -t {USER}/devops-demo .
# 第三步, 使用 docker push 命令推送镜像
docker push {USER}/devops-demo

完成后点击保存,此时任务已经成功添加到 Jenkins 中。回到任务首页,点击构建按钮即可开始构建。第一次构建需要下载依赖的基础镜像,这个过程可能比较慢。构建过程中,我们也可以点击控制台输出查看构建输出的内容。

四、配置代码变更自动构建流程

点击上一步创建的任务,点击配置进入任务配置界面,到构建触发器下勾选 GitLab 相关的选项(如果没有此选项,检查一下是否安装了gitlab相关插件),点击 Generate 按钮生成一个 GitLab 回调 Jenkins 的 token。记录下 Jenkins 的回调地址和生成的 token 信息。
生成token

在 GitLab 项目设置中,选择 Webhooks,将 Jenkins 的回调地址和 token 信息添加到 Webhooks 的配置中,点击添加即可
Webhooks
后面我们的每次提交都会触发自动构建。
为了实现根据 git 的 tag 自动构建相应版本的镜像,我们需要修改 Jenkins 构建步骤中的 shell 脚本为以下内容:

# 需要推送的镜像名称
IMAGE_NAME="{USER}/devops-demo" 
# 获取当前构建的版本号
TAG=`git describe --always --tag`
# 生成完整的镜像 URL 变量,用于构建和推送镜像
REPOSITORY=docker.io/${IMAGE_NAME}:${TAG} 
# 构建Docker镜像 
docker build -t $REPOSITORY -f Dockerfile . 
# 登录镜像仓库,username 跟 password 为目标镜像仓库的用户名和密码
docker login --username={USER} --password={PASSWORD} docker.io
# 推送 Docker 镜像到目标镜像仓库
docker push $REPOSITORY

到此,我们已经完成了 GitLab -> Jenkins -> Docker 镜像仓库的自动构建和推送。当我们推送代码到 GitLab 中时,会自动触发 Webhooks,然后 GitLab 会根据配置的 Webhooks 调用 Jenkins 开始构建镜像,镜像构建完成后自动将镜像上传到我们的镜像仓库。

五、配置自动部署流程

镜像构建完成后,我们还需要将镜像发布到测试或生产环境中将镜像运行起来。发布到环境的过程可以设置为自动发布,每当我们推送代码到 master 中时,即开始自动构建镜像,并将构建后的镜像发布到测试环境中。

在镜像构建过程中,实际上 Jenkins 是通过执行我们编写的 shell 脚本完成的,要想实现镜像构建完成后自动在远程服务器上运行最新的镜像,我们需要借助一个 Jenkins 插件 Publish Over SSH,这个插件可以帮助我们自动登录远程服务器,并执行一段脚本将我们的服务启动。

下面我们来实际操作下这个插件。
第一步,在 Jenkins 中安装 Publish Over SSH 插件。 在 Jenkins 系统管理,插件管理中,搜索 Publish Over SSH,然后点击安装并重启 Jenkins 服务。
OverSSH
第二步,配置 Publish Over SSH 插件。 插件安装完成后,在 Jenkins 系统管理的系统配置下,找到 Publish Over SSH 功能模块,添加远程服务器节点,这里我使用密码验证的方式添加一台服务器。配置好后,我们可以使用测试按钮测试服务器是否可以正常连接,显示Success 代表服务器可以正常连接,测试连接成功后,点击保存按钮保存配置。
Publish over SSH

第三步,修改之前 shell 任务中脚本, 添加部署相关的内容:

# 需要推送的镜像名称
IMAGE_NAME="{USER}/devops-demo" 
# 获取当前构建的版本号
TAG=`git describe --always --tag`
# 生成完整的镜像 URL 变量,用于构建和推送镜像
REPOSITORY=docker.io/${IMAGE_NAME}:${TAG} 
# 构建Docker镜像 
docker build -t $REPOSITORY -f Dockerfile . 
# 登录镜像仓库,username 跟 password 为目标镜像仓库的用户名和密码
docker login --username={USER} --password={PASSWORD} docker.io
# 推送 Docker 镜像到目标镜像仓库
docker push $REPOSITORY
mkdir -p ./shell && echo \
"docker login --username={USER} --password={PASSWORD} \n" \
"docker pull $REPOSITORY \n" \
"docker kill hello-jenkins \n" \
"docker run --rm --name=hello-jenkins -p 8090:8090 -d $REPOSITORY" >> ./shell/release

我们在 docker push 命令后,增加一个输出 shell 脚本到 release 文件的命令,这个脚本会发送到远端的服务器上并执行,通过执行这个脚本文件可以在远端服务器上,拉取最新镜像并且重新启动容器。

第四步,配置远程执行。在 Jenkins 的 hello-jenkins 项目中,点击配置,在构建中增加构建步骤,点击添加Send files or execute commands over SSH的步骤,选择之前添加的服务器,并且按照以下内容填写相关信息:
Send files or execute commands over SSH
添加构建步骤详情

  • Source file 就是我们要传递的 shell 脚本信息,这里填写我们上面生成的 shell 脚本文件即可。
  • Remove prefix 是需要过滤的目录,这里我们填写 shell。
  • Remote directory 为远程执行脚本的目录。

最后点击保存,配置完成后,我们就完成了推送代码到 GitLab,Jenkins 自动构建镜像,之后推送镜像到镜像仓库,最后自动在远程服务器上拉取并重新部署容器。

如果你是生产环境中使用的 Kubernetes 管理服务,可以在 Jenkins 中安装 Kubernetes 的插件,然后构建完成后直接发布镜像到 Kubernetes 集群中。

Logo

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

更多推荐