首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >GitLab Runner 自动化部署踩坑记录

GitLab Runner 自动化部署踩坑记录

作者头像
桑榆肖物
发布2026-07-15 18:35:00
发布2026-07-15 18:35:00
160
举报

本文主要记录一次 gitlab-runner 自动化部署踩坑经历,涉及 GitLab Runner 的配置、Job 容器网络连通性问题,以及 Docker 宿主机接入方式的调整。通过这次经历,分享在实际部署中遇到的问题和解决方案。

1. 引言

最近为了更新和测试方便,需要给一个前端项目补一套 GitLab 自动化部署流程。目标也不复杂,推送正式发布标签后触发流水线,构建 latest 镜像,然后在服务器上替换旧容器,对外映射宿主机 8092 端口到容器 80 端口。

看上去是个很常规的动作,真正开始跑之后才发现,问题甚至不在流水线脚本里:任务还没执行到 docker build,就在准备执行环境和拉取源码时先后失败了。这篇文章记录整个判断过程,以及两处真正需要改动的 Runner 配置,如果你也在做类似的自动化部署,或许能少踩几个坑。

2. 背景与目标

项目本身是一个基于 React + Vite 的静态前端,构建产物输出到 dist 目录。部署方案采用了常见的组合:Node 负责构建,Nginx 负责提供静态资源服务。GitLab 和 GitLab Runner 都通过 Docker Compose 启动,Runner 使用 Docker executor 创建 Job 容器。

为了让发布动作尽量收敛,我给它定了几个明确规则:

  • 只在正式发布标签时触发流水线。
  • 镜像统一打成 latest
  • 部署方式不是推送镜像仓库,而是在 Runner 所在机器上直接构建并运行。
  • 访问入口固定为宿主机 8092 端口。

对应的 .gitlab-ci.yml 并不复杂,核心逻辑就是构建镜像、删除旧容器、启动新容器。问题在于,流水线还没执行到这几步,就已经先倒下了。

代码语言:javascript
复制
workflow:
  rules:
    -if:'$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/'
    -when:never

deploy_latest:
stage:deploy
image:docker:27-cli
rules:
    -if:'$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/'
script:
    -dockerbuild--pull-t"$IMAGE_NAME".
    -dockerrm-f"$CONTAINER_NAME"||true
    -dockerrun-d--name"$CONTAINER_NAME"--restartunless-stopped-p"${HOST_PORT}:80""$IMAGE_NAME"
无数次失败
无数次失败

无数次失败

3. 镜像准备

要想首次跑通,Runner 的执行环境必须准备好。GitLab Runner 的 Docker executor 会在每次 Job 执行时新建一个容器,默认使用 docker:27-cli 镜像。这个镜像本身是轻量的,里面只有 Docker CLI 工具,没有守护进程。

但 Runner 在准备 Docker executor 时,拉取官方 helper 镜像经常会因为网络问题卡住。

代码语言:javascript
复制
Running with gitlab-runner 18.11.0~pre.918.g2aaa2400 (2aaa2400)
Preparing the "docker" executor
Using Docker executor with image docker:27-cli ...
Using helper image: registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-v18.11.0
Pulling docker image registry.gitlab.com/gitlab-org/gitlab-runner/gitlab-runner-helper:x86_64-v18.11.0 ...

国内网络环境下,拉取该镜像可能不稳定。我们可以把 helper_image 指向国内镜像仓库中对应架构和 Runner 版本的镜像:

代码语言:javascript
复制
[runners.docker]
  helper_image = "swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/gitlab/gitlab-runner-helper:x86_64-v18.9.0"

这里我使用的是 docker-compose 部署的整个 DevOps 环境,要修改上面的配置需要将 gitlab-runner 容器的 /etc/gitlab-runner 挂载到宿主机,然后在宿主机上修改 config.toml,再重启 gitlab-runner 容器。

需要注意,helper 镜像应尽量与 Runner 版本保持一致。这样会避免后面出现未知的兼容性问题。

3. 代码拉取

解决了上面的问题后,流水线测试再次失败,日志停在了 Getting source from Git repository 阶段,报错大致是这样:

代码语言:javascript
复制
fatal: unable to access 'https://git.xxx.com/xxx.git/':
Failed to connect to git.xxx.com port 443: Could not connect to server
Job 容器无法访问 GitLab
Job 容器无法访问 GitLab

Job 容器无法访问 GitLab

日志很明显了,最开始我以为是 GitLab 返回的仓库地址不通,于是把 Runner 的 clone_url 改成了容器名形式,毕竟是在同一个 Docker Compose 网络里:

代码语言:javascript
复制
clone_url = "http://gitlab"

结果新的报错很快出现了:

代码语言:javascript
复制
fatal: unable to access 'http://gitlab/xxx.git/': Could not resolve host: gitlab

好吧,好吧,确实疏忽了。gitlab 是 Docker Compose 网络内的服务名,Runner 容器可以解析它;但 Docker executor 新建的 Job 容器并不自动加入这个 Compose 网络。因此,对 Job 容器来说,gitlab 就是一个不存在的主机名。

到这里,问题已经比较清楚了:

  • Runner 能注册,不代表 Job 容器能拉代码。
  • Runner 配置里的 url 是 Runner 访问 GitLab 的地址。
  • Job 真正执行 git clone 时使用的是 clone_url,未配置时则使用 GitLab 返回的仓库地址。
  • 这个地址必须是 Job 容器内部可以直接访问到的地址。

而真正的根因也随之浮出来:当前可达的不是 Compose 服务名,而是 Docker 宿主机暴露 GitLab 服务的 IP 和端口。

4. Runner 配置调整

最终可用的配置并不花哨:

代码语言:javascript
复制
clone_url = "http://172.17.0.1:8083"
网络信息
网络信息

网络信息

在 Linux 的 Docker 默认 bridge 网络中,172.17.0.1 常常是容器访问宿主机的网关地址,可以通过宿主机上的 ip a 或在 Job 容器内实际连通性测试确认。它不是应当硬编码到所有环境的固定值;重点在于,这个地址必须是“从 Job 容器内部看过去可达的 GitLab 地址”。

如果网络结构允许,让 Runner 的 Job 容器加入 GitLab 所在的自定义 Docker 网络,并使用服务名访问 GitLab,通常会比依赖默认 bridge 网关更稳定。但在当前环境中,宿主机地址是最直接可行的方案。

这一步解决的是源码拉取问题,但还有另一个隐患很快会跟上来:即便代码能拉下来了,流水线里的 docker build 和 docker run 也不一定能执行。

原因也很直接:Job 容器默认不能操作宿主机 Docker 守护进程。要让它具备这个能力,需要把宿主机的 Docker 套接字挂进来:

代码语言:javascript
复制
volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]

这行配置看起来普通,实际意义却很大。没有它,容器里的 docker 命令只是一个没有可用守护进程的客户端;有了它,命令会连接到宿主机 Docker,后面的镜像构建和容器重启才有落点。

同时也要明确它的权限边界:能访问 /var/run/docker.sock 的 Job 基本等同于拥有宿主机 Docker 的高权限。这个方案适合受信任的项目和 Runner,不应给不受信任的合并请求或公共 Runner 使用。

5. 最后

这次自动化部署的收尾,表面看是改了两行配置:一个 clone_url,一个 docker.sock 挂载。更值得记住的不是配置本身,而是背后那条朴素的原则:让任务运行在它真正能访问、真正能操作的环境里。

技术问题有时就这样,最后的修复动作不一定复杂,难的是先把问题看对。先区分失败阶段,再从实际执行环境验证网络和权限,很多看似无关的报错就会变得可解释、可复现,也更容易解决。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 桑榆肖物 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 引言
  • 2. 背景与目标
  • 3. 镜像准备
  • 3. 代码拉取
  • 4. Runner 配置调整
  • 5. 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档