使用 Kaniko来构建镜像
Kaniko 是一种专注于容器镜像构建的开源工具,其核心设计理念与 Docker 存在显著差异。以下从功能定位、技术实现和适用场景三方面进行对比分析:
一、Kaniko 的核心特性
- 无需 Docker 守护进程
Kaniko 直接在容器或 Kubernetes 集群中运行,完全脱离 Docker 守护进程(Docker Daemon)。这种设计通过消除对特权模式的依赖,提升了安全性和资源利用率。 - 基于用户空间的构建流程
它会逐行解析 Dockerfile,提取基础镜像文件系统,并在用户空间内执行每条指令,通过快照比对生成镜像层,最后推送至镜像仓库。此过程避免了传统 Docker 构建中的权限依赖。 - 云原生场景优化
专为 Kubernetes 和 CI/CD 流水线设计,支持通过 Secret 挂载凭证,可直接集成到 Jenkins 等工具中,实现自动化构建。
二、与 Docker 的主要区别
对比维度 | Kaniko | Docker |
---|---|---|
架构依赖 | 无需 Docker Daemon,独立运行于容器环境 | 依赖 Docker Daemon 执行构建任务 |
安全性 | 容器隔离构建,避免挂载宿主机敏感文件 | 需挂载 /var/run/docker.sock ,存在特权风险 |
适用环境 | Kubernetes、无 Docker 环境的云原生场景 | 本地开发环境、传统 Docker 宿主机 |
构建效率 | 并行构建技术缩短时间,但受网络/缓存影响 | 本地构建速度快,但集群场景需额外配置 |
镜像推送 | 强制要求构建后推送至远程仓库 | 支持本地存储或手动推送 |
三、典型使用场景建议
- Kubernetes 集群内构建
当宿主机未安装 Docker 或需避免特权模式时(如 Kubernetes v1.24+ 默认使用 containerd),Kaniko 是更安全的选择。 - 高安全要求的 CI/CD 流水线
在 Jenkins 等工具中,通过 Pod 模板调用 Kaniko,可避免暴露宿主机 Docker 套接字,符合安全合规要求。 - 多平台镜像构建
支持--platform
参数指定目标架构(如linux/amd64
),适合跨平台交付场景。
四、性能注意事项
尽管 Kaniko 具备并行构建优势,但实际速度可能受基础镜像拉取延迟、缓存配置(如 --cache-repo
参数优化)和上下文传输方式(如 GCS/S3 存储桶)影响,需结合网络环境调优。
五、Kaniko的优势
Kaniko作为一个创新的容器镜像构建工具,在云原生时代提供了显著的优势,特别是在高效且灵活的容器镜像构建方面。以下是Kaniko的主要优势:
无守护进程构建
Kaniko无需Docker守护进程即可独立运行,这不仅节省了资源,还提高了构建效率。这种设计使得Kaniko在资源有限的环境中也能高效工作,特别是在Kubernetes集群或容器环境中。
安全隔离
Kaniko在单独的容器中执行构建,与宿主机系统隔离,从而增强了安全性。这种隔离机制可以有效防止潜在的安全威胁影响到宿主系统。
构建速度快
Kaniko使用并行构建技术,显著缩短了构建时间。这意味着用户可以在短时间内完成复杂的构建任务,节省宝贵的时间。
高度可定制
Kaniko允许用户定制构建过程,包括添加自定义脚本和修改构建环境,以满足特定的需求。这种灵活性使得Kaniko能够满足不同项目和环境的多样化需求。
易于集成
Kaniko可以轻松集成到CI/CD流水线中,实现自动构建和部署。这使得Kaniko成为持续集成和持续部署流程中的重要组成部分,提高了开发和部署的自动化水平。
在Kubernetes环境中的应用
Kaniko非常适合在Kubernetes环境中构建镜像,可以无缝集成,简化镜像构建和部署。这种集成方式不仅提高了效率,还增加了系统的可靠性。
对云原生应用的支持
Kaniko是云原生应用镜像构建的理想选择,可快速构建和部署,满足敏捷开发的要求。这种快速构建和部署的能力使得Kaniko在云原生应用的开发和运维中发挥着重要作用。
微服务架构的支持
Kaniko也适用于微服务架构的镜像构建,可独立构建每个微服务,实现高效的开发和部署。这种支持使得Kaniko在微服务架构的推广和应用中具有重要意义。
未来前景
随着云原生应用和微服务架构的发展,Kaniko的作用将越来越重要,成为构建容器镜像的标准工具,为开发者提供更快速、更安全、更定制化的构建体验。
综上所述,Kaniko以其无守护进程构建、安全隔离、快速构建、高度可定制、易于集成等优势,在容器镜像构建领域占据了重要地位,特别是在云原生和微服务架构的应用中,Kaniko展现出了巨大的潜力和价值。
kaniko 使用命令常用参数
说一下 kaniko 的使用 ,参数 其实和docker build 类似,需要知道 上下文 context
,dockerfile
的位置信息, destination
构建镜像完成后 要推送的地址 ,skip-tls-verify
跳过检查 https 以及配置缓存相关的。
// 构建镜像
def buildImage(Map config) {def kanikoCommand = '/usr/local/bin/executor ' +"--context dir://${config.WORKSPACE} " +"--dockerfile ${config.WORKSPACE}/Dockerfile " +"--destination ${config.IMAGE_TAG} " +'--skip-tls-verify ' +'--verbosity=info ' +'--cache=true ' +"--cache-repo ${config.DOCKER_REGISTRY}/cache-repo/${config.IMAGE_NAME} " +'--cache-ttl=168h ' +'--cache-dir=/kaniko/.cache 'echo "Building Docker image for ${config.envType} environment with Kaniko"try {echo "Current working directory: ${pwd()}"container('kaniko') {sh '''/usr/local/bin/executor version'''sh "${kanikoCommand}"}} catch (err) {error "Failed to build Docker image: ${err}"}
}
创建秘钥
配置 kaniko
使用 Docker 注册表凭证
kubectl create secret docker-registry regcred \--namespace=dev \--docker-server=172.19.89.106:12300 \--docker-username=admin \--docker-password=xxxxxxxxxx
这个命令是用来在 Kubernetes 集群中创建一个名为 regcred
的 Docker registry 类型的 Secret。这个 Secret 用于存储访问私有 Docker registry 所需的认证信息,以便 Kubernetes 能够拉取私有仓库中的镜像。具体来说,该命令的作用如下:
-
kubectl create secret docker-registry regcred
: 使用kubectl
命令行工具创建一个类型为docker-registry
的 Secret。regcred
是这个 Secret 的名称,您可以在需要引用此 Secret 时使用这个名字。 -
--namespace=dev
: 指定这个 Secret 应该被创建在哪个命名空间(namespace)中。这里指定的是dev
命名空间。Kubernetes 中的资源是按命名空间来组织的,这有助于对不同环境或团队的资源进行隔离。 -
--docker-server=172.19.89.106:12300
: 指定 Docker registry 的服务器地址。在这个例子中,它是一个位于172.19.89.106
的私有 Docker registry,并且监听着12300
端口。 -
--docker-username=admin
: 指定用于登录 Docker registry 的用户名。这里是admin
。 -
--docker-password=xxxxxxxxxx
: 指定与上述用户名关联的密码。这里是xxxxxxxxxx
。
创建了这个 Secret 后,您可以在 Pod 或其他 Kubernetes 资源定义中引用它,以确保 Kubernetes 在尝试从指定的 Docker registry 拉取镜像时能够提供正确的认证信息。例如,在 Pod 的定义中,您可以添加 imagePullSecrets
字段,并将 regcred
作为值之一,这样 Kubernetes 就知道使用这个 Secret 来获取必要的认证凭据。
kubectl get secret regcred -n dev -o yamlapiVersion: v1
data:.dockerconfigjson: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxp7InVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6ImFkbWluNzMxIiwiYXV0aCI6IllXUnRhVzQ2WVdSdGFXNDNNekU9In19fQ==
kind: Secret
metadata:creationTimestamp: "2025-04-10T06:29:02Z"name: regcrednamespace: devresourceVersion: "58990830"uid: f50b2868-1a0f-46e1-88c1-a8bc70c119b1
type: kubernetes.io/dockerconfigjson
在Pipeline 中的一个Stage 中
stage('Build CODE') {steps {script {String branchName = params.BRANCHString envType = params.ENVecho """\Build CODE:WORKSPACE: ${WORKSPACE}envType: ${envType}branchName: ${branchName}""".stripIndent()sh 'ls -al'/* groovylint-disable-next-line VariableTypeRequired */def String gitSha = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()def String currentDate = sh(returnStdout: true, script: 'date +%Y%m%d').trim()// 设置 IMAGE_TAG 环境变量 动态传值/* groovylint-disable-next-line LineLength */env.IMAGE_TAG = "${DOCKER_REGISTRY}/${IMAGE_NAME}/${SHORT_NAME}:${branchName}-${currentDate}-${gitSha}"// 打印 image tagecho "current tag: ${env.IMAGE_TAG}"// 构建镜像 和推送镜像buildImage([envType: envType,branchName: branchName,WORKSPACE: WORKSPACE,IMAGE_TAG: env.IMAGE_TAG,DOCKER_REGISTRY: DOCKER_REGISTRY,IMAGE_NAME: IMAGE_NAME,SHORT_NAME: SHORT_NAME])}}
}
#!/bin/bash # 重新打tag
docker tag gcr.io/kaniko-project/executor:v1.23.0 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0docker login -uadmin -padmin-xxxxx-xxxx 172.19.89.106:12300docker push 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0
把官方镜像 推送的私有仓库。 这个镜像 一旦开始启动 就停止了,不像其他镜像 可以一直常驻在前台,可以理解为 一次性容器我想在容器起来之后 ,根据需要 创建我的容器镜像 tag ,需要根据 时间或者分支名 组合生成,而不是传入一个destination 定义固定的值。
比如上面的例子中:TAG 生成逻辑,当前分支,当前日志,以及git提交的hash值
/* groovylint-disable-next-line VariableTypeRequired */
def String gitSha = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
def String currentDate = sh(returnStdout: true, script: 'date +%Y%m%d').trim()// 设置 IMAGE_TAG 环境变量 动态传值
/* groovylint-disable-next-line LineLength */
env.IMAGE_TAG = "${DOCKER_REGISTRY}/${IMAGE_NAME}/${SHORT_NAME}:${branchName}-${currentDate}-${gitSha}"
// 打印 image tag
echo "current tag: ${env.IMAGE_TAG}"
官方镜像改造
我对官方的镜像 进行了一点点改造
# 第一阶段:使用 kaniko 构建应用
FROM 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0 AS builder
# FROM gcr.io/kaniko-project/executor:v1.23.0 AS builder# 第二阶段:使用一个适合运行时环境的基础镜像
FROM alpine:latest# 安装 busybox
RUN apk add --no-cache busybox# 创建一个符号链接,使得 /bin/sh 指向 busybox 的 sh
RUN ln -sf /bin/busybox /bin/sh# 从第一阶段复制 /kaniko/executor 到第二阶段
COPY --from=builder /kaniko/executor /usr/local/bin/executor
COPY --from=builder /kaniko/executor /kaniko/executor
# 将 /usr/local/bin 添加到 PATH(如果它还没有在 PATH 中)
ENV PATH=/kaniko:/usr/local/bin:$PATH# 设置默认的 ENTRYPOINT 和 CMD
ENTRYPOINT ["/usr/local/bin/executor"]CMD ["--help"]
# 重新构建镜像
docker build . -t 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0-v1# 保存镜像 到文件
docker save -o executor-v1.tar 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0-v1# 加载镜像
docker load -i executor.tar# 推送到 私有仓库中
docker push 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0-v1
这样的好处 这样镜像中有了 sh
环境, 在启动容器的 时候, 我就可以通过
- name: kanikoimage: 172.19.89.106:12300/library/kaniko-project/executor:v1.23.0-v1imagePullPolicy: IfNotPresentcommand: ["/bin/sh"]args: ["-c", "tail -f /dev/null"] # 保持容器运行env:- name: DOCKER_CONFIG # 这个配置指向该卷来传递凭证value: /home/jenkins/agent/.dockervolumeMounts:- name: docker-configmountPath: /home/jenkins/agent/.docker- name: workspace-volumemountPath: /home/jenkins/agent- name: kaniko-cache # kaniko 缓存相关mountPath: /kaniko/.cachesecurityContext:runAsUser: 0resources:requests:memory: "1Gi" # 根据实际需求调整cpu: "500m" # 根据实际需求调整limits:memory: "2Gi"cpu: "1000m"volumes:- name: workspace-volumeemptyDir: {}- name: docker-configsecret:secretName: regcreditems:- key: .dockerconfigjsonpath: config.json- name: kaniko-cachepersistentVolumeClaim:claimName: kaniko-cache-pvc
把docker-config 挂载到 /home/jenkins/agent/.docker
这个目录下面,kanio 就可以有权限来推送镜像了。
通过tail -f
让容器 一直运行状态,之后 我需要执行构建镜像的时候 传入 镜像的名称即可。
六、Q&A : Kaniko 构建完成后 会自动推送镜像吗?
A: Kaniko
在构建完成后会自动推送镜像到指定的 Docker 注册表。这是 Kaniko
的一个关键特性之一,它不仅负责构建 Docker 镜像,还会将构建好的镜像推送到你指定的目标仓库。
是的,Kaniko
在构建完成后会自动推送镜像到指定的 Docker 注册表。这是 Kaniko
的一个关键特性之一,它不仅负责构建 Docker 镜像,还会将构建好的镜像推送到你指定的目标仓库。
具体工作原理
- 构建镜像:
Kaniko
会读取Dockerfile
并按照其中的指令逐层构建镜像。 - 推送镜像:在构建完成后,
Kaniko
会直接将构建好的镜像推送到你通过--destination
参数指定的 Docker 注册表。这个过程不需要与 Docker 守护进程交互,也不需要挂载 Docker Socket。
如何确保 Kaniko
推送镜像
为了确保 Kaniko
能够成功推送镜像,你需要满足以下条件:
-
提供有效的 Docker 注册表凭证:
Kaniko
需要访问 Docker 注册表的权限,因此你必须提供有效的用户名和密码(或令牌)。这通常通过 Kubernetes Secret 来实现。- 在 Jenkins Pipeline 中,我们通过挂载
docker-config
卷并将DOCKER_CONFIG
环境变量指向该卷来传递凭证。
-
正确设置
--destination
参数:-
--destination
参数指定了目标镜像的完整路径,包括注册表地址、仓库名称和标签。例如:--destination 172.19.89.106:12300/zhiexa-web-official/web-official:master-20241210-fd880b6
-
确保这个路径是正确的,并且你有权限推送镜像到该位置。
-
-
网络连接:
Kaniko
需要能够访问 Docker 注册表的网络地址。确保你的 Kubernetes 集群中的 Pod 可以访问外部网络或私有注册表的地址。
示例命令
在 Jenkins Pipeline 中,Kaniko
的调用命令如下:
sh """/kaniko/executor \--context dir://${WORKSPACE} \--dockerfile ${WORKSPACE}/Dockerfile \--destination ${env.IMAGE_TAG} \--build-arg BUILD_ENV=${envType}
"""
在这个命令中:
--context
指定了构建上下文的路径,通常是代码库的根目录。--dockerfile
指定了Dockerfile
的路径。--destination
指定了目标镜像的完整路径,Kaniko
会在构建完成后将镜像推送到这个位置。--build-arg
用于传递构建时的参数(如BUILD_ENV
)。
验证推送是否成功
你可以通过以下方式验证 Kaniko
是否成功推送了镜像:
-
日志输出:
Kaniko
会在控制台输出详细的构建和推送日志。如果你看到类似以下的日志,说明推送成功:Pushing layer sha256:xxxxxxxxxxxxx Pushing manifest for 172.19.89.106:12300/zhiexa-web-official/web-official:master-20241210-fd880b6 Successfully pushed 172.19.89.106:12300/zhiexa-web-official/web-official:master-20241210-fd880b6
-
检查注册表:你也可以手动登录到 Docker 注册表,查看是否已经有新镜像被推送。
注意事项
- 私有注册表:如果你使用的是私有 Docker 注册表,确保你已经正确配置了凭证,并且
Kaniko
有权限推送镜像。 - 防火墙和网络策略:确保 Kubernetes 集群中的网络策略允许 Pod 访问 Docker 注册表的地址。
- 镜像标签:确保你为镜像设置了唯一的标签(如基于 Git 提交哈希或构建时间),以避免覆盖旧版本的镜像。
总结
Kaniko
在构建完成后会自动推送镜像到指定的 Docker 注册表,而无需额外的推送步骤。只要确保提供了正确的凭证和网络访问权限,Kaniko
就可以顺利完成构建和推送任务。Kaniko 是不需要 Docker Daemon
比较适合K8S 环境来构建镜像。
参考文档
kanio github