Windows Docker 环境搭建 GitLab CI/CD 流水线

Windows Docker 环境搭建 GitLab CI/CD 流水线:从零到一的完整实践

引言

GitLab CI/CD 是持续集成与持续部署工具之一。它天然集成在 GitLab 代码仓库中,无需额外搭建 Jenkins 等第三方 CI 平台,开箱即用。本文将记录在 Windows 环境下使用 Docker 部署 GitLab 和 GitLab Runner,并成功跑通一条完整 CI/CD 流水线的全过程,包括环境搭建、原理剖析、踩坑与解决,希望能为同样在 Windows 上进行 DevOps 实践的开发者提供一份可复用的参考。

一、环境准备

1.1 基础环境

  • 操作系统:Windows(Docker Desktop 运行于 WSL 2 后端)
  • 容器运行时:Docker Desktop
  • 目标技术栈:Java + Maven 多模块项目

1.2 部署 GitLab 服务端

使用 Docker 一键拉起 GitLab CE 社区版容器:

bash 复制代码
docker run -d --name gitlab \
  --shm-size=1g \
  -p 8012:8012 \
  -e GITLAB_OMNIBUS_CONFIG="external_url 'http://host.docker.internal:8012';" \
  gitlab/gitlab-ce:latest

关键参数说明:

  • --shm-size=1g:增加共享内存大小,避免 GitLab 运行时因内存不足而崩溃。
  • -p 8012:8012:将容器内 8012 端口映射到宿主机 8012 端口,此处将默认的 80 端口改为 8012。
  • external_url:设置 GitLab 的外部访问地址。host.docker.internal 是 Docker Desktop 在 Windows/Mac 下提供的特殊域名,容器内可通过它访问宿主机;Linux 下需要额外配置或改用宿主机 IP。
  • 示例中未挂载数据卷,生产环境需要挂载。完整部署流程可参考《使用 Docker 部署 GitLab》

1.3 部署 GitLab Runner

Runner 是 GitLab CI/CD 的执行引擎,负责拉取并执行流水线任务。

bash 复制代码
docker run -d --name gitlab-runner \
  -v //var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:v18.8.0

核心挂载说明:

  • -v //var/run/docker.sock:/var/run/docker.sock:将宿主机的 Docker 套接字挂载到 Runner 容器内。在 Windows 下,//var/run/docker.sock 实际对应 Windows 命名管道 \\.\pipe\docker_engine。该挂载让 Runner 容器内的 Docker 客户端能够与宿主机 Docker 守护进程通信,从而启动 CI/CD 任务容器。
  • Linux 下可直接使用 -v /var/run/docker.sock:/var/run/docker.sock

1.4 注册 Runner

bash 复制代码
docker exec -it gitlab-runner gitlab-runner register \
  --non-interactive \
  --url http://host.docker.internal:8012 \
  --registration-token xxxx \
  --description "local-docker-runner" \
  --executor docker \
  --docker-image maven:3.9-eclipse-temurin-17-alpine \
  --docker-pull-policy if-not-present

参数说明:

  • --non-interactive:非交互式注册,通过命令行一次性完成配置。
  • --url http://host.docker.internal:8012:指定 GitLab 服务器地址。host.docker.internal 在 Windows/Mac 下可解析到宿主机;若在 Linux 宿主机上运行 Docker,可改用 http://172.17.0.1:8012 或使用 --network host 模式。
  • --registration-token xxxx:注册令牌,从 GitLab 项目或组的 Settings → CI/CD → Runners 页面获取。
  • --description "local-docker-runner":Runner 的描述性名称,便于在后台识别。
  • --executor docker:使用 Docker 执行器,每个 CI Job 会启动一个全新的 Docker 容器运行,结束后销毁。
  • --docker-image maven:3.9-eclipse-temurin-17-alpine:默认基础镜像,包含 Maven 3.9 和 Java 17。
  • --docker-pull-policy if-not-present:镜像拉取策略,优先使用本地镜像,本地不存在时才从 Docker Hub 拉取,可显著加快本地流水线速度。

二、GitLab CI/CD 核心原理

2.1 Runner 的工作机制:拉取而非推送

在项目根目录下编写 .gitlab-ci.yml 文件定义流水线。代码推送到 GitLab 后,GitLab 解析该文件并生成任务,放入队列。

Runner 主动轮询 GitLab 服务器:每隔几秒向 GitLab API 发送请求,询问是否有待执行任务。若有则领取并执行,否则继续等待。这种拉取模式的优势在于:

  • Runner 可部署在内网,无需 GitLab 主动穿透防火墙。
  • GitLab 短暂重启后,Runner 可在下一轮询周期自动重试。

2.2 Docker 执行器的工作流程

当 Runner 领取到一个 Job 后,Docker 执行器按以下步骤执行:

  1. 准备阶段:创建并启动所需的服务容器。
  2. 预作业阶段:克隆代码仓库、恢复缓存、下载前一阶段的制品。
  3. 作业阶段:在用户指定的 Docker 镜像中执行构建脚本,如 mvn package
  4. 后作业阶段:创建缓存、上传制品到 GitLab。

Runner 通过数据卷挂载将代码目录共享给 Job 容器。

三、流水线配置实战

3.1 多阶段流水线设计

将流水线拆分为编译、测试、打包、部署四个阶段,实现完整链路。

yaml 复制代码
stages:
  - compile
  - test
  - package
  - deploy

variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2"

cache:
  key: maven-cache
  paths:
    - .m2/

compile:
  stage: compile
  image: maven:3.9-eclipse-temurin-17-alpine
  script:
    - mvn clean compile
  artifacts:
    paths:
      - '**/target/classes/'
      - '**/target/generated-sources/'   # 如有代码生成器
    expire_in: 1 day

test:
  stage: test
  image: maven:3.9-eclipse-temurin-17-alpine
  script:
    - mvn test
  dependencies:
    - compile
  artifacts:
    when: always
    reports:
      junit: '**/target/surefire-reports/TEST-*.xml'
    paths:
      - '**/target/surefire-reports/'
    expire_in: 6 days

package:
  stage: package
  image: maven:3.9-eclipse-temurin-17-alpine
  script:
    - mvn package -DskipTests
  dependencies:
    - compile
    - test
  artifacts:
    paths:
      - '**/target/*.jar'
      - '**/target/*.war'
    expire_in: 1 week
  rules:
    - if: '$CI_COMMIT_BRANCH == "master"'

deploy:
  stage: deploy
  image: maven:3.9-eclipse-temurin-17-alpine
  script:
    - echo "开始部署当前构建产物..."
    - ls -la app/target/*.jar
    # 实际部署命令示例:
    # - scp **/target/*.jar user@server:/deploy/path/
    # - mvn deploy -DskipTests
  dependencies:
    - package
  rules:
    - if: '$CI_COMMIT_BRANCH == "master"'

说明:代码推送到 GitLab 仓库或发起合并请求时,会触发 CI/CD 流水线。示例中仅 master 分支执行打包和部署。

四、踩坑实录与解决方案

问题一:Runner 注册成功但 Job 执行时无法访问宿主机 Docker

1.现象:Runner 注册正常,但实际运行 Job 时报错。

复制代码
ERROR: Failed to remove network for build   error=networksManager is undefined
WARNING: Preparation failed: getting docker info: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

2.原因:GitLab Runner 容器无法访问宿主机 Docker daemon。Linux 容器内需要 Unix socket 文件,但默认路径下没有可用的 socket,因为启动 Runner 容器时未挂载宿主机 socket。

3.解决:启动 Runner 容器时挂载 Docker socket。Windows Docker Desktop 下推荐写法:

bash 复制代码
-v //var/run/docker.sock:/var/run/docker.sock

注意 Windows 路径开头使用双斜杠 //,避免被 shell 或 Docker CLI 转义。

问题二:无法下载镜像文件

1.现象:

复制代码
Failed to pull image with policy "always": Error response from daemon: failed to resolve reference "docker.io/library/maven:3.9-eclipse-temurin-17-alpine": failed to do request: Head "https://registry-1.docker.io/v2/library/maven/manifests/3.9-eclipse-temurin-17-alpine"

2.原因:Runner 通过宿主机 Docker 启动 Job 容器时,无法从 Docker Hub 下载 Maven 镜像。

3.解决:先通过镜像加速站或代理将镜像下载到本地,然后在注册 Runner 时添加 --docker-pull-policy if-not-present,优先使用本地镜像(默认always, 笔者使用的docker镜像网站为:https://docker.aityp.com/)。

若 Runner 已注册,可修改其配置文件:

bash 复制代码
docker cp gitlab-runner:/etc/gitlab-runner/config.toml config.toml

编辑 config.toml,在 [runners.docker] 段中添加或修改:

toml 复制代码
[runners.docker]
  image = "maven:3.9-eclipse-temurin-17-alpine"
  pull_policy = "if-not-present"

保存后复制回容器并重启:

bash 复制代码
docker cp config.toml gitlab-runner:/etc/gitlab-runner/config.toml
docker restart gitlab-runner

问题三:Runner 注册成功但 Job 执行时无法从 GitLab 拉取代码

1.现象:Runner 执行 Job 时无法拉取代码,因为 GitLab 生成的仓库地址不可达。

2.原因:GitLab 启动时使用了 external_url "http://localhost:8012",该地址仅对宿主机有效,Runner 容器无法通过 localhost 访问 GitLab。

3.解决:

方案一:重新构建 GitLab 容器,将 external_url 改为容器可识别的宿主机地址:

bash 复制代码
-e GITLAB_OMNIBUS_CONFIG="external_url 'http://host.docker.internal:8012';"

方案二:进入 GitLab 容器,编辑 /etc/gitlab/gitlab.rb,修改:

ruby 复制代码
external_url 'http://host.docker.internal:8012'

然后重新配置并重启:

bash 复制代码
gitlab-ctl reconfigure
gitlab-ctl restart

问题四:多模块项目 Artifacts 上传失败

1.现象:mvn package 构建成功,但 artifacts 上传时报错:

复制代码
WARNING: target/*.jar: no matching files

2.原因:项目为 Maven 多模块结构,JAR 包生成在子模块目录中,例如 app/target/app-0.1.0-SNAPSHOT.jar。而 artifacts 配置的 target/*.jar 只匹配根目录下的 target/

3.解决:使用递归通配符 **/target/*.jar,匹配所有层级子目录中的 JAR 包。同样,编译阶段的 target/classes/ 也应改为 **/target/classes/

yaml 复制代码
artifacts:
  paths:
    - '**/target/*.jar'

五、进阶:模拟 Merge Request 流程

基础流水线跑通后,模拟真实的 MR 协作流程:

  1. 创建功能分支:git checkout -b dev
  2. 提交代码:git push origin dev
  3. 发起 MR:在 GitLab 网页端创建从 devmaster 的合并请求
  4. 自动触发流水线:MR 创建后,GitLab 自动针对源分支运行 CI 流水线
  5. 合并后自动部署:MR 合并入 master 后,触发 deploy 阶段,完成自动部署

MR 不仅是合并代码的入口,更是质量卡点,通过 CI 流水线自动验证代码质量,避免问题代码进入主分支。

六、总结与展望

通过本次实践,从零开始在 Windows 环境下搭建了一套完整的 GitLab CI/CD 系统,核心收获包括:

  1. Runner 采用拉取模式,主动轮询 GitLab 领取任务。
  2. Docker 执行器的作业流程为:准备 → 预作业(克隆代码、恢复缓存)→ 作业(执行构建)→ 后作业(上传制品)。
  3. Windows 下 Docker 套接字的特殊写法://var/run/docker.sock 对应命名管道 \\.\pipe\docker_engine
  4. 多模块项目应使用递归通配符 **/target/*.jar 匹配子模块制品。

后续可探索的方向包括:使用 Kubernetes 执行器实现 Runner 弹性伸缩、配置分布式缓存支持多 Runner 共享依赖、集成安全扫描实现 DevSecOps。

希望这份实践记录能为你的 GitLab CI/CD 实践提供帮助。如遇到问题,欢迎在评论区交流讨论。


愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意!

相关推荐
拿本唠嗑AI研究2 小时前
从电脑到手机:DeepSeek Harness Windows安装与手机互动教程(避坑完全版)
人工智能·windows·智能手机·deepseek·harness
面对疾风叭!哈撒给12 小时前
Windows 11 系统更新操作设置停止更新的时间
windows
孙克旭_12 小时前
Docker 镜像构建|Vue+SpringBoot+Go 多语言项目 Dockerfile 案例
linux·运维·vue.js·spring boot·docker·dockerfile
JavaPub-rodert13 小时前
使用 Docker 部署 Ollama:Docker Compose 一键运行 DeepSeek-R1 1.5B
运维·docker·容器
二宝哥17 小时前
docker安装apisix
docker·容器·apisix
小飞侠在吗18 小时前
Windows 下 Nginx 访问 127.0.0.1 报 50x 错误:根因是路径里 \t 被当成 Tab
运维·windows·nginx
ylj_dev20 小时前
从 0 构建 AI Workload Platform(四):从单机工作流内核到可靠控制面
docker·postgresql·架构·golang
.柒宇.1 天前
使用 cri-docker 搭建 Kubernetes 集群完整教程(v1.36.3)
docker·容器·kubernetes·k8s集群安装
水饺编程1 天前
第5章,[Win32 章节] :贝塞尔样条曲线(一)
c语言·c++·windows·visual studio