第 15/60 天
引言
在 Kubernetes 原生 CI/CD 流水线中,构建容器镜像是一个核心环节。传统方式依赖 Docker daemon(需 docker build 命令),但在 Kubernetes 集群中运行 Docker daemon 存在诸多问题:
- 特权模式风险:Docker-in-Docker(DinD)需要 privileged 容器,带来严重安全隐患
- 存储开销:每个构建节点都需要完整的 Docker 镜像缓存
- 调度复杂:DaemonSet 部署模式占用集群资源,且与 Kubernetes 调度器存在竞争
kaniko 应运而生。它是 Google 开源的容器镜像构建工具,无需 Docker daemon,完全在用户空间运行,以非 root 方式构建镜像,天然适合 Kubernetes 和 Tekton 环境。
本文将从安装配置、YAML 编写、Harbor 集成、缓存优化、踩坑排除五个维度,手把手带你掌握 kaniko + Tekton 的镜像构建最佳实践。
核心概念
kaniko 的工作原理
| 组件 | 说明 |
|---|---|
| Executor | 核心构建器,解析 Dockerfile、逐层构建、推送镜像 |
| Warmer | 预热缓存器,提前拉取基础镜像加速构建 |
| 缓存机制 | 支持 registry 缓存和本地缓存两种模式 |
kaniko 的工作原理不依赖任何容器运行时 daemon,它通过以下方式实现镜像构建:
- 解析 Dockerfile:逐条解析
FROM、RUN、COPY等指令 - 逐层构建:在用户空间执行每条指令,生成新的文件系统快照
- 快照比对:利用
fsutil或proc文件系统比对文件变更 - 层提交:将变更打包为 OCI 镜像层,推送到远程仓库
为什么选择 kaniko 而非 DinD
| 对比项 | kaniko | DinD (Docker-in-Docker) |
|---|---|---|
| 特权模式 | 不需要 | 需要 --privileged |
| 安全风险 | 低(非 root 运行) | 高(宿主节点 root 权限) |
| Kubernetes 原生 | 天然支持 | 需额外配置容忍 |
| 缓存支持 | Registry 缓存、本地缓存 | Docker 层缓存 |
| 多架构构建 | 支持 --platform |
支持 |
| 镜像大小 | ~50MB | ~200MB+ |
实战步骤
1. 准备 kaniko 镜像
kaniko 官方提供 gcr.io 镜像,但国内环境建议使用镜像站或自建代理。推荐使用 gcr.io/kaniko-project/executor:v1.23.2 镜像。
注意:国内用户可将
gcr.io替换为gcr.dockerproxy.com或阿里云镜像加速。
2. 创建 Kubernetes Secret 用于 Harbor 认证
在 Tekton 中构建并推送镜像到 Harbor(或任何私有仓库),需要先创建 Docker Registry 凭据:
apiVersion: v1
kind: Secret
metadata:
name: harbor-registry-cred
namespace: tekton-pipelines
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>
创建命令:
# 使用 robot account 创建凭据
kubectl create secret docker-registry harbor-registry-cred
--docker-server=harbor.stellardata.top
--docker-username=robot$tekton-builder
--docker-password=<robot-account-token>
-n tekton-pipelines
关于 Harbor Robot Account 的详细配置,请参考第 21 天文章。
3. 编写 Tekton Task:kaniko 构建任务
以下是完整的 kaniko 构建 Task 定义:
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: kaniko-build
namespace: tekton-pipelines
spec:
description: >-
Build container image using kaniko (rootless) and push to Harbor registry.
params:
- name: IMAGE
description: Full image name including registry and tag
type: string
example: harbor.stellardata.top/library/my-app:v1.0.0
- name: DOCKERFILE
description: Path to Dockerfile within the source workspace
type: string
default: Dockerfile
- name: CONTEXT
description: Build context directory within the workspace
type: string
default: .
- name: EXTRA_ARGS
description: Additional kaniko flags
type: string
default: ""
- name: CACHE_REPO
description: Remote repository to cache intermediate layers
type: string
default: harbor.stellardata.top/library/cache
workspaces:
- name: source
description: Git repository source code
results:
- name: IMAGE_DIGEST
description: Digest of the built image
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:v1.23.2
args:
- --dockerfile=$(params.DOCKERFILE)
- --context=$(workspaces.source.path)/$(params.CONTEXT)
- --destination=$(params.IMAGE)
- --cache=true
- --cache-repo=$(params.CACHE_REPO)
- --registry-mirror=harbor.stellardata.top/mirror
- --skip-tls-verify=false
- --verbosity=info
- $(params.EXTRA_ARGS)
env:
- name: DOCKER_CONFIG
value: /builder/home/.docker
volumeMounts:
- name: docker-config
mountPath: /builder/home/.docker
volumes:
- name: docker-config
secret:
secretName: harbor-registry-cred
items:
- key: .dockerconfigjson
path: config.json
4. 创建 Pipeline:从源码到镜像
将 git clone 与 kaniko 构建串联成完整流水线:
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: gitops-build-pipeline
namespace: tekton-pipelines
spec:
params:
- name: GIT_REPO
type: string
description: Git repository URL
- name: GIT_REVISION
type: string
description: Git revision (branch/tag/commit)
default: main
- name: IMAGE_NAME
type: string
description: Image name (without tag)
- name: IMAGE_TAG
type: string
description: Image tag (e.g., v1.0.0 or commit-sha)
default: latest
workspaces:
- name: shared-workspace
description: Workspace shared between tasks
tasks:
- name: fetch-source
taskRef:
resolver: git
params:
- name: url
value: https://github.com/tektoncd/catalog.git
- name: path
value: task/git-clone/0.9/git-clone.yaml
- name: revision
value: main
params:
- name: url
value: $(params.GIT_REPO)
- name: revision
value: $(params.GIT_REVISION)
workspaces:
- name: output
workspace: shared-workspace
- name: build-image
taskRef:
name: kaniko-build
runAfter:
- fetch-source
params:
- name: IMAGE
value: "$(params.IMAGE_NAME):$(params.IMAGE_TAG)"
workspaces:
- name: source
workspace: shared-workspace
5. 运行 PipelineRun
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
name: my-service-build-run
namespace: tekton-pipelines
spec:
pipelineRef:
name: gitops-build-pipeline
params:
- name: GIT_REPO
value: https://git.stellardata.top/devops/my-service.git
- name: GIT_REVISION
value: main
- name: IMAGE_NAME
value: harbor.stellardata.top/devops/my-service
- name: IMAGE_TAG
value: v1.0.0-20260826
workspaces:
- name: shared-workspace
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
使用 tkn CLI 启动流水线:
# 创建 PipelineRun
tkn pipeline start gitops-build-pipeline
-p GIT_REPO=https://git.stellardata.top/devops/my-service.git
-p GIT_REVISION=main
-p IMAGE_NAME=harbor.stellardata.top/devops/my-service
-p IMAGE_TAG=v1.0.0-$(date +%Y%m%d)
-w name=shared-workspace,claimName=build-workspace-pvc
--showlog
# 查看构建日志
tkn pipelinerun logs my-service-build-run -f
6. 编写 Dockerfile 优化建议
kaniko 构建同样遵循 Docker 最佳实践,但有一些特殊优化点:
# 多阶段构建示例
# 第一阶段:编译
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .
# 第二阶段:运行(注意 kaniko 下使用最小基础镜像)
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /app/server /server
EXPOSE 8080
USER 1000:1000
ENTRYPOINT ["/server"]
对于 kaniko,建议使用
alpine或distroless基础镜像,避免在构建过程中生成大量临时文件,减少镜像层数。
7. 缓存配置优化
# 启用缓存时的参数说明
# --cache=true # 开启缓存
# --cache-repo=... # 缓存仓库地址
# --cache-ttl=240h # 缓存有效期(默认 2 周)
# --snapshot-mode=time # 快照模式:time(更快)或 full(更准确)
# --compression=gzip # 压缩方式(默认 gzip,可选 zstd)
# --use-new-run=/kaniko/executor # 使用新的 RUN 指令处理
# 预热缓存:在流水线前预先拉取基础镜像
docker run gcr.io/kaniko-project/warmer:v1.23.2
--image=golang:1.22-alpine
--image=alpine:3.20
--cache-dir=/cache
常见问题
Q1: kaniko 构建时出现 no space left on device
原因:kaniko 在 /tmp 和 /kaniko 目录构建临时文件,默认 PVC 空间不足。
解决:
– 确保 workspace 的 PVC 有足够空间(建议 5GB+)
– 在 Task 中设置 --cache-dir 到 workspace 挂载目录
– 清理旧构建缓存
# 在 Task 中添加临时目录挂载
workspaces:
- name: kaniko-cache
mountPath: /kaniko/.cache
Q2: 连接 Harbor 时出现 x509: certificate signed by unknown authority
原因:自签名证书未加入 kaniko 信任列表。
解决:通过 ConfigMap 挂载自定义 CA 证书:
# 创建 ConfigMap
kubectl create configmap custom-ca
--from-file=harbor-ca.crt=/path/to/harbor-ca.crt
-n tekton-pipelines
# 在 Task 中挂载
volumeMounts:
- name: custom-ca
mountPath: /kaniko/ssl/certs/ca-certificates.crt
subPath: harbor-ca.crt
Q3: kaniko 构建速度慢,没有缓存命中
原因:大多数 Dockerfile 指令变更导致缓存失效,或缓存仓库配置不正确。
解决:
– 将 COPY 指令放在 RUN apt-get 之后,最大化缓存命中
– 使用 .dockerignore 排除不必要的文件
– 检查 --cache-repo 的可访问性
– 考虑使用 --snapshot-mode=time 加快快照比对
Q4: 如何构建多架构镜像(arm64 + amd64)?
解决:kaniko 支持通过 --platform 参数构建多架构镜像:
# 并行构建不同架构
- name: build-amd64
args:
- --destination=harbor.stellardata.top/app/my-service:linux-amd64
- --platform=linux/amd64
- name: build-arm64
args:
- --destination=harbor.stellardata.top/app/my-service:linux-arm64
- --platform=linux/arm64
Q5: 构建 Java 应用时 kaniko 退出代码 137 被 OOM Kill
原因:Maven/Gradle 编译消耗大量内存,kaniko 默认内存限制不足。
解决:
– 增大 Task 的资源限制
– 使用多阶段构建,编译阶段在专门的高内存节点运行
resources:
requests:
memory: 2Gi
cpu: 1000m
limits:
memory: 4Gi
cpu: 2000m
总结
本文从零到一实现了 kaniko + Tekton 的容器镜像构建流水线,核心要点如下:
- kaniko 是 Kubernetes 原生镜像构建的最佳选择,无需 Docker daemon,安全且高效
- Tekton Task 封装使得 kaniko 构建参数化、可复用,配合 Pipeline 与 Git clone 串联形成完整 CI 流程
- Harbor 集成通过 dockerconfigjson Secret 和 Robot Account 实现自动化认证,安全合规
- 缓存优化是 kaniko 生产化部署的关键,合理配置
--cache-repo和构建顺序可大幅提升速度 - 多架构构建能力让 kaniko 在云原生异构环境中同样适用
下一篇文章将深入 Harbor 的安装与 HTTPS 配置,敬请期待第 16 天。















暂无评论内容