在 GitLab CI 中使用 Docker 构建 Go 项目
这篇文章是我在 CI 环境（特别是在 Gitlab 中）的 Docker 容器中构建 Go 项目的研究总结。我发现很难解决私有依赖问题（来自 Node/.NET 背景），因此这是我写这篇文章的主要原因。
Go CI Docker
这篇文章是我在 CI 环境（特别是在 Gitlab 中）的 Docker 容器中构建 Go 项目的研究总结。我发现很难解决私有依赖问题（来自 Node/.NET 背景），因此这是我写这篇文章的主要原因。
![](/data/attachment/album/201805/10/115107wk2k2tmtvm1xkvt1.jpg)


### 介绍


这篇文章是我在 CI 环境（特别是在 Gitlab 中）的 Docker 容器中构建 Go 项目的研究总结。我发现很难解决私有依赖问题（来自 Node/.NET 背景），因此这是我写这篇文章的主要原因。如果 Docker 镜像上存在任何问题或提交请求，请随时与我们联系。


### dep


由于 dep 是现在管理 Go 依赖关系的最佳选择，因此在构建前之前运行 `dep ensure`。


注意：我个人不会将我的 `vendor/` 文件夹提交到源码控制，如果你这样做，我不确定这个步骤是否可以跳过。


使用 Docker 构建的最好方法是使用 `dep ensure -vendor-only`。 [见这里](https://github.com/golang/dep/blob/master/docs/FAQ.md#how-do-i-use-dep-with-docker)。


### Docker 构建镜像


我第一次尝试使用 `golang:1.10`，但这个镜像没有：


* curl
* git
* make
* dep
* golint


我已经创建好了用于构建的镜像（[github](https://github.com/sjdweb/go-docker-build/blob/master/Dockerfile) / [dockerhub](https://hub.docker.com/r/sjdweb/go-docker-build/)），我会保持更新，但我不提供任何担保，因此你应该创建并管理自己的 Dockerhub。


### 内部依赖关系


我们完全有能力创建一个有公共依赖关系的项目。但是如果你的项目依赖于另一个私人 Gitlab 仓库呢？


在本地运行 `dep ensure` 应该可以和你的 git 设置一起工作，但是一旦在 CI 上不适用，构建就会失败。


#### Gitlab 权限模型


这是在 [Gitlab 8.12 中添加的](https://docs.gitlab.com/ce/user/project/new_ci_build_permissions_model.html)，这个我们最关心的有用的功能是在构建期提供的 `CI_JOB_TOKEN` 环境变量。


这基本上意味着我们可以像这样克隆[依赖仓库](https://docs.gitlab.com/ce/user/project/new_ci_build_permissions_model.html#dependent-repositories)：



```
git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/myuser/mydependentrepo

```

然而，我们希望使这更友好一点，因为 `dep` 在试图拉取代码时不会奇迹般地添加凭据。


我们将把这一行添加到 `.gitlab-ci.yml` 的 `before_script` 部分。



```
before_script:
  - echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc

```

使用 `.netrc` 文件可以指定哪个凭证用于哪个服务器。这种方法可以避免每次从 Git 中拉取（或推送）时输入用户名和密码。密码以明文形式存储，因此你不应在自己的计算机上执行此操作。这实际用于 Git 在背后使用 `cURL`。 [在这里阅读更多](https://github.com/bagder/everything-curl/blob/master/usingcurl-netrc.md)。


### 项目文件


#### Makefile


虽然这是可选的，但我发现它使事情变得更容易。


配置这些步骤意味着在 CI 脚本（和本地）中，我们可以运行 `make lint`、`make build` 等，而无需每次重复步骤。



```
GOFILES = $(shell find . -name '*.go' -not -path './vendor/*')
GOPACKAGES = $(shell go list ./...  | grep -v /vendor/)

default: build

workdir:
    mkdir -p workdir

build: workdir/scraper

workdir/scraper: $(GOFILES)
    GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o workdir/scraper .

test: test-all

test-all:
    @go test -v $(GOPACKAGES)

lint: lint-all

lint-all:
    @golint -set_exit_status $(GOPACKAGES)


```

#### .gitlab-ci.yml


这是 Gitlab CI 魔术发生的地方。你可能想使用自己的镜像。



```
image: sjdweb/go-docker-build:1.10

stages:
  - test
  - build

before_script:
  - cd $GOPATH/src
  - mkdir -p gitlab.com/$CI_PROJECT_NAMESPACE
  - cd gitlab.com/$CI_PROJECT_NAMESPACE
  - ln -s $CI_PROJECT_DIR
  - cd $CI_PROJECT_NAME
  - echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc
  - dep ensure -vendor-only

lint_code:
  stage: test
  script:
    - make lint

unit_tests:
  stage: test
  script:
    - make test

build:
  stage: build
  script:
    - make


```

### 缺少了什么


我通常会用我的二进制文件构建 Docker 镜像，并将其推送到 Gitlab 容器注册库中。


你可以看到我正在构建二进制文件并退出，你至少需要将该二进制文件（例如生成文件）存储在某处。




---


via: <https://seandrumm.co.uk/blog/building-go-projects-with-docker-on-gitlab-ci/>


作者：[SEAN DRUMM](https://seandrumm.co.uk/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

