目录

如何使用 GitLab CI/CD 快速实现自动化构建与发布

背景

现在每次开发完成代码、每次改完代码都要经历“本地编译→打包→传服务器→SSH登录→停止旧服务→启动新服务”这一套流程,

算下来每次部署最少要10分钟。

之后接入了GitLab CI/CD 流水线,现在提交代码后喝杯咖啡的功夫,自动化构建、测试、发布就全完成了,还能自动回滚——这才是DevOps该有的效率。本篇将记录下如何将 go 项目接入 GitLab CI/CD 实现部署发布自动化,希望能够帮助大家提高开发效率。

常见的 CI/CD 流水线有:

  • Github Action
  • Jenkins
  • Gitlab

我用的 Gitlab 的 Saas 版,如果有条件可以自己部署 gitlab,官方有开源代码

见:https://about.gitlab.com/

GitLab CI/CD是什么?

很多新手听到“CI/CD”就觉得复杂,其实核心就是“代码提交后自动完成一系列操作”的工具:

  • CI(持续集成):代码提交后自动执行构建、测试,比如Go项目的编译、单元测试,提前发现语法错误或逻辑bug;
  • CD(持续部署/交付):集成通过后自动把代码部署到服务器(部署),或生成可交付的安装包(交付),我们重点讲自动化部署。

GitLab CI/CD不需要额外搭建服务器,只要你的代码存在GitLab仓库,再配置两个核心组件就够用:

  1. .gitlab-ci.yml:放在项目根目录的配置文件,用来定义“什么时候执行什么操作”,比如“提交到main分支后执行构建”;
  2. GitLab Runner:执行CI/CD任务的“工人”,可以安装在本地电脑或服务器上,接收GitLab的指令并执行构建、发布等操作。

GitLab社区版就支持完整的CI/CD功能,个人或企业用都不用额外付费,这也是它比Jenkins更轻量的核心原因。

注册 Gitlab

从官方 https://about.gitlab.com/ 注册,即可使用 Saas 版本

⚠️:gitlab 处于某些原因,现在似乎不对中国用户免费开放了……

创建项目

进入 Saas 版 gitlab 之后,创建一个 git 仓库,基本和 github 操作一致,然后提交自己的代码

具体可以从官方了解:https://about.gitlab.com/

创建 GitLab Runner

在你服务器下部署 gitlab runner,然后注册到 gitlab 上

Runner是执行任务的核心,必须安装在“能访问GitLab仓库+能访问部署服务器”的机器上,

这里推荐直接装在部署服务器上(减少权限问题)。

这里以 CentOS 为例

# 1. 添加Runner仓库
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash

# 2. 安装Runner
sudo yum install gitlab-runner -y

# 3. 验证安装(出现版本号即为成功)
gitlab-runner --version

安装完成后进行注册(可以理解为连接 gitlab):

# 执行注册命令
sudo gitlab-runner register

# 按照提示依次输入信息
1. Enter the GitLab instance URL: 粘贴第一步复制的URL
2. Enter the registration token: 粘贴第二步复制的令牌
3. Enter a description for the runner: 输入描述(如"Go服务部署Runner",自定义)
4. Enter tags for the runner (comma-separated): 输入标签(如"go-deploy",后续配置文件要用到)
5. Enter an executor: 选择执行器(输入"shell",简单易上手)
6. 其他选项直接回车默认即可

验证是否注册成功

回到GitLab仓库的Runners页面,会看到“Active”状态的Runner,标签和描述和注册时一致,说明注册成功。

创建 CI/CD 流水线

在自己的项目下创建 .gitlab-ci.yml 文件

整体流程设计

定义3个阶段(stages),执行顺序是“build→test→deploy”,只有前一个阶段成功,后一个阶段才会执行:

  • build(构建):编译Go项目生成可执行文件;
  • test(测试):执行单元测试,确保代码逻辑正确;
  • deploy(发布):把构建好的程序传到服务器指定目录,重启服务。

模版文件如下:

stages: # 执行的步骤
#  - test
  - build
#  - push
  - deploy
before_script:
  - date
after_script:
  - echo "Job finished at $(date)"
variables: # 环境变量
  GIT_DEPTH: 3 # 抓取代码的深度,如设置 3 ,则 只抓取或克隆最后的3次commits
  GIT_BRANCH: ${CI_COMMIT_REF_NAME} # 内置变量,用于获取当前Git commit所在的分支或标签的名称
  GIT_TAG: ${CI_COMMIT_TAG} # 内置变量,用于获取当前Git commit所在的标签的名称。如果当前Git commit不是一个标签,则${CI_COMMIT_TAG}的值为空字符串。
  GIT_COMMIT: ${CI_COMMIT_SHORT_SHA} # 置变量,用于获取当前Git commit的短哈希值(默认为7位)
  VERSION: ${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHORT_SHA}
  CICD_SVC_IMAGE: test-cicd-${VERSION}
# -----------------------------------  test-cicd -------------------------------------
## 1. 单元测试 、golangcli-lint
test-test-cicd:
  stage: test
  tags:
    - master
  script:
    - echo '正在执行单元测试......'
  rules:
    - changes:
        - test-cicd/**/*.*
lint-test-cicd:
  stage: test
  tags:
    - master
  script:
    - echo '正在执行 golangci-lint ......'
  rules:
    - changes:
        - test-cicd/**/*.*

然后本地修改代码-提交代码,gitlab 就会自动执行流水线啦

进阶优化

优化 1:缓存依赖(加速构建)

每次构建都要拉取 Go mod 依赖,耗时较长。用 cache 缓存依赖目录,下次构建直接复用:

# 全局缓存(所有 job 共享)
cache:
  paths:
    - $GOPATH/pkg/mod/  # Go mod 依赖缓存
    - ~/.cache/go-build/  # Go 构建缓存

build_job:
  script:
    - go mod tidy --modcacherw  # 确保依赖可写,方便缓存更新
    - go build -o $APP_NAME

优化 2:多环境部署(测试/生产)

实际开发需要区分测试和生产环境,通过“环境变量+分支”控制:

# 测试环境部署(develop 分支触发)
deploy_test_job:
  stage: deploy
  tags:
    - go
  environment:
    name: test  # 标记环境,GitLab 会显示环境记录
    url: http://test.example.com:8080
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker stop $APP_NAME-test || true
    - docker rm $APP_NAME-test || true
    - docker run -d --name $APP_NAME-test -p 8081:8080 $DOCKER_IMAGE
  only:
    - develop

# 生产环境部署(main 分支或版本标签触发)
deploy_prod_job:
  stage: deploy
  tags:
    - go
  environment:
    name: production
    url: http://prod.example.com:8080
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker stop $APP_NAME-prod || true
    - docker rm $APP_NAME-prod || true
    - docker run -d --name $APP_NAME-prod -p 8080:8080 $DOCKER_IMAGE
  only:
    - main
    - /^v\d+\.\d+\.\d+$/
  when: manual  # 手动触发,避免自动部署风险

生产环境加 when: manual,需要在 GitLab 界面点击“播放”按钮才执行部署,增加一道防护。

优化 3:失败通知(及时止损)

自动化流程失败后要及时通知,避免等到用户反馈才发现问题。配置邮件通知或 Slack 通知,以邮件为例:

# 全局通知配置
notify_failure:
  stage: .post  # 所有阶段结束后执行
  tags:
    - go
  script:
    - echo "发送失败通知邮件"
    - apt-get update && apt-get install -y mailutils  # 安装邮件工具
    - echo "Pipeline 失败!项目:$CI_PROJECT_NAME,分支:$CI_COMMIT_BRANCH,链接:$CI_PIPELINE_URL" | mail -s "GitLab CI/CD 失败通知" your-email@example.com
  when: on_failure  # 只有当流程失败时执行
  dependencies: []  # 不依赖任何产物

常见问题

Q1. Runner 显示“离线”或不执行任务?

排查步骤:

① 检查 Runner 服务是否启动:sudo gitlab-runner status,没启动就执行 sudo gitlab-runner start

② 检查网络:Runner 所在机器能否访问 GitLab 仓库 URL(用 ping 或 curl 测试);

③ 重新注册:如果以上都没问题,删除旧 Runner(sudo gitlab-runner unregister --name runner-name)后重新注册。

Q2. 构建时提示“go: command not found”?

原因:Runner 所在机器没装 Go 环境,或 Go 环境变量没配置。

解决:

① 在 Runner 机器安装 Go 1.20+;

② 配置环境变量:在 /etc/profile 中添加 export PATH=$PATH:/usr/local/go/bin,然后执行 source /etc/profile,最后重启 Runner。

Q3. Docker 镜像推送到 GitLab 仓库失败?

常见原因:

① 权限不足:确保 GitLab 仓库的“Settings → Repository → Deploy tokens”有推送镜像的权限;

② 镜像标签错误:DOCKER_IMAGE 必须是 CI_REGISTRY_IMAGE:标签,其中 CI_REGISTRY_IMAGE 是 GitLab 自带变量,不用手动改;

③ 未登录:检查脚本中是否有 docker login 步骤,CI_REGISTRY_USERCI_REGISTRY_PASSWORD 是 GitLab 自动生成的,不用手动配置。

Q4. 多 Runner 时如何指定特定 Runner 执行任务?

通过 tags 精确匹配:

① 注册 Runner 时给不同 Runner 加不同标签,比如测试环境 Runner 加 test-runner,生产环境加 prod-runner

② 在 job 中通过 tags: [test-runner] 指定 Runner,避免任务跑错环境。

总结

GitLab CI/CD 自动化的核心是“用配置文件定义流程,让 Runner 自动执行”,入门的关键是先搭简单流程跑通,再逐步优化。

不同项目(如 Java、前端)的配置思路类似,只是构建和部署脚本不同。

如果在搭建的过程中还遇到其他问题,欢迎在评论区交流~

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-gitlab-ci-cd/

备用原文链接: https://blog.fiveyoboy.com/articles/go-gitlab-ci-cd/