使用Docker+Jenkins实现Go语言项目的持续集成

这篇文章将介绍如何使用 Docker+Jenkins 实现 Go 语言项目的持续集成。

首先讲一下大致的实现思路:

推送代码至Git服务器 => 触发Jenkins服务器配置的Git Web Hooks => 从Git服务器中pull或clone代码 => 将代码编译成二进制可执行文件 => 构建docker镜像 => 上传docker镜像至镜像仓库 => 从Jenkins服务器进入远程应用服务器 => 从docker镜像仓库中拉取镜像 => 停止并删除该项目正在运行的docker容器 => 使用该新镜像构建并启动docker容器 => 删除其他旧版本镜像 => 完成

然后讲一下实践过程中用到的一些技术点:

  • Docker

    使用 Docker 的主要原因主要有,应用移植方便,并且可有效解决同一应用在不同服务器上部署带来的环境问题影响。

  • Docker Compose

    docker-compose 也是由 Docker 提供的一个命令行工具,这里主要用于简化 Jenkins 服务器上对容器的操作,仅此而已,可直接使用 shell 脚本代替。

  • Jenkins

    Jenkins 是一个自动化服务器,也可以作为简单的 CI/CD 服务器。

  • Git

    Git 想必大家都不会陌生,这里同样使用它作为项目的代码管理仓库,并且利用它的 Web Hooks ,作为 Jenkins 任务构建的触发器。

  • 镜像仓库

    这里选择阿里云提供的容器服务作为我们的镜像仓库,可自行选择自己合适的镜像仓库。

在本文的最后,列出了实践过程中可能会出现的问题,并且提供了实践使用的 Go 项目代码仓库。

安装 Jenkins

启动 Jenkins 容器

  1. 拉取 Jenkins 镜像

    docker pull jenkins/jenkins:latest
    复制代码
  2. 编写 docker-compose.yml 文件

    version: "2"
    services:
    	jks:
    		image: jenkins/jenkins:latest
    		ports:
    			- 8080:8080
    			- 50000:50000
    		volumes:
    			- /data/jenkins:/var/jenkins_home
    			- /var/run/docker.sock:/var/run/docker.sock
    			- /bin/docker:/bin/docker
    		container_name: jks
    		user: root
    复制代码
  3. 创建用于挂载的 /data/jenkins 文件夹, 并修改该文件夹的拥有者为 ID=1000 的用户

    mkdir -p /data/jenkins
    chown -R 1000:1000 /data/jenkins
    复制代码
  4. 通过 docker-compose 启动 jenkins 容器

    docker-compose -f /data/compose/docker-compose.yml up -d jks
    复制代码

安装 Jenkins 插件

  1. 在浏览器输入 http://IP:8080 进入 Jenkins 管理页面

  2. 通过命令 cat /data/jenkins/secrets/initialAdminPassword 获取初始密码,对 Jenkins 进行解锁,解锁后先跳过插件安装(无需担心漏装推荐的插件,在后续安装插件过程中,会自动安装解锁后推荐的所有插件)

  3. (可选)修改配置文件,并重启 Jenkins 容器,实现插件安装加速

    # 编辑jenkins配置文件
    vim /data/jenkins/updates/default.json
    
    # 执行ex命令, 替换所有插件下载URL
    :1,$s/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g
    
    # 执行ex命令, 替换连接测试URL
    :1,$s/http:\/\/www.google.com/https:\/\/www.baidu.com/g
    
    # 重启jenkins容器
    docker-compose -f /data/compose/docker-compose.yml restart jks
    复制代码
  4. 进入 Jenkins -> Plugin Manager 页面安装以下插件

    • Localization: Chinese (Simplified)
    • Publish Over SSH
    • Gitee
    • Go

配置 Jenkins

全局工具配置

进入 Jenkins -> 系统管理 -> 全局工具配置 页面,对 GitGo 进行相关配置

Gitee 配置

在已安装 Gitee 插件 的前提下,进入 Jenkins -> 系统管理 -> 系统配置 ,找到 Gitee 配置 ,对其进行配置,配置后内容大致如下:

配置 Publish over SSH

在已安装 Publish over SSH 插件 的前提下,进入 Jenkins -> 系统管理 -> 系统配置 ,找到 Publish over SSH 配置,如下图所示:

Passphrase:生成密钥时使用的加密口令,为空则表示无

Path to key:生成的私钥位置,与 Key 选项只需填其中一个

Key:生成的私钥内容,与 Path to key 选项只需填其中一个

Name:远程服务器备注名(自定义)

Hostname:远程服务器地址

Username:远程服务器用户名

Remote Directory:进入远程服务器后所在的位置

主要有两种配置方式,第一种是直接使用远程服务器的账号和密码,另外一种则是通过密钥的方式。

  • 账号密码方式

    使用账号密码方式无需配置公私钥相关的选项,直接对 SSH Server 内容进行配置,并点击 高级 按钮,勾选 Use password authentication, or use a different key 选项,并填写远程服务器用户对应的密码 Passphrase / Password ,完成后点击下方的 Test Configuration 按钮进行连接测试即可。

  • 密钥方式

    1. 进入 Jenkins 容器

      docker exec -it jks /bin/bash
      复制代码
    2. 生成密钥

      ssh-keygen -t rsa
      复制代码
    3. 将公钥复制到远程服务器

      ssh-copy-id -i ~/.ssh/id_rsa.pub 192.168.56.101
      复制代码
    4. 配置 Path to key 选项值为 /root/.ssh/id_rsa

    5. 配置 SSH Server

    6. 连接测试

构建任务

  1. 点击 Jenkins -> 新建任务 ,创建一个 Jenkins 任务

  2. General

    填写项目的 Gitee 链接 以及勾选 丢弃旧的构建

  3. 源码管理

    选择 Git 选项,填写 Repositories 信息,并创建 Gitee 账号密码凭据

  4. 构建触发器

    勾选 Gitee webhook 触发构建 ,根据需求选择 允许触发构建的分支 ,并在下方的 Gitee WebHook 密码 选项右边,点击 生成 按钮,将该触发器的 WebHook URLWebHook 密码 填写至该项目的 Gitee WebHooks管理 中。

  5. 构建环境

    在已安装 Go 插件 的前提下,勾选 Set up Go programming language tools 选项框,并在其下方填写项目使用到的 Go 版本号即可,如下图:

  6. 构建

    构建过程大致可以分为如下步骤:

    • 判断是否存在项目本地仓库
      • 存在:进入该本地仓库文件夹,通过 git pull 命令从 Git 远程仓库拉取最新代码
      • 不存在:直接使用 git clone 命令从 Git 远程仓库克隆项目,并进入该项目文件夹
    • 使用 go build 命令编译成二进制可执行文件
    • 执行事先写好的 docker-push 脚本,编译 docker镜像 并上传至 docker仓库
    if [ ! -d "/var/go-docker-demo" ];then
    	cd /var
        git clone https://hkail:xxxxxxxxx@gitee.com/hkail/go-docker-demo
        cd go-docker-demo
    else
    	cd /var/go-docker-demo
        git pull
    fi
    
    go build -o app
    
    chmod +x docker-push && ./docker-push
    复制代码

    Dockerfile 文件内容如下:

    FROM golang:1.14.2
    
    COPY app .
    COPY conf/conf.toml ./conf/
    
    ENTRYPOINT ["./app"]
    复制代码

    docker-push 脚本内容如下:

    # 容器名
    name=`cat version | awk '{print $1}'`
    # 容器标签
    tag=`cat version | awk '{print $2}'`
    # 仓库域名
    domain=registry-vpc.cn-shenzhen.aliyuncs.com
    # 仓库URL
    url=colehuang/coletest
    
    # 构建Docker镜像
    docker build -t $name:$tag .
    
    # 获取镜像ID
    id=`docker images | grep $name | grep $tag | awk '{ print $3 }'`
    
    # 镜像上传至Docker镜像仓库
    docker login --username=xxx --password=xxx $domain
    docker tag $id $domain/$url:$tag
    docker push $domain/$url:$tag
    复制代码

    version 文件内容如下:

    gdd 1.1.2
    复制代码
  7. 构建后操作

    构建后操作的过程大致可以分为如下步骤:

    • 将项目中的 versiondocker-pull 文件传送至远程服务器中
    • 进入在 Publish over SSH 中配置的远程服务器目录,并执行 docker-pull 脚本,从 docker镜像仓库 中拉取提交的新版本镜像,并使用该镜像构建 docker容器

    docker-pull 脚本内容如下:

    # 容器名
    name=`cat version | awk '{print $1}'`
    # 容器标签
    tag=`cat version | awk '{print $2}'`
    # 仓库域名
    domain=registry.cn-shenzhen.aliyuncs.com
    # 仓库URL
    url=colehuang/coletest
    
    # 从Docker镜像仓库中拉取镜像
    docker login --username=xxx --password=xxx $domain
    docker pull $domain/$url:$tag
    
    # 停止该镜像正在运行的Docker容器
    line=`docker ps | grep $name`
    if [ -n "$line" ]; then
    	echo "存在正在运行的$name容器, 正在使其停止运行..."
    	docker stop $name
    	echo "$name容器, 已停止运行"
    fi
    
    # 删除该镜像的Docker容器
    line=`docker ps -a | grep $name`
    if [ -n "$line" ]; then
    	echo "存在$name容器, 对其进行删除..."
    	docker rm $name
    	echo "$name容器, 已被删除"
    fi
    
    # 启动容器
    docker run --rm --name $name -p 8008:8006 -d $domain/$url:$tag
    
    IFS=$'\n'
    
    # 删除多余镜像
    images=`docker images | grep $domain/$url`
    for i in $images
    	do
    		echo $i
    		t=`echo "$i" | awk '{print $2}'`
    		if [ "$t" != "$tag" ]; then
    			id=`echo "$i" | awk '{print $3}'`
    			docker rmi $id
    		fi
    	done
    复制代码
  8. 基本完成

    完成以上所有配置后,当在本地将代码 pushGit 远程仓库 时,则会触发 Git WebHooks ,从而全自动的实现对服务器项目的自动更新和部署。

内容小结

这篇文章对如何使用 Docker 结合 Jenkins 实现 Go 语言项目的持续集成进行了简单讲解,在最后讲一下实践过程中需要注意的地方。

首先是在 Jenkins服务器 上通过 git pull 命令拉取远程仓库的代码时,如果为私有仓库,可能会需要输入 Git 账号和密码,这里使用的方式是通过设置 Git 全局变量的方式,记录 Git 账号和密码。

git config --global credential.helper store
复制代码

然后是最后的 构建后操作 过程中,笔者本人会出现一个现象,当远程服务器第一次从 docker镜像仓库 获取镜像时,会因为由于远程服务器本地不存在该镜像依赖的其他镜像,从而导致拉取的速度较慢,出现超时的情况。该问题的解决方案可修改超时时间或者进入远程服务器中手动拉取一遍。

最后附上与演示项目内容一致的代码仓库: gitee.com/hkail/go-do…

实践时需修改的内容可能有:

docker-push 脚本文件中: domain 仓库域名, url 仓库URL, docker login 命令后的用户名和密码

docker-pull 脚本文件中:同 docker-pull 脚本文件, docker run 命令后的映射端口号

最后,感谢大家的耐心阅读~

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章