痛点
在 CI/CD 流水线中构建容器镜像,传统方案是 Docker-in-Docker(DinD)或挂载宿主机 Docker Socket。两种做法都有硬伤:
- DinD:需要
--privileged特权模式,Pod 拥有宿主机几乎所有权限,一旦被攻破等同于节点沦陷 - 挂载 Socket:任何能访问
/var/run/docker.sock的容器都能操控宿主机上所有容器,安全审计直接红灯 - Kubernetes 1.24+ 已移除 dockershim:节点上可能根本没有 Docker Daemon,containerd/CRI-O 环境下 DinD 方案失效
生产环境需要一种 无特权、无 Daemon、纯用户态 的镜像构建方案。Kaniko 正是 Google 为此场景开源的工具。
方案
Kaniko 在容器内部以普通用户进程方式解析 Dockerfile,逐层构建镜像并推送到 Registry,全程 不依赖 Docker Daemon,不需要特权模式。
核心优势:
| 对比项 | DinD | Socket 挂载 | Kaniko |
|---|---|---|---|
| 需要特权模式 | ✅ | ❌(但等效危险) | ❌ |
| 依赖 Docker Daemon | ✅ | ✅ | ❌ |
| containerd 环境兼容 | ❌ | ❌ | ✅ |
| 安全隔离 | 差 | 差 | 好 |
| 缓存支持 | 本地 | 本地 | Registry 层级缓存 |
实操步骤
Step 1:准备 Registry 认证 Secret
Kaniko 构建完成后需要推送镜像到 Registry(Docker Hub、Harbor、ECR、GCR 等),先创建认证凭据:
# Docker Hub 示例
kubectl create secret docker-registry kaniko-secret \
--docker-server=https://index.docker.io/v1/ \
--docker-username=<your-user> \
--docker-password=<your-token> \
--docker-email=<your-email> \
-n ci
# AWS ECR 示例(使用 ecr-credential-helper 更优,此处给基础方案)
TOKEN=$(aws ecr get-login-password --region ap-northeast-1)
kubectl create secret docker-registry kaniko-ecr \
--docker-server=123456789.dkr.ecr.ap-northeast-1.amazonaws.com \
--docker-username=AWS \
--docker-password="$TOKEN" \
-n ci
Step 2:编写 Kaniko 构建 Pod
最简单的用法——一个一次性 Pod 完成构建+推送:
# kaniko-build-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: kaniko-build
namespace: ci
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=Dockerfile"
- "--context=git://github.com/your-org/your-app.git#refs/heads/main"
- "--destination=your-registry.com/your-app:v1.2.3"
- "--cache=true"
- "--cache-repo=your-registry.com/your-app/cache"
- "--snapshot-mode=redo"
- "--push-retry=3"
volumeMounts:
- name: kaniko-secret
mountPath: /kaniko/.docker
volumes:
- name: kaniko-secret
secret:
secretName: kaniko-secret
items:
- key: .dockerconfigjson
path: config.json
restartPolicy: Never
关键参数说明:
- --context:支持 git://、s3://、gs:// 以及本地路径
- --cache=true:启用 Registry 层级缓存,重复构建速度提升 50%-80%
- --snapshot-mode=redo:比默认 full 模式更快,适合大多数场景
- --push-retry:网络抖动时自动重试推送
kubectl apply -f kaniko-build-pod.yaml
kubectl logs -f kaniko-build -n ci
Step 3:集成到 CI/CD Pipeline(GitLab CI 示例)
# .gitlab-ci.yml
build_image:
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- |
cat > /kaniko/.docker/config.json << EOF
{
"auths": {
"${CI_REGISTRY}": {
"auth": "$(echo -n ${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD} | base64)"
}
}
}
EOF
- >
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"
--destination "${CI_REGISTRY_IMAGE}:latest"
--cache=true
--cache-repo="${CI_REGISTRY_IMAGE}/cache"
only:
- main
- tags
注意:使用
executor:debug镜像(带 shell),而非executor:latest(无 shell,只能用 args)。
Step 4:在 Tekton/Argo Workflows 中使用
# Tekton Task 片段
steps:
- name: build-and-push
image: gcr.io/kaniko-project/executor:latest
command:
- /kaniko/executor
args:
- --dockerfile=$(params.dockerfile)
- --context=$(workspaces.source.path)
- --destination=$(params.image):$(params.tag)
- --cache=true
- --compressed-caching=false
- --use-new-run
避坑指南
1. 构建上下文过大导致 OOM
Kaniko 会将整个 context 加载到内存。如果项目目录含大文件(日志、数据集),Pod 直接 OOMKilled。
解决方案:
# .dockerignore(必须配置)
.git
node_modules
*.log
data/
tests/
同时给 Pod 设合理的 resources.limits.memory,一般 2-4Gi 可覆盖大部分项目。
2. 多阶段构建缓存失效
Kaniko 的 --cache 只缓存最终镜像的层。多阶段构建(multi-stage)中间阶段默认不缓存。
解决方案:
/kaniko/executor \
--dockerfile=Dockerfile \
--destination=registry.com/app:latest \
--cache=true \
--cache-repo=registry.com/app/cache \
--cache-copy-layers # 缓存所有中间层
3. ECR Token 12 小时过期
AWS ECR 的认证 Token 有效期仅 12 小时,长时间运行的 CI 环境中 Secret 会失效。
解决方案:使用 ecr-credential-helper 或配合 CronJob 定时刷新 Secret:
# refresh-ecr-secret.sh(CronJob 每 6 小时执行)
#!/bin/bash
TOKEN=$(aws ecr get-login-password --region ap-northeast-1)
kubectl create secret docker-registry kaniko-ecr \
--docker-server=123456789.dkr.ecr.ap-northeast-1.amazonaws.com \
--docker-username=AWS \
--docker-password="$TOKEN" \
-n ci \
--dry-run=client -o yaml | kubectl apply -f -
性能优化技巧
- Registry 缓存 +
--compressed-caching=false:牺牲少量存储空间换取缓存读取速度提升 30%+ --use-new-run:使用优化后的文件系统快照算法,大项目构建提速 20%--single-snapshot:如果 Dockerfile 最后一层是大量文件复制,可合并快照减少开销- 并行构建:多微服务场景下,每个服务启一个 Kaniko Pod 并行构建,充分利用集群资源
总结
Kaniko 解决了 Kubernetes 环境中容器镜像构建的安全和兼容性问题:
- 安全:无特权、无 Daemon,满足 PSA(Pod Security Admission)restricted 策略
- 兼容:不依赖 Docker,在 containerd/CRI-O 节点上开箱即用
- 高效:Registry 层级缓存 + 快照优化,生产环境构建速度可接受
- 集成简单:支持所有主流 CI 系统(GitLab CI、GitHub Actions、Tekton、Argo Workflows、Jenkins)
如果你的集群已经升级到 Kubernetes 1.24+ 且启用了 Pod Security Standards,Kaniko 几乎是唯一的无痛镜像构建方案。建议配合 --cache + .dockerignore 优化后直接替换现有的 DinD 流水线。