Go 项目使用 Gitlab 生态构建镜像

前言⌗
Go 项目的构建方式有很多,如何能找到一种适合自己团队的呢?
今天分享的就是我自己摸索出来的一些经验,通过 Gitlab 的强大生态,让 Go 项目从开发到部署都变得更加高效!
环境⌗
为了本次实验,我在本地使用 Docker 跑了如下服务:
- Traefik: 用于服务自动发现并反向代理
- Gitlab: 用于测试 CI/CD 的流程(需开启 Container Registry)
- Gitlab Runner: 用于执行 CI/CD 的任务
Traefik 和 Gitlab 的部署,可以参考我之前两篇文章,里面有详细的部署方案!
域名⌗
- gitlab.test
- registry.test
因为是内网测试环境,所以所有服务的 HTTPS 证书都是使用 mkcert 自签名的,这也为接下来的基础设施搭建挖了很大一个坑,但通过爬坑也掌握了更多原理!
注册 Runner⌗
在最新版的 Gitlab 中可以访问 https://gitlab.test/admin/runners
进入 Runner 的管理页面:
- 进入后点击
New instance runner
按钮进行创建 - 填写 Tags 以及描述信息,然后点击
Create runner
- 保存好 Gitlab-Runner 的注册 Token
接下来编写 Gtilab Runner 的配置文件以和 docker-compose.yaml
文件:
config/config.toml
文件:
- 在 13,15 行将前面获得的 URL 和 Token
- 在 25 行将
/var/run/docker.sock:/var/run/docker.sock:ro
加入volumes
- 在 29 行设置自定义 TLD 的解析,而
10.8.10.254
这个 IP 是我在 traefik 网络中手动为 Traefik 设置的 IP
docker-compose.yaml
文件:
- 7-8 行为 Gitlab Runner 设置 HOST 解析
- 16-17 行为 Gitlab Runner 请求 https://gitlab.test 域名设置信任证书!
成功后前往 Gitlab Admin 的 Runner 页面查看 Runner 是否正常:
项目适配⌗
为了模拟真实开发环境,我创建了两个项目组和两个项目,分别是:
主要的配置都在 services/sendbox
这个项目中,其目录结构如下:
我在本地使用了 Go Workspace 来引入本地的包:
Dockerfile⌗
- 第 10 行: 将身份认证信息写入
~/.netrc
- 第 11 行: 将自签名 CA 证书写入系统中(非自签名证书,或者不适用 HTTPS 的可以删除这两行)
- 第 12 行: 更新系统信任 CA 证书(非自签名证书,或者不适用 HTTPS 的可以删除这两行)
- 第 14 行: 使用
-ldflags
将版本信息写入项目的变量中,后期做日志分析及版本稳定性分析可能会用到
在构建 Docker 镜像过程中,可以加入基于环境拉取不同私有包的设置。例如在测试环境,可以在执行构建前,先执行
go get gitlab.test/modules/mail@develop
,来拉取 develop 分支最新的 Commit,避免私有包打了 Tag 后,测试环境出现问题,又要多次发布私有包!
CI/CD 配置⌗
这里需要注意一下,最新版的 Gitlab 默认使用 .yml
后缀,所以如果要使用 .yaml
会导致 CI/CD 无法获取。如果一定要使用后者的话,可以在 Gitlab 中进行设置:
在上图中
Default CI/CD configuration file
下方修改默认 CI 配置文件名称即可!
.gitlab-ci.yml
配置如下:
Gitlab CI 预设环境变量:
- CI_REGISTRY: Container Registry HOST,这里对应的就是
registry.test
- CI_REGISTRY_USER: gitlab-ci-token
- CI_REGISTRY_PASSWORD: 值与
CI_JOB_TOKEN
一致,如需操作其他项目的 Image,参考下面的权限问题
章节 - CI_REGISTRY_IMAGE: 根据项目的命名空间自动生成的,例如我这里是: registry.test/services/sendbox
- CI_COMMIT_REF_NAME: 提交的名称,如果是分支就是分支名称,如果是 Tag 就是对应的版本,如: master,develop 或 v1.0.0
如果直接将 CI_COMMIT_REF_NAME 用于 Image Tag 可能存在问题,例如当提交的分支是 feature/auth,那么生成的 Image Tag 就是
registry.test/services/sendbox:feature/auth
,这显然不符合 Tag 的命名规范,所以这里可以使用另一个环境变量CI_COMMIT_REF_SLUG
,他会将非字母和数字的字符替换为 Slug,例如将 feature/auth 替换为 feature-auth!
更多预设环境变量可以参考 Gitlab 官方文档 GitLab CI/CD variables。
- 第 4 行: 用于打印出 Gitlab CI 预设的所有环境变量,如果你不想去看文档的话可以执行
export
,其中敏感信息会被标记为[MASKED]
- 第 26 行:
--add-host gitlab.test:"$GITLAB_IP"
这个如果 gitlab 不是在本地的话不用配置,因为我这里使用 dnsmasq 将 *.test 这个 TLD 都解析成了 127.0.0.1,这就导致 buildx 中访问 gitlab.test 最终请求的 IP 是 127.0.0.1:443! - 第 36-37 行: 再为最新版本打上 latest 标签
权限问题⌗
如果你使用 Personal Token 作为 CI/CD 中的身份认证的话,那么需要这个 Personal Token 的所有者拥有私有包的仓库访问权限。
我这里使用的是 CI_JOB_TOKEN
,这个是 Pipeline 生命周期中有效的 Token,并且在 Gitlab 15.9
版本之后,为了安全考虑,不允许跨项目访问。也就是说,在 services/sendbox
项目的 CI/CD 中使用 CI_JOB_TOKEN
拉取 modules/mail
这个私有包的时候,会认证失败,报错提示如下面图中 233 行所示:
出现这个问题你可以选择关闭 Limit Access to the project
功能,或者将要访问的项目添加到下面的 Allow CI job tokens from the following projects to access this project
列表中:
这样再次执行就可以成功获取私有包的代码了!
总结⌗
到这里项目的构建与分发问题已经很好的解决了,这种 Overwrite DNS + Self-signed 的证书,真的是能折腾死人!
不过经历最艰难的过程后,能让我更加了解 Gitlab 生态中的服务相互间是如何交互的,焉知非福吧。
后面会再分享一下关于 CD 的最佳实践,敬请期待吧…
I hope this is helpful, Happy hacking…