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

龙芯平台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 会执行以下核心操作拉取构建镜像根据.gitlab-ci.yml中定义的image从镜像仓库拉取对应的 Docker 镜像。创建容器基于拉取的镜像启动一个全新的、隔离的容器。注入资源将 Git 仓库代码作为 Volume 挂载、缓存目录、环境变量等“注入”到这个容器中。执行脚本在容器内部执行script部分定义的命令。清理现场构建结束后容器被销毁除非配置了缓存。这个流程在 x86 世界运行良好因为gitlab/gitlab-runner官方镜像、各种语言的基础镜像如alpine,ubuntu,node都有丰富的 x86_64 和 arm64 版本。但在 LoongArch 生态中情况就不同了。1.2 龙芯平台的三重挑战第一重挑战来自镜像生态。你很难直接使用node:latest或python:3.11这样的镜像因为 Docker Hub 上官方镜像大多不提供 LoongArch 版本。你必须寻找或自己构建基于 LoongArch 的基础镜像。这直接影响了.gitlab-ci.yml中image字段的填写。第二重挑战在于Runner 镜像与构建镜像的架构匹配。即使你找到了loongarch64/gitlab-runner镜像这个 Runner 本身也是在龙芯宿主机上的一个容器。当它试图拉取一个构建镜像时Docker 会默认请求与宿主机也就是 Runner 容器相同的架构。如果镜像仓库没有提供 LoongArch 版本拉取就会失败。第三重挑战也是最隐蔽的是文件系统与权限的映射问题。Docker 执行器需要将宿主机目录如代码仓库、缓存目录挂载到构建容器内部。在龙芯服务器上用户 IDUID、组 IDGID的映射可能因为基础镜像的不同而出现偏差导致容器内的进程没有权限读写挂载进来的文件引发 “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.cgroupdriversystemd], log-driver: json-file, log-opts: { max-size: 100m }, storage-driver: overlay2 }配置完成后重启 Docker 服务sudo systemctl daemon-reload sudo systemctl restart docker2.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 项目获取GitLab 实例 URL你的 GitLab 地址如https://gitlab.example.com。注册令牌共享 Runner在 GitLab 管理后台Admin Area - Overview - Runners获取。项目特定 Runner在项目页面Settings - CI/CD - Runners获取。描述和标签为 Runner 设置一个描述和标签便于在流水线中通过tags选择。执行器这里必须选择docker。默认 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 8g3.2 关键配置项深度解读image(默认镜像)这是安全网。当你的.gitlab-ci.yml中没有指定image或者指定的镜像拉取失败时Runner 会回退使用这个镜像。务必设置成一个你百分百确定能在龙芯上拉取并运行的镜像。pull_policy(拉取策略)这是避免构建失败的核心设置。always每次都拉取最新镜像。在龙芯生态不成熟时极易因镜像更新导致架构不匹配而失败。if-not-present本地没有时才拉取。这是最推荐的策略。你先在宿主机上手动拉取好所需的基础镜像如docker pull cr.loongnix.cn/library/debian:12后续构建就直接使用本地镜像稳定可靠。never只使用本地镜像。适合完全内网、离线或对稳定性要求极高的环境。volumes(卷挂载)/cacheRunner 自动管理的缓存目录用于在流水线不同作业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/关键点image必须指定一个明确的、存在于龙芯上的镜像。使用变量便于维护。tags必须与注册 Runner 时设置的标签一致确保任务被分配到正确的龙芯 Runner 上。镜像源在script中首要任务往往是替换包管理器的源为国内镜像如 npm、pip、apt这对龙芯服务器尤其重要可以避免网络超时。缓存充分利用cache功能缓存依赖目录。注意key的设计要平衡缓存复用率和有效性。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 版本。解决检查config.toml中的pull_policy改为if-not-present。在宿主机上手动拉取一个可用的龙芯基础镜像。修改.gitlab-ci.yml中的image指向正确的镜像地址。问题三Running with gitlab-runner ...之后Job 失败报错bash: line 1: npm: command not found。现象能进入容器但命令找不到。原因你使用的龙芯基础镜像可能非常精简没有安装所需的工具如node,npm,git。解决在script的第一步先安装工具例如apt update apt install -y nodejs npm。但这会拖慢每次构建。推荐自己构建一个包含项目所需全部工具链的龙芯 Docker 镜像并推送到私有仓库使用。问题四Permission denied错误发生在文件读写时。现象mkdir: cannot create directory ‘/cache’: Permission denied或npm ERR! Error: EACCES: permission denied。原因容器内运行进程的用户通常是root与宿主机挂载目录的所有者 UID/GID 不匹配。解决检查宿主机挂载目录如/srv/gitlab-runner/cache的权限。确保 Runner 容器有读写权限可以暂时用sudo chmod -R 777 /srv/gitlab-runner测试生产环境需谨慎。在config.toml的[runners.docker]部分可以尝试设置user 1000:1000替换成宿主机有效用户的 UID:GID强制容器内以指定用户运行。但这要求基础镜像中存在该用户。在 Dockerfile 中创建与宿主机相同的 UID/GID 的用户并在gitlab-ci.yml的script中用sudo或su切换。问题五构建缓慢。原因龙芯处理器性能与主流 x86 有差距且从外网下载依赖慢。优化缓存为王极致优化cache配置让依赖尽可能被复用。镜像源所有包管理器apt, yum, npm, pip, maven都必须配置国内镜像源。构建镜像将项目依赖尽可能多地做到自定义基础镜像里减少每次构建时的安装时间。Runner 配置在config.toml中适当增加cpuset_cpus和memory为构建容器分配更多资源。在龙芯 3B6000 上成功运行 GitLab Runner 的 Docker 执行器标志着你打通了国产化 CI/CD 流水线的关键一环。这个过程的核心收获远不止于一份可运行的配置。它更像是一次对“基础设施即代码”和“环境一致性”的深度实践——你必须清晰地定义每一层依赖从宿主机 Docker 服务到 Runner 容器再到构建镜像最后到项目本身的脚本。真正的稳定来自于对不确定性的管理。在龙芯生态中最大的不确定性就是“随时可能拉取不到的镜像”。因此最有效的策略就是变“动态拉取”为“静态准备”预拉取基础镜像、自建项目镜像仓库、将pull_policy设置为if-not-present。这本质上是在用确定的、已知的、经过验证的二进制资产去对抗外部网络和生态的不确定性。当你完成这一切得到的不仅仅是一个能跑通流水线的 Runner。你得到的是一个可复用的、针对特定硬件架构的 CI/CD 环境模板。下次在类似的信创环境下无论是飞腾、鲲鹏还是其他平台你都可以沿用同样的思路——先理解执行器机制再解决镜像生态最后处理权限和性能——来快速搭建起可靠的自动化构建流水线。这才是从一次具体的技术问题解决中沉淀下来的长期价值。