gitlab
内置支持持续集成(CI),但是 go
有一点比较特殊,依赖 $GOPATH
,特别是使用了 glide
来管理包依赖后, vendor
目录必须在 $GOPATH
下,这就要求 gitlab
拉取项目源代码的位置符合 $GOPATH
的目录结构。
但是 gitlab
拉取代码后的目录结构类似 /home/gitlab-runner/builds/6913a759/0/myproject
,必须将 myproject
置于 src
目录下才符合 $GOPATH
约定。
《GitLab CI with Go》给出的方案是将拉取的代码移到 $GOPATH
下的正确位置上,再进行 glide
操作以及跑编译和测试,这篇文章提供了示例配置文件 .gitlab-ci.yml
,但有以下几个问题需要解决:
mv
操作默认是不会移动隐藏目录(如:.git
)到目标位置的,这会导致后面的任务拉取代码失败可以开启
bash
的选项dotglob
让*
匹配隐藏文件文件移动到目标位置后,没有清理机制,会影响下一任务
将
gitlab
的GIT_STRATEGY
变量配置为fetch
,它会在拉取代码后执行git clean
将未知的文件删除,如果我们将移动后的代码放在原来的位置下就可以做到自动清除没有负作用了。缓存
vendor
目录glide update
会更新 Go 项目依赖,比较耗时,构建有build
test
deploy
等多个阶段,缓存vendor
目录能够会快很多。这些阶段会依次执行,同阶段的多个任务是并行的,可以将build
阶段的工作目录状态保留到其它阶段,可以用cache
来实现,也可以将除了build
阶段以外的其它阶段的GIT_STRATEGY
置为none
来实现。创建 docker 镜像
安装完
gitlab-runner
后要将gitlab-runner
用户加入到docker
用户组,这样才可调用docker
工具。usermod gitlab-runner -a -G docker
不要在
.gitlab-ci.yml
中直接写死 docker 帐号和密码,而是引用环境变量,在~gitlab-runner/.bashrc
中设置环境变量export DOCKER_REGISTRY=gitlab.xxxxxx.com export DOCKER_USER=xxx@xxxxxx.com export DOCKER_PASSWORD=xxxxxxxx
docker 镜像按照简单的约定:
git 打 tag 时打一个镜像,做为发布镜像
之前一直想实现仅当
master
分支打tag
时才创建镜像,但是实现起来会很麻烦,因为 git 的 tag 只是 commit 的引用,与具体的 branch 无关,tags 和 branchs 是平级的概念。相关讨论 Update `.gitlab-ci.yml` to support conjunction logic for build conditions (#27818)
dev
开头的分支进行代码提交时打一个镜像,做为测试镜像
示例配置:
.gitlab-ci.yml
variables: REPO_NAME: gitlab.example.com/mygroup/myproject BIN_NAME: mygroup.myproject before_script: - go version - protoc --version - echo $CI_BUILD_REF - echo $CI_PROJECT_DIR - if [ ! -d "${CI_PROJECT_DIR}/src/$REPO_NAME" ]; then mkdir -p ${CI_PROJECT_DIR}.src.tmp/$REPO_NAME; shopt -s dotglob; mv $CI_PROJECT_DIR/* ${CI_PROJECT_DIR}.src.tmp/$REPO_NAME/; mv ${CI_PROJECT_DIR}.src.tmp ${CI_PROJECT_DIR}/src; echo "${CI_PROJECT_DIR}/src/$REPO_NAME created"; fi - export GOPATH=$CI_PROJECT_DIR - cd $GOPATH/src/$REPO_NAME build: stage: build variables: GIT_STRATEGY: fetch script: - make test: stage: test variables: GIT_STRATEGY: none script: - go test -v # Build docker image for development when any branch named begin with "dev" deploy-dev: stage: deploy variables: GIT_STRATEGY: none only: - /^dev.*/@mygroup/myproject except: - tags script: - VERSION=${CI_COMMIT_REF_NAME} make - docker build ./ -t ${REPO_NAME}/${BIN_NAME}:${CI_COMMIT_REF_NAME} - docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD} - docker push ${REPO_NAME}/${BIN_NAME}:${CI_COMMIT_REF_NAME} # Build docker image for production when pushed a tag deploy: stage: deploy variables: GIT_STRATEGY: none only: - tags@mygroup/myproject script: - VERSION=${CI_COMMIT_REF_NAME} make - docker build ./ -t ${REPO_NAME}/${BIN_NAME}:${CI_COMMIT_REF_NAME} - docker login ${DOCKER_REGISTRY} -u ${DOCKER_USER} -p ${DOCKER_PASSWORD} - docker push ${REPO_NAME}/${BIN_NAME}:${CI_COMMIT_REF_NAME}