docker+jenkins+golang持续集成实践
因为生产需要最近又重新折腾了一下Jenkins和docker。主要目的是想自动编译,打包,部署一些Golang的HttpServer。于是决定使用Jenkins来做这个持续集成的载体。
起因
因为生产需要最近又重新折腾了一下Jenkins和docker。主要目的是想自动编译,打包,部署一些Golang的HttpServer。于是决定使用Jenkins来做这个持续集成的载体,选择Jenkins出于两点原因:
1. 以前就使用过,上手会更快 2. 社区比较成熟,插件和文档丰富
安装Docker和Pull Jenkins镜像
这一步,作为前置条件且不是本文主要要描述的步骤,因此略去。网上也有很多参考资料~
Jenkins & docker-compose配置
为了方便我才用了docker-compose这个工具,docker-compose 基础可以参见我的docker-compose上手。这里直接上配置:
version: '2'
services:
jenkins:
container_name: jenkins-lts
ports:
- 9001:8080
- 50000:50000
image: jenkins/jenkins:lts
volumes:
- /home/worker/jenkins/jenkins_home:/var/jenkins_home
配置也是官方的示例配置。
Note: 将宿主机的/home/worker/jenkins/jenkins_home挂载为容器的/var/jenkins_home目录。这样做的目的是,如果容器被不小心删除也不至于Jenkins的数据丢失。
到这里,我们只需要执行docker-compose up -d
便可以将Jenkins容器跑起来了,再配置一下Nginx,便可以直接访问到Jenkins页面了,并进行初始化。
我的目录结构如下:
➜ jenkins ll
total 8.0K
-rw-rw-r-- 1 worker worker 220 May 2 17:19 docker-compose.yml
drwxrwxr-x 19 worker worker 4.0K May 3 15:53 jenkins_home
➜ jenkins pwd
/home/worker/jenkins
➜ jenkins docker-compose up -d # 运行
Publish Over SSH配置
Publish Over SSH
配置,由于我们是通过docker运行的Jenkins,因此要特别配置一下SSH,方便Jenkins部署项目。这里先列出步骤:
- 安装
Publish Over SSH
- 容器内ssh-keygen
- 配置
Publish Over SSH
- 配置Git仓库部署公钥 #这一步相当于拉取代码的Credentials
Golang Build-env
因为默认的Jenkins镜像是不带有Go的编译工具的,所以我们很有必要安装一个Go
插件Go-Plugin-Jenkins
具体步骤如下:
- 安装Jenkins
Go
插件 - 在全局工具配置中,安装Go
- 在对应任务配置-> 构建环境项,选择Go版本
这一步的详细步骤可以在参考文献第一条中查询Setup Go Build Environment
Note: 官方文档中说全局配置Go是在系统设置中进行的,但是我用的
Jenkins ver. 2.107.2
,这一项配置是在全局工具配置中。
如何打包部署
编写一个makefile来打包项目,通过scp
来分发部署服务,这也是配置Publish Over SSH
的目的。
由于Jenkins镜像不带有make相关工具(甚至Vim也没有),所以需要安装Make及其相关工具。与此同时,如果项目使用了相关的依赖管理工具,因此还有必要去配置相关的GO环境变量。其中Go的安装路径在: /var/jenkins_home/tools/org.jenkinsci.plugins.golang.GolangInstallation/$GOVERSION中。
这里贴上我的Makefile
# To test, build, deploy offline-tasks
# -: ignore this commnad error
# @: no display current commnad to std output
# Commnads declare
GOCMD=go
GOTEST=$(GOCMD) test
GOBUILD=$(GOCMD) build
# Params define
MAIN_PATH=../main
PACKAGE_PATH=../package
PACKAGE_BIN_PATH=../package/bin
BIN=offline-tasks
FILENAME=offline-tasks.tar.gz
# Deploy Params
DEV_HOST=zy-dev
DEV_TAR_PATH=/home/worker/project/offline-tasks
PROD_HOST=zy-pro2
PROD_TAR_PATH=/home/worker/project/offline-tasks
default: build pack
test:
# testing
- $(GOTEST) ../... -v
build:
# building
mkdir $(PACKAGE_PATH)
mkdir $(PACKAGE_BIN_PATH)
cd $(MAIN_PATH) && $(GOBUILD) -o $(BIN)
mv "$(MAIN_PATH)/$(BIN)" $(PACKAGE_BIN_PATH)
cp -r "../configs" $(PACKAGE_PATH)
cp "../sh/start.sh" $(PACKAGE_BIN_PATH)
pack:
# packing
cd $(PACKAGE_PATH) && tar -zcvf ../$(FILENAME) ./*
mv ../$(FILENAME) $(PACKAGE_PATH)
##################################################
# #
# deploy: from zy-dev to execute #
# deploy-dev: from dev-CI to execute #
# deploy-prod: from prod-CI to execute #
# #
##################################################
deploy: clean build pack
# deploy dev from dev
cp $(PACKAGE_PATH)/$(FILENAME) $(DEV_TAR_PATH)
cd $(DEV_TAR_PATH) && tar zxvf $(FILENAME) && supervisorctl -c configs/dev.supervisord.conf restart offline-tasks
deploy-dev: clean build pack
# deploy-dev from CI
scp $(PACKAGE_PATH)/$(FILENAME) $(DEV_HOST):$(DEV_TAR_PATH)
ssh $(DEV_HOST) "cd $(DEV_TAR_PATH) && tar zxvf $(FILENAME) && supervisorctl -c configs/dev.supervisord.conf restart offline-tasks"
deploy-prod: clean build pack
# deploying prod from dev or CI
scp $(PACKAGE_PATH)/$(FILENAME) $(PROD_HOST):$(PROD_TAR_PATH)
ssh $(PROD_HOST) "cd $(PROD_TAR_PATH) && tar zxvf $(FILENAME) && supervisorctl -c configs/prod.supervisord.conf restart offline-tasks"
clean:
# cleaning
rm -fr $(PACKAGE_PATH)
rm -fr ../$(FILENAME)
总结
进过上述的一系列操作之后,只剩下一个比较尴尬的问题了:如果Go代码仓库中vendor不带有依赖项目,那么获取依赖的动作就要自己手动来操作了~。或许可以在makefile中新增一个deps,如下:
# default set $CURDIR="$PROJ_ROOT/sh"
# preparing works...
GVT_RESTORE=gvt restore
PROJ_ROOT=../
deps:
cd ($PROJ_ROOT) && $(GVT_RESTORE)
build: deps
# building
mkdir $(PACKAGE_PATH)
mkdir $(PACKAGE_BIN_PATH)
cd $(MAIN_PATH) && $(GOBUILD) -o $(BIN)
mv "$(MAIN_PATH)/$(BIN)" $(PACKAGE_BIN_PATH)
cp -r "../configs" $(PACKAGE_PATH)
cp "../sh/start.sh" $(PACKAGE_BIN_PATH)
# other commands...
并且加deps命令,加build命令中,每次打包都检查一下依赖。