第 6/18 天
引言

在前面五天里,我们完成了从 K8s 集群搭建、Harbor 私有镜像仓库部署、GitLab CE 代码托管平台安装到 GitLab Runner 的 K8s Executor 与 RBAC 权限配置。基础设施层已经就绪,今天我们将打通整个 DevOps 管道中最关键的一环——CI(持续集成)流水线。
CI 流水线的核心使命是:当开发者向代码仓库推送代码(或发起 Merge Request)时,系统能够自动完成代码检出、依赖安装、单元测试、镜像构建、镜像推送这一系列动作,无需任何人工干预。本篇将围绕 GitLab CI 的声明式配置文件 .gitlab-ci.yml 展开,并使用 Kaniko 这一无守护进程(daemonless)的镜像构建工具替代传统 Docker-in-Docker 方案,在 K8s Executor 环境下实现安全、高效、无特权的容器镜像构建与推送。
核心概念:GitLab CI 与 Kaniko
GitLab CI 工作模型
GitLab CI 采用声明式配置,所有流水线行为都定义在仓库根目录的 .gitlab-ci.yml 文件中。其核心概念包括:
- Pipeline(流水线):一次代码推送触发的完整构建流程,由多个阶段(Stage)组成
- Stage(阶段):流水线的逻辑分组,同一 Stage 内的 Job 并行执行,不同 Stage 之间串行
- Job(作业):最小执行单元,由
script中的一组 shell 命令构成 - Runner:执行 Job 的计算资源,我们已在第 5 天配置了 K8s Executor 类型的 Runner
为什么选择 Kaniko
传统容器镜像构建依赖 Docker 守护进程(dockerd),在 K8s Pod 中运行 Docker 需要 DinD(Docker-in-Docker)模式,这要求容器拥有 privileged: true 特权模式,带来严重的安全隐患:
- 特权容器可访问宿主机内核能力,存在容器逃逸风险
- DinD 需要额外运行 dockerd 进程,资源开销大
- 构建缓存管理复杂,跨 Job 难以共享
Kaniko 由 Google 开源,其工作原理是直接在非特权容器内解析 Dockerfile、逐条执行构建指令,最终将分层文件系统打包为镜像并推送到 Registry。整个过程不依赖任何守护进程,也不需要特权模式,天然契合 K8s Executor 的安全模型。
Kaniko 工作原理
# Kaniko 构建镜像的完整命令
/kaniko/executor
–context=git://github.com/myorg/myapp.git
–dockerfile=Dockerfile
–destination=registry.stellardata.top/myapp:$(git rev-parse –short HEAD)
–cache=true
–cache-repo=registry.stellardata.top/myapp/cache
Kaniko executor 接收三个核心参数:--context 指定构建上下文来源,--dockerfile 指定构建文件路径,--destination 指定目标镜像仓库地址。同时支持 --cache 启用分层缓存,大幅加速重复构建。
实战步骤:搭建完整 CI 流水线
步骤一:准备应用代码与 Dockerfile
首先在 GitLab 仓库中准备一个简单的 Go 应用及其 Dockerfile:
// main.go – 简单的 HTTP 服务
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello from StellarData DevOps Pipeline! Version: %s", os.Getenv("APP_VERSION"))
})
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
fmt.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
对应的 Dockerfile 采用多阶段构建,最小化最终镜像体积:
# Dockerfile – 多阶段构建
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp -ldflags="-s -w" main.go
FROM alpine:3.18
RUN apk add –no-cache ca-certificates
WORKDIR /app
COPY –from=builder /app/myapp .
ENV APP_VERSION=1.0.0
EXPOSE 8080
ENTRYPOINT ["./myapp"]
步骤二:编写 .gitlab-ci.yml
在仓库根目录创建 .gitlab-ci.yml,定义完整的流水线。这里采用 image 指定 Kaniko 官方镜像作为构建容器,通过变量复用 Harbor 仓库凭据:
# .gitlab-ci.yml – GitLab CI 流水线定义
stages:
– test
– build
– push
variables:
HARBOR_REGISTRY: "registry.stellardata.top"
IMAGE_NAME: "$HARBOR_REGISTRY/devops/myapp"
IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
# 单元测试阶段
unit-test:
stage: test
image: golang:1.21-alpine
script:
– go test -v -race -coverprofile=coverage.out ./…
– go tool cover -func=coverage.out
artifacts:
paths:
– coverage.out
expire_in: 1 week
rules:
– if: $CI_PIPELINE_SOURCE == "merge_request_event"
– if: $CI_COMMIT_BRANCH == "main"
# Kaniko 镜像构建与推送阶段
build-and-push:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
– mkdir -p /kaniko/.docker
– |
cat > /kaniko/.docker/config.json << EOF
{
"auths": {
"$HARBOR_REGISTRY": {
"username": "$HARBOR_USER",
"password": "$HARBOR_PASSWORD"
}
}
}
EOF
– >
/kaniko/executor
–context="$CI_PROJECT_DIR"
–dockerfile="Dockerfile"
–destination="$IMAGE_NAME:$IMAGE_TAG"
–destination="$IMAGE_NAME:latest"
–cache=true
–cache-repo="$HARBOR_REGISTRY/devops/cache"
–cache-ttl=24h
rules:
– if: $CI_COMMIT_BRANCH == "main"
步骤三:配置 Harbor 仓库凭据
在 GitLab 项目的 Settings → CI/CD → Variables 中,添加以下变量,确保流水线能够通过 Harbor 认证:
# 在 GitLab CI/CD Variables 中配置(类型为 Variable,勾选 Masked)
HARBOR_REGISTRY=registry.stellardata.top
HARBOR_USER=ci-robot
HARBOR_PASSWORD=<your-harbor-password-or-token>
注意:HARBOR_PASSWORD 务必勾选 Masked 选项,避免在日志中明文泄露。同时建议在 Harbor 中为 CI 创建专用的 Robot Account,授予对应项目的推送权限,而非使用管理员账号。
步骤四:配置 Runner 命名空间与 RBAC
回顾第 5 天的 Runner 配置,确保 Runner 所在命名空间对 Kaniko 镜像有拉取权限。如果 Harbor 仓库是私有仓库,需要预先创建 ImagePullSecret:
# 创建 Harbor 仓库登录凭据 Secret
kubectl create secret docker-registry harbor-credentials
–docker-server=registry.stellardata.top
–docker-username=ci-robot
–docker-password=<password>
–namespace=gitlab-runner
# 验证 Secret 创建成功
kubectl get secret harbor-credentials -n gitlab-runner -o yaml
步骤五:触发流水线并验证
代码推送至 main 分支后,GitLab 将自动触发流水线。可在 GitLab 项目的 CI/CD → Pipelines 页面查看执行状态。构建成功后,登录 Harbor 控制台即可看到推送的镜像:
# 查看 Harbor 仓库中的镜像
curl -u "ci-robot:<password>"
https://registry.stellardata.top/api/v2.0/projects/devops/repositories/myapp/artifacts
# 验证镜像 Tag
{
"name": "myapp",
"tags": [
{"name": "a3f5c2b", "size": 12451840},
{"name": "latest", "size": 12451840}
]
}
常见问题
Q1:Kaniko 构建报错 “no space left on device”
Kaniko 的工作目录位于容器内,构建大型镜像时会占用大量临时空间。K8s Executor 默认的临时存储配额可能不足。解决方法是在 .gitlab-ci.yml 中为 Job 挂载更大的 emptyDir,或在 Runner 的 ConfigMap 中调整 emptyDir.sizeLimit:
# 在 Runner ConfigMap 的 [runners.kubernetes] 段中配置
[runners.kubernetes]
ephemeral_storage_limit = "10Gi"
ephemeral_storage_request = "5Gi"
Q2:镜像推送 Harbor 报 401 Unauthorized
通常原因是 /kaniko/.docker/config.json 中的凭据配置错误,或 Harbor 的 Robot Account 权限不足。排查步骤:
- 确认 GitLab CI Variables 中的
HARBOR_USER和HARBOR_PASSWORD值正确 - 确认 Harbor 中该用户/Robot 对目标项目有
推送到仓库权限 - 在 Kaniko 命令前添加
cat /kaniko/.docker/config.json调试输出,确认 JSON 格式无误 - 注意 Harbor 如果启用了 OIDC,需要使用 Robot Account 的 Token 而非用户密码
Q3:构建缓存不生效,每次都全量构建
Kaniko 的缓存基于镜像分层哈希匹配。如果 Dockerfile 中频繁使用 COPY . . 且上下文文件变动较多,缓存命中率会很低。优化方法:
- 在
COPY . .之前先COPY go.mod go.sum并执行go mod download,让依赖下载层被缓存 - 使用
--cache-repo指定独立的缓存仓库 - 使用
--cache-ttl控制缓存有效期
总结
今天我们完成了 GitLab CI 流水线的搭建,掌握了以下要点:
- GitLab CI 的声明式配置模型:Pipeline → Stage → Job 三层结构
- Kaniko 无守护进程构建的核心优势:安全(无需特权)、高效(分层缓存)、云原生(契合 K8s)
.gitlab-ci.yml的完整编写:包含单元测试、镜像构建、镜像推送三个阶段- Harbor 凭据的安全管理:通过 GitLab CI Variables 注入,使用 Robot Account 降权
至此,从代码提交到镜像推送到 Harbor 的 CI 闭环已经打通。但这只是 DevOps 管道的前半段——镜像虽然构建出来了,但还没有部署到 K8s 集群。自动部署这一环需要 Argo CD 的 GitOps 能力来实现,这将在后续篇章中展开。
下期预告
明天我们将进入第 7 天:Harbor 镜像版本管理与 Tag 策略配置。当 CI 流水线不断推送大量镜像后,如何管理这些镜像的版本、如何制定合理的 Tag 策略、如何清理冗余镜像避免空间膨胀,都是生产环境必须解决的问题。敬请期待。
系列大纲
- 全链路架构总览:从代码提交到灰度发布的完整管道设计
- K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
- Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
- GitLab CE 自托管部署:代码仓库与项目管理平台
- GitLab Runner 配置:K8s Executor 与 RBAC 权限设置
- GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建(今天)
- Harbor 镜像版本管理与 Tag 策略配置
- Argo CD 部署与 GitOps 配置仓库创建
- CI 与 CD 联动:从代码提交到部署的全自动闭环
- Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
- Grafana 看板搭建:K8s 标准面板与自定义业务看板
- 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
- Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
- 金丝雀发布实战:setWeight 流量分割与 pause 步骤
- AnalysisTemplate 指标分析与自动回滚机制
- 全链路端到端演示:代码提交→构建→灰度→监控→告警完整流程
- 生产化加固要点:Harbor/GitLab/Argo CD 高可用方案
- 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

















暂无评论内容