Jenkins + Ansible 实现 Golang 自动化编译部署

环境:

  • 本机(local): Mac OS 10.13
  • 跳板机(jenkins): Ubuntu 14.04
  • 目标机(servers): Ubuntu 14.04

项目说明

项目目录下至少需要三块文件:

  • hosts: 用于指定 ansible 插件作用的目标服务器

比如下面指定了两组服务器,在 jenkins 的 servers 参数中可以选择某一组(‘dev’、’prod’)也可以用 ‘all’ 或 ‘*’ 代表所有服务器

[dev] // 组名
10.9.X.A ansible_connection=ssh ansible_ssh_user=work

[prod]
10.42.X.B ansible_connection=ssh ansible_ssh_user=work
10.42.X.C ansible_connection=ssh ansible_ssh_user=work
  • pm2.json: 用于在目标服务器上设置 pm2 守护程序

比如

{
  "name": "sandiego", // 项目名
  "script": "sandiego", // 运行文件,因为最后一般是把可执行文件和 pm2.json 放在同一目录,指定编译后的文件名即可,需要和 jenkins 当中的参数一致
  "error_file": "log/error.log",
  "out_file": "log/out.log",
  "instances": 1,
  "exec_interpreter": "none",
  "exec_mode": "fork",
  "merge_logs": true
}
  • vendor 目录: 在 jenkins 服务器上编译时需要此目录中的依赖,请保证项目编译所需均在此并上传 git 远程仓库。可以用 dep 命令解决

注意事项: 最好在项目根目录有一个编译入口文件,比如 main.go,编译时会在项目根目录 build;另外如果代码中引用相对路径的文件,最好是同级或子目录里的,如果出现 “../path/config.file” 这样的上层目录引用,后面处理会麻烦点

比如:

$ tree $GOPATH/src/sandiego
├── cgo
│   ├── cgo.go
│   ├── demo.cpp
│   └── demo.h
├── Gopkg.lock
├── Gopkg.toml
├── main.go
├── hosts
├── pm2.json
└── vendor/

如果项目结构不是这样,则需要适当修改 jenkins 的编译和部署脚本

跳板机安装 JDK (如果有则跳过)

添加源

$ sudo add-apt-repository ppa:webupd8team/java

$ sudo apt-get update

安装 jdk8

$ sudo apt-get install oracle-java8-installer

设置系统默认 jdk

$ sudo update-java-alternatives -s java-8-oracle

测试 jdk

$ java -version

$ javac -version

安装 Jenkins

$ wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -

$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'

$ sudo apt-get update

$ sudo apt-get install jenkins
  • 访问端口:8080
  • 安装目录:/var/lib/jenkins
  • 日志目录:/var/log/jenkins/jenkins.log
# 开启
$ sudo service jenkins start # sudo /etc/init.d/jenkins start
# 关闭
$ sudo service jenkins stop # sudo /etc/init.d/jenkins stop
# 重启
$ sudo service jenkins restart # sudo /etc/init.d/jenkins restart

更改 jenkins 目录(可选)

$ chown -R jenkins:jenkins /home/work/jenkins
$ sudo vi /etc/profile 中添加 export JENKINS_HOME=/home/work/jenkins
$ sudo service jenkins restart

设置 Jenkins

初始化

访问 ip:8080 访问配置页面,初始化时需要传入初始管理员密钥,可以到跳板机上查看 /var/log/jenkins/jenkins.log 或者 /var/lib/jenkins/secrets/initialAdminPassword 获取

安装插件

配置完管理员账号后进入主页面,点击 manage jenkins > manage plugins 进入插件安装页面

plugins

搜索并安装 Go 插件Ansible 插件Blue Ocean 插件Email-Ext,最后重启一下 Jenkins 服务

email-ext 这个插件可能搜不到,可以到这个界面: http://updates.jenkins-ci.org/download/plugins/email-ext/ 下载插件文件并手动安装

配置插件

1、点击 manage jenkins > global tool configuration 找到 Go 插件配置:

configure-go

添加相应版本的 GOSDK,这里可以设置多个不同版本,之后项目中可以通过 name 选择


2、在跳板机上执行 ssh-keygen -t rsa 生成密钥对,默认会放在 ~/.ssh/ 里,将公钥 id_rsa.pub 的内容追加进所有目标机的 ~/.ssh/authorized_keys 文件中(可以使用 ssh-copy-id 命令实现)

测试在跳板机上是否可以用 ssh 直连目标服务器,如果可以说明密钥生效

在跳板机上安装 Ansible:

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

3、点击 manage jenkins > global tool configuration 找到 Ansible 插件配置:

configure-ansible

4、我之前使用的部署插件是 Publish Over SSH,但是 pos 只能一个一个添加目标服务器的配置,太麻烦,后来就换成 Ansible 了,这里也贴一下 pos 的配置:

configure-ssh-servers

deploy-shell

5、配置邮件

Manage Jenkins > Configure System > Extended E-mail Notification

email-configure

邮件模板:

<hr/>
(本邮件是程序自动下发的,请勿回复!)<br/><hr/>

项目名称:$PROJECT_NAME<br/><hr/>

构建编号:build_$BUILD_NUMBER<br/><hr/>

构建状态:$BUILD_STATUS<br/><hr/>

触发原因:${CAUSE}<br/><hr/>

构建日志地址:<a href="${BUILD_URL}console">${BUILD_URL}console</a><br/><hr/>

构建地址:<a href="$BUILD_URL">$BUILD_URL</a><br/><hr/>

变更集:${JELLY_SCRIPT,template="html"}<br/><hr/>

添加 golang 模板项目

点击 new item 进入项目配置页,填入项目名,选择 Freestyle Project。

然后是项目详情设置

project

1 ~ 4、General 一栏中选上 This project is parameterized,然后添加四个参数: tag(用于选择 git 分支)、gitRepo(用于拉取项目)、filename(编译和部署时用的文件名)、servers(Ansible 插件作用的目标服务器组)

5、源码选择 Git,填入 https://$gitRepo,如果是私有仓库,还要添加凭证(可以使用账号密码也可以用密钥)

代码默认会克隆到当前项目的工作目录中,默认是 /var/lib/jenkins/workspace/项目名/,如果像图中一样设置 check out to a sub-directory,则会克隆到 /var/lib/jenkins/workspace/项目名/sub-directory/

6、Build Environment 选上 golang 工具,并选择一个 GOSDK 版本

7、Build 部分添加一个 Execute shell,填入你想执行编译的脚本,比如图中是

export GOPATH=$WORKSPACE/gopath
export PATH=$GOPATH:$PATH

FilePath=$gitRepo

mkdir -p $GOPATH/bin
mkdir -p $GOPATH/src/$FilePath

rm -rf $GOPATH/src/$FilePath/*
cp -R git-repo/* $GOPATH/src/$FilePath

cd $GOPATH/src/$FilePath

go build -o $filename

需要注意的是 jenkins 需要我们临时声明 \$GOPATH,这里是设置工作目录下的 gopath 文件夹为 \$GOPATH,代码目录需要按仓库的路径添加,避免之后导包出现错误

8、添加一个 Ansible file 指令,在目标服务器上创建目录

dest=~/$filename/log/ mode=755 owner=work group=work state=directory

Inventory 选择项目中指定的 hosts 文件

Credentials 需要刚才生成的密钥对中的私钥 id_rsa 的内容和你要登录目标服务器的用户

点击 Advanced 按钮,将 Number of parallel processes 设为 0,并选上 Disable the host SSH key checkColorized stdout

下面的指令也是相同的设置

9、添加一个 Ansible copy 指令,将第 7 步编译出来的文件上传到目标服务器

src=$WORKSPACE/gopath/src/$gitRepo/$filename dest=~/$filename/log/ owner=work group=work mode=755

10、添加一个 Ansible copy 指令,将项目中的 pm2.json 文件上传到目标服务器

src=$WORKSPACE/gopath/src/$gitRepo/pm2.json dest=~/$filename/log/ owner=work group=work mode=644

11、添加一个 Ansible shell 指令,在目标服务器上执行脚本实现部署更替

cd ~/$filename;
mv $filename last_version;
mv log/$filename log/pm2.json .;
pm2 startOrRestart pm2.json;

12、添加邮件提醒

email-notifier

添加新的 Job

当有新的项目时,只需要点击 new item 进入项目配置页,填入项目名,然后选择最下方的 Copy from,从模板项目中拷贝配置信息。

然后修改前面四个参数和使用的凭证即可。

执行编译

创建好项目后点击 build with parameters 执行编译部署任务,可以进入 build history 查看具体控制台输出

project

也可以点击侧边栏中的 Open Blue Ocean 后进入相应 job,点击 Run 并查看输出

project

邮件信息

email

email

其他

完整的 CICD 流程还应该再加上 git hook,这样 push 后能直接触发编译部署;

而且编译前应该先执行测试脚本,测试完后再继续下一步,我这里没有加单元测试,所以略过了;

Jenkins 环境变量说明

自己定义的参数(Parameter)在调用时可以直接用 $参数名,比如 \$tag;
设置的环境变量可以用 \${环境变量名} 调用。

  • BRANCH_NAME:
    对于多分支项目,这将被设置为正在构建的分支的名称,例如,如果您希望从 master 部署到生产环境而不是从 feature 分支部署;如果对应某种更改请求,则该名称通常是任意的(请参阅下面的CHANGE_ID和CHANGE_TARGET)

  • CHANGE_ID:
    对于与某种更改请求相对应的多分支项目,这将被设置为更改 ID,例如拉取请求编号(如果支持)

  • CHANGE_URL:
    对于与某种更改请求相对应的多分支项目,这将被设置为更改 URL (如果支持)

  • CHANGE_TITLE:
    对于与某种更改请求相对应的多分支项目,这将被设置为更改的标题(如果支持)

  • CHANGE_AUTHOR:
    对于与某种更改请求相对应的多分支项目,这将被设置为建议更改的作者的用户名(如果支持)

  • CHANGE_AUTHOR_DISPLAY_NAME:
    对于与某种更改请求相对应的多分支项目,这将被设置为建议更改的作者的人名(如果支持)

  • CHANGE_AUTHOR_EMAIL:
    对于与某种更改请求相对应的多分支项目,这将被设置为建议更改的作者的 Email 地址(如果支持)

  • CHANGE_TARGET:
    对于与某种更改请求相对应的多分支项目,这将被设置为合并到的目标或者基础分支(如果支持)

  • BUILD_NUMBER: 当前构建的编号,例如 “4674” 等

  • BUILD_ID: 当前构建的版本 ID,与构建的 BUILD_NUMBER 相同

  • BUILD_DISPLAY_NAME: 当前版本的显示名称,默认为 “#4674”,即 BUILD_NUMBER

  • JOB_NAME: 即此版本的项目名称,例如 “foo” 或 “foo/bar”

  • JOB_BASE_NAME: 此构建的项目的短名称剥离文件夹路径,例如 “bar/foo” 的 “foo”

  • BUILD_TAG:
    “jenkins - ${JOB_NAME} - ${BUILD_NUMBER}” 的字符串。JOB_NAME 中的所有正斜杠(/)都用破折号(-)替换。方便地放入资源文件,jar文件等,以便于识别

  • EXECUTOR_NUMBER:
    唯一编号,用于标识执行此构建的当前执行程序(在同一台计算机的执行程序中)。这是您在“构建执行程序状态”中看到的数字,但数字从 0 开始,而不是从 1 开始

  • NODE_NAME:
    如果构建在代理上,则代理的名称; 如果在主版本上运行,则为 “MASTER”

  • NODE_LABELS: 节点分配的空白分隔的标签列表

  • WORKSPACE: 作为工作空间分配给构建的目录的绝对路径

  • JENKINS_HOME: Jenkins 用于存储数据的主节点上分配的目录的绝对路径

  • JENKINS_URL:
    Jenkins 的完整URL,如 http://server:port/jenkins/(注意: 仅在系统配置中设置 Jenkins URL 时可用)

  • BUILD_URL:
    此版本的完整 URL,例如 http://server:port/jenkins/job/foo/15/(必须设置 Jenkins URL)

  • JOB_URL:
    该任务的完整 URL,例如 http://server:port/jenkins/job/foo/(必须设置 Jenkins URL)

  • GIT_COMMIT: The commit hash being checked out

  • GIT_PREVIOUS_COMMIT: The hash of the commit last built on this branch, if any

  • GIT_PREVIOUS_SUCCESSFUL_COMMIT: The hash of the commit last successfully built on this branch, if any

  • GIT_BRANCH: 远程分支名称,如果有的话

  • GIT_LOCAL_BRANCH: 本地分支名称,如果有的话

  • GIT_URL: 远程 git 仓库的 URL。如果有多个,将会是 GIT_URL_1、GIT_URL_2 等

  • GIT_COMMITTER_NAME: 配置的 Git 提交者名称(如果有的话)

  • GIT_AUTHOR_NAME: 配置的 Git 作者姓名(如果有的话)

  • GIT_COMMITTER_EMAIL: 配置的 Git 提交者电子邮件(如果有的话)

  • GIT_AUTHOR_EMAIL: 已配置的 Git 作者电子邮件(如果有)

  • SVN_REVISION: 当前工作区的 Subversion 版本号,例如“12345”

  • SVN_URL: 当前工作区的 Subversion 版本号,例如“12345”

文章目录
  1. 项目说明
  2. 跳板机安装 JDK (如果有则跳过)
  3. 安装 Jenkins
  4. 设置 Jenkins
    1. 初始化
    2. 安装插件
    3. 配置插件
    4. 添加 golang 模板项目
    5. 添加新的 Job
    6. 执行编译
  5. 其他
  6. Jenkins 环境变量说明