GitLab CI/CD 集成 Harbor 全面教程

你不只是要把镜像推上仓库,你要的是一套可审计、可复用、易维护的流水线。从管理员的实例级集成,到 Runner 构建方式、项目级 .gitlab-ci.yml 模板、安全合规、缓存加速和故障排查,这篇教程帮你把全链路打通。


环境与目标

  • 目标: 代码提交后自动构建镜像并推送到 Harbor,支持版本追踪、缓存加速与安全策略。
  • 组件:
    • GitLab: 14+(CE/EE,或 GitLab.com
    • GitLab Runner: 14+,Docker executor 或 Kubernetes executor
    • Harbor: 2.5+,启用 HTTPS
    • 构建器: Docker(DIND/BuildKit)或 Kaniko(K8s)
  • 网络/证书:
    • HTTPS: 生产必须;Runner/开发机需信任 Harbor CA
    • 连通性: Runner 能访问 Harbor;GitLab 能访问 Runner

管理员配置实例级 Harbor 集成

集中管理凭据,避免每个项目都手工维护账号密码。

管理后台设置

  • 进入管理员区域: Admin Area → Settings → Integrations(部分版本在 Settings → Network → Container Registry)
  • 添加 Registry:
  • Harbor 准备:
    • 项目: 创建 my-project,默认私有
    • 机器人账号: 绑定到该项目,权限最小化(Push)
  • 变量注入(如版本不支持自动注入则在 Group/Project 级创建):
    • CI_REGISTRY = harbor.example.com
    • CI_REGISTRY_USER = robot$gitlab-ci
    • CI_REGISTRY_PASSWORD = <robot token>

提示:机器人账号比通用用户更安全,便于轮换和审计。


Runner 与构建方式选择

不同构建器在安全性、性能和兼容性上存在取舍。

对比与建议

  • Docker-in-Docker(DIND)
    • 优点: 通用、易上手
    • 缺点: 需要 privileged;缓存持久化差
    • 适用: 快速落地、小团队或非高敏场景
  • BuildKit(buildx)
    • 优点: 更快、优秀缓存、多平台构建
    • 缺点: 需配置 buildx;对旧镜像源兼容需验证
    • 适用: 生产推荐,尤其追求速度与多架构
  • Kaniko(K8s)
    • 优点: 无需 Docker 守护进程,安全、云原生
    • 缺点: 少量 Dockerfile 特性兼容性需评估
    • 适用: Kubernetes Runner 或禁用特权环境

Docker executor 安装与注册

  • 安装 Runner:

    bash 复制代码
    curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
    sudo apt -y install gitlab-runner
  • 注册 Runner:

    bash 复制代码
    sudo gitlab-runner register
    # 选择 executor: docker
    # 填默认镜像: docker:24.0
  • config.toml(DIND 示例)

    toml 复制代码
    [[runners]]
      name = "docker-dind-runner"
      executor = "docker"
      [runners.docker]
        image = "docker:24.0"
        privileged = true
        tls_verify = false
        volumes = [
          "/cache",
          "/etc/docker/certs.d:/etc/docker/certs.d:ro" # 注入 Harbor CA 证书
        ]
        shm_size = 0
    • 证书注入: 将 Harbor CA 放入 Runner 节点 /etc/docker/certs.d/harbor.example.com/ca.crt,并挂载给作业容器。

项目级 CI/CD 模板

根据 Runner 环境选择一套模板即可使用。镜像命名采用"项目/应用:标签"。

模板 A:DIND(通用)

yaml 复制代码
stages:
  - build
  - push

services:
  - name: docker:24.0-dind
    command: ["--mtu=1450"] # 云环境常用;可删除

variables:
  DOCKER_HOST: tcp://docker:2375
  IMAGE_REGISTRY: $CI_REGISTRY
  IMAGE_REPO: my-project/my-app
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA
  CACHE_REF: "$IMAGE_REGISTRY/$IMAGE_REPO:buildcache"

before_script:
  - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"

build:
  stage: build
  image: docker:24.0
  script:
    - docker pull "$CACHE_REF" || true
    - docker build \
        --cache-from "$CACHE_REF" \
        -t "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" \
        -t "$IMAGE_REGISTRY/$IMAGE_REPO:latest" .
    - docker tag "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" "$CACHE_REF"

push:
  stage: push
  image: docker:24.0
  script:
    - docker push "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG"
    - docker push "$IMAGE_REGISTRY/$IMAGE_REPO:latest"
    - docker push "$CACHE_REF" || true

模板 B:BuildKit(更快,多平台)

yaml 复制代码
stages: [push]

variables:
  DOCKER_BUILDKIT: "1"
  IMAGE_REGISTRY: $CI_REGISTRY
  IMAGE_REPO: my-project/my-app
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

push:
  stage: push
  image: docker:24.0
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
    - docker run --privileged --rm tonistiigi/binfmt --install all || true
    - docker buildx create --use --name builder || docker buildx use builder
  script:
    - docker buildx build \
        --platform linux/amd64 \
        --tag "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" \
        --tag "$IMAGE_REGISTRY/$IMAGE_REPO:latest" \
        --push \
        --cache-to type=registry,ref="$IMAGE_REGISTRY/$IMAGE_REPO:buildcache",mode=max \
        --cache-from type=registry,ref="$IMAGE_REGISTRY/$IMAGE_REPO:buildcache" \
        .

模板 C:Kaniko(K8s 无特权)

yaml 复制代码
stages: [push]

variables:
  IMAGE_REGISTRY: $CI_REGISTRY
  IMAGE_REPO: my-project/my-app
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

push:
  stage: push
  image:
    name: gcr.io/kaniko-project/executor:latest
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - |
      cat > /kaniko/.docker/config.json <<EOF
      { "auths": { "${CI_REGISTRY}": { "username": "${CI_REGISTRY_USER}", "password": "${CI_REGISTRY_PASSWORD}" } } }
      EOF
    - /kaniko/executor \
        --dockerfile=Dockerfile \
        --context="$CI_PROJECT_DIR" \
        --destination="$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" \
        --destination="$IMAGE_REGISTRY/$IMAGE_REPO:latest"

Harbor 端最佳实践

  • 项目与命名:
    • 命名规范: project/app,避免顶层 library 滥用。
    • 标签策略:latest 表示"当前主分支",用 vX.Y.Z 标记版本,用 commit_sha 追溯构建。
  • 机器人账号:
    • 最小权限: 仅对指定项目授予 Push;不同环境分账号,便于隔离。
    • 轮换: token 定期更换;在 GitLab 变量使用 masked + protected。
  • 安全与质量:
    • 漏洞扫描: 启用 Trivy,高危阻断(在流水线或 Harbor policy)。
    • 镜像签名: 结合 Cosign/Notary v2;在部署阶段验签。
  • 复制同步:
    • 跨站点: Harbor 间配置 replication,提高就近拉取性能。

证书与网络

  • 客户端信任 Harbor:
    • Docker 客户端: /etc/docker/certs.d/harbor.example.com/ca.crt
    • Runner 节点: 相同路径,并挂载给作业容器/DIND 服务。
  • 自签名开发环境:
    • 可用,但生产建议正式证书。
  • Insecure Registry(不推荐):
    • 在 Runner 的 Docker daemon.json 配置 insecure-registries 后重启;仅在受控内网临时使用。

常见故障与直击要点

  • 登录 401
    • 核查: 机器人账号是否绑定项目并具备 Push;变量拼写;Harbor 域名/端口一致。
  • 证书 x509
    • 核查: 证书链完整;CA 放置路径正确;DIND 服务也要注入证书。
  • push denied
    • 核查: 仓库路径 project/app 是否存在;项目私有与权限配置是否正确。
  • Runner 不支持特权
    • 解决: 改用 BuildKit/ Kaniko;避免 privileged = true
  • 缓存不生效
    • 建议: 固化缓存镜像名;优化 Dockerfile 层(先拷贝清单文件再安装依赖)。
  • 多架构失败
    • 解决: 先安装 binfmt;确保基础镜像支持目标平台。

合规与加速建议

  • 合规门禁:
    • 分支策略:mainlatest;仅 tag 推 v*;MR 合并前构建但不推正式标签。
    • SBOM: 用 Syft 生成 SBOM 并存档;安全审计可追溯。
  • 构建加速:
    • 镜像缓存: BuildKit --cache-to/--cache-from 指向 Harbor。
    • 依赖代理: NPM/PIP/Maven 配企业代理;减少外网开销。

最小可用清单(复制即用)

  • CI/CD 变量(组/项目级)

  • DIND 简版 .gitlab-ci.yml

    yaml 复制代码
    stages: [build, push]
    services: [docker:24.0-dind]
    variables:
      DOCKER_HOST: tcp://docker:2375
      IMAGE_REGISTRY: $CI_REGISTRY
      IMAGE_REPO: my-project/my-app
      IMAGE_TAG: $CI_COMMIT_SHORT_SHA
    before_script:
      - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
    build:
      stage: build
      image: docker:24.0
      script:
        - docker build -t "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" -t "$IMAGE_REGISTRY/$IMAGE_REPO:latest" .
    push:
      stage: push
      image: docker:24.0
      script:
        - docker push "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG"
        - docker push "$IMAGE_REGISTRY/$IMAGE_REPO:latest"
相关推荐
雪碧聊技术2 小时前
gitLab如何新建分支(根据某个分支)
gitlab·new branch·新建分支
测试-鹏哥4 小时前
要将ITP集成到Jenkins Pipeline中,实现开发发版时自动触发自动化测试
运维·python·测试工具·ci/cd·jenkins
字节逆旅19 小时前
如何解决代码冲突
gitlab
林晓lx1 天前
使用Git钩子+ husky + lint语法检查提高前端项目代码质量
前端·git·gitlab·源代码管理
wangruofeng1 天前
为 CI/CD 装上“眼睛”:App 包大小监控的实践
ci/cd·架构
爱宇阳1 天前
从容器化到自动化:Vue3 项目 Docker 部署与 GitLab CI/CD 集成 Harbor 全流程
docker·自动化·gitlab
爱宇阳1 天前
Spring Boot 项目 GitLab CI/CD 自动构建并推送到 Harbor 教程
spring boot·ci/cd·gitlab
佐杰1 天前
持续集成与持续部署
ci/cd
一念一花一世界1 天前
Argo CD vs Tekton vs Arbess,CI/CD工具一文纵评
ci/cd·tekton·argo cd·arbess