龙芯平台GitLab Runner Docker执行器配置实战:从镜像拉取到权限调优

📅 2026/7/28 20:25:17 👁️ 阅读次数 📝 编程学习
龙芯平台GitLab Runner Docker执行器配置实战:从镜像拉取到权限调优

最近在给一个内部项目做 CI/CD 迁移,目标是把 GitLab Runner 的执行器从 Shell 切换到 Docker。听起来是个标准操作,但真动起手来,才发现坑比想象中多。尤其是在国产化信创环境下,当宿主机是龙芯 3B6000 这样的 LoongArch 架构平台时,问题会变得格外“有趣”。你可能会遇到镜像拉取失败、容器内命令执行异常、缓存目录权限混乱等一系列报错,而网上的通用解决方案,往往在龙芯平台上水土不服。

很多人以为,在龙芯上跑 Docker 化的 GitLab Runner,无非是把gitlab/gitlab-runner镜像换成loongarch64版本。但实际落地时,你会发现这仅仅是万里长征第一步。真正的挑战在于,如何让 Runner 的 Docker 执行器与龙芯的生态、Docker 的配置、以及项目自身的构建需求无缝协同。这背后涉及的是对 Docker 执行器工作机制的深度理解,以及对龙芯平台特殊性的适配。

这篇文章,我们就来彻底拆解这个问题。我会基于在龙芯 3B6000 上的实战经验,带你走通从零到一的完整配置流程,并重点剖析那些最容易让人卡住的“暗坑”。我们的目标不是简单地贴出命令,而是让你理解每一步背后的“为什么”,从而具备在任何类似架构上自主排错和优化的能力。

1. 为什么在龙芯上配置 Docker 执行器是个“系统工程”

在 x86 或 ARM 服务器上,你可能通过几行docker run命令就能让 GitLab Runner 跑起来。但在龙芯平台上,这种“拿来主义”往往会碰壁。根本原因在于,Docker 执行器的工作模式,与龙芯生态的现状,存在几个关键的不匹配点。

1.1 Docker 执行器的核心工作流与潜在冲突

GitLab Runner 的 Docker 执行器,其本质是一个“调度器”和“监工”。当 CI/CD 流水线触发时,Runner 会执行以下核心操作:

  1. 拉取构建镜像:根据.gitlab-ci.yml中定义的image,从镜像仓库拉取对应的 Docker 镜像。
  2. 创建容器:基于拉取的镜像,启动一个全新的、隔离的容器。
  3. 注入资源:将 Git 仓库代码(作为 Volume 挂载)、缓存目录、环境变量等“注入”到这个容器中。
  4. 执行脚本:在容器内部,执行script部分定义的命令。
  5. 清理现场:构建结束后,容器被销毁(除非配置了缓存)。

这个流程在 x86 世界运行良好,因为gitlab/gitlab-runner官方镜像、各种语言的基础镜像(如alpine,ubuntu,node)都有丰富的 x86_64 和 arm64 版本。但在 LoongArch 生态中,情况就不同了。

1.2 龙芯平台的三重挑战

第一重挑战来自镜像生态。你很难直接使用node:latestpython:3.11这样的镜像,因为 Docker Hub 上官方镜像大多不提供 LoongArch 版本。你必须寻找或自己构建基于 LoongArch 的基础镜像。这直接影响了.gitlab-ci.ymlimage字段的填写。

第二重挑战在于Runner 镜像与构建镜像的架构匹配。即使你找到了loongarch64/gitlab-runner镜像,这个 Runner 本身也是在龙芯宿主机上的一个容器。当它试图拉取一个构建镜像时,Docker 会默认请求与宿主机(也就是 Runner 容器)相同的架构。如果镜像仓库没有提供 LoongArch 版本,拉取就会失败。

第三重挑战,也是最隐蔽的,是文件系统与权限的映射问题。Docker 执行器需要将宿主机目录(如代码仓库、缓存目录)挂载到构建容器内部。在龙芯服务器上,用户 ID(UID)、组 ID(GID)的映射可能因为基础镜像的不同而出现偏差,导致容器内的进程没有权限读写挂载进来的文件,引发 “Permission denied” 错误。

所以,在龙芯上配置 Docker 执行器,绝不能只盯着 Runner 本身的安装。你需要一个涵盖“Runner 容器化 -> 构建镜像准备 -> 目录权限规划 -> 流水线适配”的全局方案。接下来,我们就从零开始,搭建这个方案。

2. 从零开始:龙芯平台 GitLab Runner Docker 执行器部署指南

假设我们有一台干净的龙芯 3B6000 服务器,操作系统为 Loongnix 或 UOS 等。我们的目标是安装 Docker,然后以容器方式运行 GitLab Runner,并将其配置为 Docker 执行器。

2.1 基础环境准备:Docker 安装与配置

首先,确保 Docker 已正确安装。龙芯平台通常有社区维护的 Docker 版本。

# 1. 安装 Docker(具体命令可能因发行版而异,以下以 Loongnix 为例) sudo yum install -y docker-ce docker-ce-cli containerd.io # 2. 启动 Docker 服务并设置开机自启 sudo systemctl start docker sudo systemctl enable docker # 3. 将当前用户加入 docker 组,避免每次使用 sudo sudo usermod -aG docker $USER # 注意:需要重新登录或执行 `newgrp docker` 使组生效 # 4. 验证安装 docker --version docker run hello-world # 如果龙芯有 hello-world 镜像,可以测试

关键一步是配置 Docker 的镜像加速器,这对于后续拉取镜像至关重要。由于国内访问 Docker Hub 较慢,且 LoongArch 镜像可能存放在不同的仓库,建议配置多个镜像源。

编辑或创建/etc/docker/daemon.json

{ "registry-mirrors": [ "https://docker.mirrors.ustc.edu.cn", "https://hub-mirror.c.163.com" ], "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" }

配置完成后,重启 Docker 服务:

sudo systemctl daemon-reload sudo systemctl restart docker

2.2 获取并运行 LoongArch 版本的 GitLab Runner

官方不提供 LoongArch 版本的 Runner 镜像,但社区有维护。我们可以从hub.gitlab.cn或龙芯的镜像仓库获取。

# 拉取 LoongArch 架构的 GitLab Runner 镜像 docker pull hub.gitlab.cn/loongarch64/gitlab-runner:latest # 运行 GitLab Runner 容器 docker run -d \ --name gitlab-runner \ --restart always \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ hub.gitlab.cn/loongarch64/gitlab-runner:latest

命令解析与避坑点:

  • -v /srv/gitlab-runner/config:/etc/gitlab-runner:将宿主机的/srv/gitlab-runner/config目录挂载到容器内 Runner 的配置目录。这是持久化配置的关键,否则容器重启后注册信息会丢失。
  • -v /var/run/docker.sock:/var/run/docker.sock:这是 Docker 执行器的灵魂配置。它将宿主机的 Docker 守护进程套接字挂载到 Runner 容器内,使得 Runner 容器能够直接与宿主机 Docker 通信,从而创建和管理用于构建的其他容器。没有这个挂载,Docker 执行器无法工作。
  • --restart always:确保容器在异常退出或系统重启后自动启动。

2.3 向 GitLab 注册 Runner

现在,Runner 容器已经运行,但它还不知道为哪个 GitLab 项目服务。我们需要进入容器内部,完成注册。

# 进入 Runner 容器 docker exec -it gitlab-runner bash # 在容器内执行注册命令 gitlab-runner register

接下来会进入交互式注册流程,你需要准备以下信息(从 GitLab 项目获取):

  1. GitLab 实例 URL:你的 GitLab 地址,如https://gitlab.example.com
  2. 注册令牌
    • 共享 Runner:在 GitLab 管理后台Admin Area -> Overview -> Runners获取。
    • 项目特定 Runner:在项目页面Settings -> CI/CD -> Runners获取。
  3. 描述和标签:为 Runner 设置一个描述和标签,便于在流水线中通过tags选择。
  4. 执行器:这里必须选择docker
  5. 默认 Docker 镜像:这是第一个大坑。在龙芯平台,你不能填alpine:latest。必须填写一个确定存在于龙芯架构上的镜像。例如,你可以使用龙芯基础镜像仓库中的镜像,如cr.loongnix.cn/library/debian:12。如果留空或不正确,流水线会因拉取不到镜像而失败。

注册成功后,你可以在 GitLab 项目的 Runners 设置页面看到这个 Runner,状态应为online

3. 核心配置调优:让 Docker 执行器在龙芯上稳定工作

注册成功只是第一步。要让流水线真正跑起来,还需要对 Runner 的配置文件进行精细调整。配置文件位于宿主机之前挂载的目录:/srv/gitlab-runner/config/config.toml

3.1 配置解析与关键参数

用编辑器打开这个文件,你会看到刚注册的 Runner 配置段。我们需要重点关注[runners.docker]部分。

[[runners]] name = "loongarch64-docker-runner" url = "https://gitlab.example.com" token = "你的token" executor = "docker" [runners.docker] # 1. 默认镜像:必须使用龙芯可用的镜像 image = "cr.loongnix.cn/library/debian:12" # 2. 特权模式:谨慎开启。对于需要构建 Docker 镜像(Docker-in-Docker)的场景可能需要。 privileged = false # 3. 网络模式:通常保持默认。如果构建需要访问特定网络服务,可设置为 `host`,但会降低隔离性。 network_mode = "bridge" # 4. 卷挂载:这是缓存和共享目录的关键 volumes = [ "/cache", # Runner 管理的缓存目录 "/home/user/.m2:/root/.m2:rw", # 示例:将宿主机 Maven 仓库挂载进去加速构建 "/opt/builds:/opt/builds:rw" # 示例:共享一个自定义输出目录 ] # 5. 拉取策略:强烈建议在龙芯环境下使用 `if-not-present` 或 `never` pull_policy = "if-not-present" # 6. 额外主机:解决容器内域名解析问题 extra_hosts = ["gitlab.example.com:192.168.1.100"] # 7. 运行时参数:可调整内存、CPU等限制 # cpuset_cpus = "0,1" # memory = "4g" # memory_swap = "8g"

3.2 关键配置项深度解读

  • image(默认镜像):这是安全网。当你的.gitlab-ci.yml中没有指定image,或者指定的镜像拉取失败时,Runner 会回退使用这个镜像。务必设置成一个你百分百确定能在龙芯上拉取并运行的镜像。
  • pull_policy(拉取策略):这是避免构建失败的核心设置
    • always:每次都拉取最新镜像。在龙芯生态不成熟时,极易因镜像更新导致架构不匹配而失败。
    • if-not-present:本地没有时才拉取。这是最推荐的策略。你先在宿主机上手动拉取好所需的基础镜像(如docker pull cr.loongnix.cn/library/debian:12),后续构建就直接使用本地镜像,稳定可靠。
    • never:只使用本地镜像。适合完全内网、离线或对稳定性要求极高的环境。
  • volumes(卷挂载)
    • /cache:Runner 自动管理的缓存目录,用于在流水线不同作业(Job)之间传递缓存。要确保宿主机对应目录(在[[runners]]顶层有cache_dir配置)存在且 Runner 容器有读写权限。
    • 自定义挂载:如示例中的 Maven 仓库,可以显著加速 Java 项目的构建。权限问题常发于此:如果容器内用户(如root)的 UID/GID 与宿主机文件所有者不一致,会导致读写失败。解决方案通常是在宿主机上调整目录权限(chmod 777不推荐),或确保使用相同 UID/GID 的用户基础镜像。
  • extra_hosts:如果 GitLab 实例使用内部域名,或者构建过程中需要访问内网其他服务,需要在这里配置主机映射,否则容器内可能无法解析。

3.3 针对龙芯的专项调整:镜像拉取策略与缓存

在龙芯平台上,最脆弱的环节就是“拉取镜像”。因此,我们的配置策略必须围绕“避免运行时拉取”和“充分利用缓存”来设计。

策略一:预拉取所有基础镜像在宿主机上,手动拉取你项目所有可能用到的构建镜像。

docker pull cr.loongnix.cn/library/debian:12 docker pull cr.loongnix.cn/library/node:18-bookworm # ... 拉取其他所需镜像

然后,在config.toml中设置pull_policy = "if-not-present"

策略二:构建自己的项目基础镜像如果龙芯社区镜像仓库没有你需要的语言或工具链,你需要自己构建。编写 Dockerfile,从一个可靠的龙芯基础镜像(如cr.loongnix.cn/library/debian:12)开始,安装项目所需的依赖(如 gcc, python3-pip, npm 等),然后推送到你的私有镜像仓库。在.gitlab-ci.yml中直接使用这个自定义镜像,稳定性最高。

策略三:精细化配置缓存Runner 的/cache可以缓存包管理器下载的内容(如 npm 的node_modules, pip 的包, Maven 的.m2)。确保你的gitlab-ci.yml正确配置了cache关键字,并指定了缓存的路径和策略(如key,policy)。这能极大减少因网络问题导致的构建失败。

4. 编写适配龙芯的 .gitlab-ci.yml 与高级问题排查

配置好 Runner 之后,最后一步是调整你的流水线定义文件,使其适应龙芯环境。

4.1 .gitlab-ci.yml 适配要点

# 示例:一个在龙芯上构建 Node.js 项目的配置 stages: - build - test variables: # 明确指定镜像,避免使用 latest 标签 IMAGE_NAME: "cr.loongnix.cn/library/node:18-bookworm" build-job: stage: build image: $IMAGE_NAME # 使用变量,方便统一管理 tags: - loongarch64 # 必须匹配 Runner 注册时的标签 script: - node --version - npm config set registry https://registry.npmmirror.com # 使用国内镜像源 - npm ci --cache .npm --prefer-offline # 利用缓存,尝试离线安装 - npm run build cache: key: ${CI_COMMIT_REF_SLUG} paths: - .npm/ - node_modules/ artifacts: paths: - dist/

关键点:

  1. image:必须指定一个明确的、存在于龙芯上的镜像。使用变量便于维护。
  2. tags:必须与注册 Runner 时设置的标签一致,确保任务被分配到正确的龙芯 Runner 上。
  3. 镜像源:在script中,首要任务往往是替换包管理器的源为国内镜像(如 npm、pip、apt),这对龙芯服务器尤其重要,可以避免网络超时。
  4. 缓存:充分利用cache功能,缓存依赖目录。注意key的设计,要平衡缓存复用率和有效性。
  5. artifacts:如果构建产生输出物,记得通过artifacts声明,以便后续阶段或下载使用。

4.2 常见问题与排查链路

即使配置无误,流水线仍可能失败。以下是龙芯平台上 Docker 执行器的经典问题排查顺序:

问题一:Job 一直处于Pending状态。

  • 排查:检查 Runner 是否online,以及 Job 的tags是否与 Runner 的标签匹配。在龙芯环境中,你可能只为龙芯 Runner 打了特定标签(如loongarch64),而 Job 没有指定或指定了其他标签。

问题二:Pulling docker image ...阶段失败。

  • 现象ERROR: Failed to pull image ... no matching manifest for linux/loong64 in the manifest list entries
  • 原因:指定的镜像没有 LoongArch 版本。
  • 解决
    1. 检查config.toml中的pull_policy,改为if-not-present
    2. 在宿主机上手动拉取一个可用的龙芯基础镜像。
    3. 修改.gitlab-ci.yml中的image,指向正确的镜像地址。

问题三:Running with gitlab-runner ...之后,Job 失败,报错bash: line 1: npm: command not found

  • 现象:能进入容器,但命令找不到。
  • 原因:你使用的龙芯基础镜像可能非常精简,没有安装所需的工具(如node,npm,git)。
  • 解决
    1. script的第一步先安装工具,例如apt update && apt install -y nodejs npm。但这会拖慢每次构建。
    2. (推荐)自己构建一个包含项目所需全部工具链的龙芯 Docker 镜像,并推送到私有仓库使用。

问题四:Permission denied错误,发生在文件读写时。

  • 现象mkdir: cannot create directory ‘/cache’: Permission deniednpm ERR! Error: EACCES: permission denied
  • 原因:容器内运行进程的用户(通常是root)与宿主机挂载目录的所有者 UID/GID 不匹配。
  • 解决
    1. 检查宿主机挂载目录(如/srv/gitlab-runner/cache)的权限。确保 Runner 容器有读写权限(可以暂时用sudo chmod -R 777 /srv/gitlab-runner测试,生产环境需谨慎)。
    2. config.toml[runners.docker]部分,可以尝试设置user = "1000:1000"(替换成宿主机有效用户的 UID:GID),强制容器内以指定用户运行。但这要求基础镜像中存在该用户。
    3. 在 Dockerfile 中创建与宿主机相同的 UID/GID 的用户,并在gitlab-ci.ymlscript中用sudosu切换。

问题五:构建缓慢。

  • 原因:龙芯处理器性能与主流 x86 有差距,且从外网下载依赖慢。
  • 优化
    1. 缓存为王:极致优化cache配置,让依赖尽可能被复用。
    2. 镜像源:所有包管理器(apt, yum, npm, pip, maven)都必须配置国内镜像源。
    3. 构建镜像:将项目依赖尽可能多地做到自定义基础镜像里,减少每次构建时的安装时间。
    4. Runner 配置:在config.toml中适当增加cpuset_cpusmemory,为构建容器分配更多资源。

在龙芯 3B6000 上成功运行 GitLab Runner 的 Docker 执行器,标志着你打通了国产化 CI/CD 流水线的关键一环。这个过程的核心收获,远不止于一份可运行的配置。它更像是一次对“基础设施即代码”和“环境一致性”的深度实践——你必须清晰地定义每一层依赖,从宿主机 Docker 服务,到 Runner 容器,再到构建镜像,最后到项目本身的脚本。

真正的稳定,来自于对不确定性的管理。在龙芯生态中,最大的不确定性就是“随时可能拉取不到的镜像”。因此,最有效的策略就是变“动态拉取”为“静态准备”:预拉取基础镜像、自建项目镜像仓库、将pull_policy设置为if-not-present。这本质上是在用确定的、已知的、经过验证的二进制资产,去对抗外部网络和生态的不确定性。

当你完成这一切,得到的不仅仅是一个能跑通流水线的 Runner。你得到的是一个可复用的、针对特定硬件架构的 CI/CD 环境模板。下次在类似的信创环境下,无论是飞腾、鲲鹏还是其他平台,你都可以沿用同样的思路——先理解执行器机制,再解决镜像生态,最后处理权限和性能——来快速搭建起可靠的自动化构建流水线。这才是从一次具体的技术问题解决中,沉淀下来的长期价值。