境搭建 GitLab CI/CD 流水線)
Windows Docker 環(huán)境搭建 GitLab CI/CD 流水線從零到一的完整實踐引言GitLab CI/CD 是持續(xù)集成與持續(xù)部署工具之一。它天然集成在 GitLab 代碼倉庫中無需額外搭建 Jenkins 等第三方 CI 平臺開箱即用。本文將記錄在 Windows 環(huán)境下使用 Docker 部署 GitLab 和 GitLab Runner并成功跑通一條完整 CI/CD 流水線的全過程包括環(huán)境搭建、原理剖析、踩坑與解決希望能為同樣在 Windows 上進行 DevOps 實踐的開發(fā)者提供一份可復(fù)用的參考。一、環(huán)境準備1.1 基礎(chǔ)環(huán)境操作系統(tǒng)WindowsDocker Desktop 運行于 WSL 2 后端容器運行時Docker Desktop目標技術(shù)棧Java Maven 多模塊項目1.2 部署 GitLab 服務(wù)端使用 Docker 一鍵拉起 GitLab CE 社區(qū)版容器dockerrun-d--namegitlab\--shm-size1g\-p8012:8012\-eGITLAB_OMNIBUS_CONFIGexternal_url http://host.docker.internal:8012;\gitlab/gitlab-ce:latest關(guān)鍵參數(shù)說明--shm-size1g增加共享內(nèi)存大小避免 GitLab 運行時因內(nèi)存不足而崩潰。-p 8012:8012將容器內(nèi) 8012 端口映射到宿主機 8012 端口此處將默認的 80 端口改為 8012。external_url設(shè)置 GitLab 的外部訪問地址。host.docker.internal是 Docker Desktop 在 Windows/Mac 下提供的特殊域名容器內(nèi)可通過它訪問宿主機Linux 下需要額外配置或改用宿主機 IP。示例中未掛載數(shù)據(jù)卷生產(chǎn)環(huán)境需要掛載。完整部署流程可參考《使用 Docker 部署 GitLab》。1.3 部署 GitLab RunnerRunner 是 GitLab CI/CD 的執(zhí)行引擎負責(zé)拉取并執(zhí)行流水線任務(wù)。dockerrun-d--namegitlab-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 容器內(nèi)。在 Windows 下//var/run/docker.sock實際對應(yīng) Windows 命名管道\\.\pipe\docker_engine。該掛載讓 Runner 容器內(nèi)的 Docker 客戶端能夠與宿主機 Docker 守護進程通信從而啟動 CI/CD 任務(wù)容器。Linux 下可直接使用-v /var/run/docker.sock:/var/run/docker.sock。1.4 注冊 Runnerdockerexec-itgitlab-runner gitlab-runner register\--non-interactive\--urlhttp://host.docker.internal:8012\--registration-token xxxx\--descriptionlocal-docker-runner\--executordocker\--docker-image maven:3.9-eclipse-temurin-17-alpine\--docker-pull-policy if-not-present參數(shù)說明--non-interactive非交互式注冊通過命令行一次性完成配置。--url http://host.docker.internal:8012指定 GitLab 服務(wù)器地址。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-runnerRunner 的描述性名稱便于在后臺識別。--executor docker使用 Docker 執(zhí)行器每個 CI Job 會啟動一個全新的 Docker 容器運行結(jié)束后銷毀。--docker-image maven:3.9-eclipse-temurin-17-alpine默認基礎(chǔ)鏡像包含 Maven 3.9 和 Java 17。--docker-pull-policy if-not-present鏡像拉取策略優(yōu)先使用本地鏡像本地不存在時才從 Docker Hub 拉取可顯著加快本地流水線速度。二、GitLab CI/CD 核心原理2.1 Runner 的工作機制拉取而非推送在項目根目錄下編寫.gitlab-ci.yml文件定義流水線。代碼推送到 GitLab 后GitLab 解析該文件并生成任務(wù)放入隊列。Runner 主動輪詢 GitLab 服務(wù)器每隔幾秒向 GitLab API 發(fā)送請求詢問是否有待執(zhí)行任務(wù)。若有則領(lǐng)取并執(zhí)行否則繼續(xù)等待。這種拉取模式的優(yōu)勢在于Runner 可部署在內(nèi)網(wǎng)無需 GitLab 主動穿透防火墻。GitLab 短暫重啟后Runner 可在下一輪詢周期自動重試。2.2 Docker 執(zhí)行器的工作流程當 Runner 領(lǐng)取到一個 Job 后Docker 執(zhí)行器按以下步驟執(zhí)行準備階段創(chuàng)建并啟動所需的服務(wù)容器。預(yù)作業(yè)階段克隆代碼倉庫、恢復(fù)緩存、下載前一階段的制品。作業(yè)階段在用戶指定的 Docker 鏡像中執(zhí)行構(gòu)建腳本如mvn package。后作業(yè)階段創(chuàng)建緩存、上傳制品到 GitLab。Runner 通過數(shù)據(jù)卷掛載將代碼目錄共享給 Job 容器。三、流水線配置實戰(zhàn)3.1 多階段流水線設(shè)計將流水線拆分為編譯、測試、打包、部署四個階段實現(xiàn)完整鏈路。stages:-compile-test-package-deployvariables:MAVEN_OPTS:-Dmaven.repo.local$CI_PROJECT_DIR/.m2cache:key:maven-cachepaths:-.m2/compile:stage:compileimage:maven:3.9-eclipse-temurin-17-alpinescript:-mvn clean compileartifacts:paths:-**/target/classes/-**/target/generated-sources/# 如有代碼生成器expire_in:1 daytest:stage:testimage:maven:3.9-eclipse-temurin-17-alpinescript:-mvn testdependencies:-compileartifacts:when:alwaysreports:junit:**/target/surefire-reports/TEST-*.xmlpaths:-**/target/surefire-reports/expire_in:6 dayspackage:stage:packageimage:maven:3.9-eclipse-temurin-17-alpinescript:-mvn package-DskipTestsdependencies:-compile-testartifacts:paths:-**/target/*.jar-**/target/*.warexpire_in:1 weekrules:-if:$CI_COMMIT_BRANCH masterdeploy:stage:deployimage:maven:3.9-eclipse-temurin-17-alpinescript:-echo 開始部署當前構(gòu)建產(chǎn)物...-ls-la app/target/*.jar# 實際部署命令示例# - scp **/target/*.jar userserver:/deploy/path/# - mvn deploy -DskipTestsdependencies:-packagerules:-if:$CI_COMMIT_BRANCH master說明代碼推送到 GitLab 倉庫或發(fā)起合并請求時會觸發(fā) CI/CD 流水線。示例中僅master分支執(zhí)行打包和部署。四、踩坑實錄與解決方案問題一Runner 注冊成功但 Job 執(zhí)行時無法訪問宿主機 Docker1.現(xiàn)象Runner 注冊正常但實際運行 Job 時報錯。ERROR: Failed to remove network for build errornetworksManager 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 容器內(nèi)需要 Unix socket 文件但默認路徑下沒有可用的 socket因為啟動 Runner 容器時未掛載宿主機 socket。3.解決啟動 Runner 容器時掛載 Docker socket。Windows Docker Desktop 下推薦寫法-v//var/run/docker.sock:/var/run/docker.sock注意 Windows 路徑開頭使用雙斜杠//避免被 shell 或 Docker CLI 轉(zhuǎn)義。問題二無法下載鏡像文件1.現(xiàn)象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-alpine2.原因Runner 通過宿主機 Docker 啟動 Job 容器時無法從 Docker Hub 下載 Maven 鏡像。3.解決先通過鏡像加速站或代理將鏡像下載到本地然后在注冊 Runner 時添加--docker-pull-policy if-not-present優(yōu)先使用本地鏡像默認always, 筆者使用的docker鏡像網(wǎng)站為https://docker.aityp.com/。若 Runner 已注冊可修改其配置文件dockercpgitlab-runner:/etc/gitlab-runner/config.toml config.toml編輯config.toml在[runners.docker]段中添加或修改[runners.docker] image maven:3.9-eclipse-temurin-17-alpine pull_policy if-not-present保存后復(fù)制回容器并重啟dockercpconfig.toml gitlab-runner:/etc/gitlab-runner/config.tomldockerrestart gitlab-runner問題三Runner 注冊成功但 Job 執(zhí)行時無法從 GitLab 拉取代碼1.現(xiàn)象Runner 執(zhí)行 Job 時無法拉取代碼因為 GitLab 生成的倉庫地址不可達。2.原因GitLab 啟動時使用了external_url http://localhost:8012該地址僅對宿主機有效Runner 容器無法通過localhost訪問 GitLab。3.解決方案一重新構(gòu)建 GitLab 容器將external_url改為容器可識別的宿主機地址-eGITLAB_OMNIBUS_CONFIGexternal_url http://host.docker.internal:8012;方案二進入 GitLab 容器編輯/etc/gitlab/gitlab.rb修改external_urlhttp://host.docker.internal:8012然后重新配置并重啟gitlab-ctl reconfigure gitlab-ctl restart問題四多模塊項目 Artifacts 上傳失敗1.現(xiàn)象mvn package構(gòu)建成功但artifacts上傳時報錯WARNING: target/*.jar: no matching files2.原因項目為 Maven 多模塊結(jié)構(gòu)JAR 包生成在子模塊目錄中例如app/target/app-0.1.0-SNAPSHOT.jar。而artifacts配置的target/*.jar只匹配根目錄下的target/。3.解決使用遞歸通配符**/target/*.jar匹配所有層級子目錄中的 JAR 包。同樣編譯階段的target/classes/也應(yīng)改為**/target/classes/。artifacts:paths:-**/target/*.jar五、進階模擬 Merge Request 流程基礎(chǔ)流水線跑通后模擬真實的 MR 協(xié)作流程創(chuàng)建功能分支git checkout -b dev提交代碼git push origin dev發(fā)起 MR在 GitLab 網(wǎng)頁端創(chuàng)建從dev到master的合并請求自動觸發(fā)流水線MR 創(chuàng)建后GitLab 自動針對源分支運行 CI 流水線合并后自動部署MR 合并入master后觸發(fā)deploy階段完成自動部署MR 不僅是合并代碼的入口更是質(zhì)量卡點通過 CI 流水線自動驗證代碼質(zhì)量避免問題代碼進入主分支。六、總結(jié)與展望通過本次實踐從零開始在 Windows 環(huán)境下搭建了一套完整的 GitLab CI/CD 系統(tǒng)核心收獲包括Runner 采用拉取模式主動輪詢 GitLab 領(lǐng)取任務(wù)。Docker 執(zhí)行器的作業(yè)流程為準備 → 預(yù)作業(yè)克隆代碼、恢復(fù)緩存→ 作業(yè)執(zhí)行構(gòu)建→ 后作業(yè)上傳制品。Windows 下 Docker 套接字的特殊寫法//var/run/docker.sock對應(yīng)命名管道\\.\pipe\docker_engine。多模塊項目應(yīng)使用遞歸通配符**/target/*.jar匹配子模塊制品。后續(xù)可探索的方向包括使用 Kubernetes 執(zhí)行器實現(xiàn) Runner 彈性伸縮、配置分布式緩存支持多 Runner 共享依賴、集成安全掃描實現(xiàn) DevSecOps。希望這份實踐記錄能為你的 GitLab CI/CD 實踐提供幫助。如遇到問題歡迎在評論區(qū)交流討論。愿你我都能在各自的領(lǐng)域里不斷成長勇敢追求夢想同時也保持對世界的好奇與善意!