Kaniko:容器构建的灵活解决方案

Kaniko:容器构建的灵活解决方案

背景

在云原生时代,容器技术如Docker和容器编排系统如Kubernetes的广泛应用推动了应用程序交付的变革。容器镜像作为应用程序的构建和交付单元,成为了现代软件开发和部署的重要组成部分。而Docker作为目前最流行的容器技术之一,也提供了强大的构建工具Docker Build,用于构建Docker容器镜像。然而,Docker Build存在一些限制,特别是在某些场景下无法满足需求,例如在没有Docker守护进程的环境中进行构建。

为了解决这些限制和问题,Google开源了Kaniko项目,这是一个独立于Docker守护进程的容器镜像构建工具,它可以在任何支持OCI(Open Container Initiative)镜像格式的容器运行时中进行构建,而不需要特权或守护进程。

本文将介绍Kaniko的特点和优势,并演示如何在Kubernetes集群中使用Kaniko来构建容器镜像。

什么是Kaniko?

Kaniko 🔗是由Google开发的一个开源项目,它是一个容器镜像构建工具,可以在纯粹的用户态(user space)环境中执行容器镜像构建操作,无需Docker守护进程。Kaniko支持OCI镜像规范,并能够与任何OCI兼容的容器运行时(如containerd、CRI-O等)集成,从而实现容器镜像的构建和打包。Kaniko的主要优势在于:

  1. 无需Docker守护进程: 在Kaniko中,构建过程完全在容器中进行,无需依赖宿主机的Docker守护进程。这使得Kaniko能够在不支持Docker守护进程或需要限制特权的环境中运行,提高了构建的灵活性和安全性。
  2. OCI兼容: Kaniko遵循OCI(Open Container Initiative)镜像规范,能够构建符合OCI标准的容器镜像,与OCI兼容的容器运行时完美集成。
  3. 并行构建: Kaniko支持并行下载和构建镜像层,从而提高了构建效率,特别是在构建复杂多层镜像时表现更加出色。
  4. 镜像缓存: Kaniko支持镜像缓存,可以在多个构建之间重复使用相同的镜像层,从而减少构建时间和网络带宽消耗。

Kaniko的使用(docker环境)

步骤一:预拉取Kaniko镜像

Kaniko作为一个独立的容器镜像,可以直接从官方仓库中中获取。您可以通过以下命令来拉取Kaniko镜像:

docker pull gcr.io/kaniko-project/executor:latest

或者使用bitnami仓库中的镜像 🔗

docker pull docker.io/bitnami/kaniko:latest

步骤二:创建Dockerfile

在使用Kaniko构建镜像之前,首先需要准备一个Dockerfile,用于定义镜像的构建过程。可以根据项目需求自定义Dockerfile,指定所需的基础镜像、软件包、依赖项和应用程序等信息。

例如,以下是一个简单的Dockerfile示例:

FROM alpine:latest
RUN apk --no-cache add curl
CMD ["curl", "https://www.example.com"]

步骤三:使用Kaniko构建镜像

接下来,使用Kaniko镜像来执行构建操作。使用Kaniko的主要命令是/kaniko/executor,它接受一些参数来指定构建过程的详细信息。

在此之前请务必确保:

  • 已经登陆<registry>/<image>:<tag>的镜像仓库,且登陆信息已经保存到$HOME/.docker/config.json
  • Dockerfile文件保存在/root/lomtom目录下
docker run --rm -v /root/lomtom:/workspace \
    -v $HOME/.docker/:/kaniko/.docker \
    gcr.io/kaniko-project/executor:latest \
    --context=/workspace \
    --destination=<registry>/<image>:<tag>
  • -v /root/lomtom:/workspace:将本地工作目录映射到容器中的/workspace目录,用于存放构建上下文和Dockerfile,在/root/lomtom存放着上面的Dockerfile
  • -v $HOME/.docker/:/kaniko/.docker: 将主机的 Docker 配置目录(通常在用户主目录下的 ~/.docker/)挂载到容器的 /kaniko/.docker 目录。这是为了让 Kaniko 容器能够访问 Docker Hub 或其他私有 Docker 镜像仓库所需的 Docker 认证信息。更多认证方式可查看Kaniko的认证方式
  • --context=/workspace:指定构建的上下文路径,这是Dockerfile中所有文件和目录的根目录。
  • --destination=<registry>/<image>:<tag>:指定构建完成后生成的镜像的目标位置,即镜像仓库和标签。

日志:

INFO[0000] Retrieving image manifest alpine:latest      
INFO[0000] Retrieving image alpine:latest from registry index.docker.io 
INFO[0005] Built cross stage deps: map[]                
INFO[0005] Retrieving image manifest alpine:latest      
INFO[0005] Returning cached image manifest              
INFO[0005] Executing 0 build triggers                   
INFO[0005] Building stage 'alpine:latest' [idx: '0', base-idx: '-1'] 
INFO[0005] Unpacking rootfs as cmd RUN apk --no-cache add curl requires it. 
INFO[0014] RUN apk --no-cache add curl                  
INFO[0014] Initializing snapshotter ...                 
INFO[0014] Taking snapshot of full filesystem...        
INFO[0014] Cmd: /bin/sh                                 
INFO[0014] Args: [-c apk --no-cache add curl]           
INFO[0014] Running: [/bin/sh -c apk --no-cache add curl] 
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/community/x86_64/APKINDEX.tar.gz
(1/7) Installing ca-certificates (20230506-r0)
(2/7) Installing brotli-libs (1.0.9-r14)
(3/7) Installing libunistring (1.1-r1)
(4/7) Installing libidn2 (2.3.4-r1)
(5/7) Installing nghttp2-libs (1.55.1-r0)
(6/7) Installing libcurl (8.2.1-r0)
(7/7) Installing curl (8.2.1-r0)
Executing busybox-1.36.1-r0.trigger
Executing ca-certificates-20230506-r0.trigger
OK: 12 MiB in 22 packages
INFO[0281] Taking snapshot of full filesystem...        
INFO[0281] CMD ["curl", "https://www.example.com"]      
INFO[0281] Pushing image to swr.cn-east-3.myhuaweicloud.com/x-test/lomtom:temp2 
INFO[0287] Pushed swr.cn-east-3.myhuaweicloud.com/x-test/lomtom@sha256:2aeea24cd05697ce824f0f5a909d23326fd6a3b8e3b83d56125c7d60a08b0d5a

步骤四:确认完成构建

运行上述命令后,Kaniko将根据Dockerfile和构建上下文中的信息来执行构建操作。构建完成后,将在指定的目标位置生成镜像,您可以通过docker pull命令来获取该镜像。

docker pull <registry>/<image>:<tag>

至此,您已经成功使用Kaniko完成了容器镜像的构建。

Kaniko的使用(containerd.io环境)

步骤一:预拉取Kaniko镜像

containerddocker一样也可以通过命令行工具拉取镜像。您可以通过以下命令来拉取Kaniko镜像:

ctr images pull gcr.io/kaniko-project/executor:latest

或者使用bitnami仓库中的镜像 🔗

ctr images pull docker.io/bitnami/kaniko:latest

步骤二:创建Dockerfile

这里仍然以该Dockerfile为例:

FROM alpine:latest
RUN apk --no-cache add curl
CMD ["curl", "https://www.example.com"]

步骤三:使用Kaniko构建镜像

接下来,使用Kaniko镜像来执行构建操作。使用Kaniko的主要命令是/kaniko/executor,它接受一些参数来指定构建过程的详细信息。

在此之前请务必确保:

  • 已经登陆<registry>/<image>:<tag>的镜像仓库,且登陆信息已经保存到$HOME/.docker/config.json
  • Dockerfile文件保存在/root/lomtom目录下
ctr run --rm  \
	--net-host \
  --mount type=bind,src=/root/lomtom,dst=/workspace,options=rbind:rw    \
  --mount type=bind,src=$HOME/.docker,dst=/kaniko/.docker,options=rbind:rw    \
  gcr.io/kaniko-project/executor:latest  kaniko-executor \
  /kaniko/executor \
  --context=/workspace     \
  --destination=<registry>/<image>:<tag>
  • --net-host: 使用宿主机的网络命名空间,这样容器将共享宿主机的网络栈,可以访问宿主机网络。
  • --mount type=bind,src=/root/lomtom,dst=/workspace,options=rbind:rw: 将宿主机上的/root/lomtom目录绑定挂载到容器内部的/workspace目录,并使用rbind选项以递归方式将宿主机目录挂载到容器中,同时设置挂载的权限为读写。并且在/root/lomtom存放着上面的Dockerfile
  • --mount type=bind,src=$HOME/.docker,dst=/kaniko/.docker,options=rbind:rw: 将宿主机上的$HOME/.docker目录绑定挂载到容器内部的/kaniko/.docker目录,并使用rbind选项以递归方式将宿主机目录挂载到容器中,同时设置挂载的权限为读写。这是为了让 Kaniko 容器能够访问 Docker Hub 或其他私有 Docker 镜像仓库所需的 Docker 认证信息。更多认证方式可查看Kaniko的认证方式
  • /kaniko/executor:在Containerd中,它并不会像Docker引擎那样直接执行容器镜像中的ENTRYPOINTCMD指令,所以需要手动指定运行程序。
  • --context=/workspace:指定构建的上下文路径,这是Dockerfile中所有文件和目录的根目录。
  • --destination=<registry>/<image>:<tag>:指定构建完成后生成的镜像的目标位置,即镜像仓库和标签。

日志如下:

INFO[0000] Retrieving image manifest alpine:latest      
INFO[0000] Retrieving image alpine:latest from registry index.docker.io 
INFO[0006] Built cross stage deps: map[]                
INFO[0006] Retrieving image manifest alpine:latest      
INFO[0006] Returning cached image manifest              
INFO[0006] Executing 0 build triggers                   
INFO[0006] Building stage 'alpine:latest' [idx: '0', base-idx: '-1'] 
INFO[0006] Unpacking rootfs as cmd RUN apk --no-cache add curl requires it. 
INFO[0036] RUN apk --no-cache add curl                  
INFO[0036] Initializing snapshotter ...                 
INFO[0036] Taking snapshot of full filesystem...        
INFO[0037] Cmd: /bin/sh                                 
INFO[0037] Args: [-c apk --no-cache add curl]           
INFO[0037] Running: [/bin/sh -c apk --no-cache add curl] 
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.18/community/x86_64/APKINDEX.tar.gz
(1/7) Installing ca-certificates (20230506-r0)
(2/7) Installing brotli-libs (1.0.9-r14)
(3/7) Installing libunistring (1.1-r1)
(4/7) Installing libidn2 (2.3.4-r1)
(5/7) Installing nghttp2-libs (1.55.1-r0)
(6/7) Installing libcurl (8.2.1-r0)
(7/7) Installing curl (8.2.1-r0)
Executing busybox-1.36.1-r0.trigger
Executing ca-certificates-20230506-r0.trigger
OK: 12 MiB in 22 packages
INFO[0216] Taking snapshot of full filesystem...        
INFO[0216] CMD ["curl", "https://www.example.com"]      
INFO[0216] Pushing image to swr.cn-east-3.myhuaweicloud.com/x-test/lomtom:temp1
INFO[0221] Pushed swr.cn-east-3.myhuaweicloud.com/x-test/lomtom@sha256:9fa700b62e0df7775afc474128a88790367c471066bc426f561f134b4359e186

步骤四:确认完成构建

运行上述命令后,Kaniko将根据Dockerfile和构建上下文中的信息来执行构建操作。构建完成后,将在指定的目标位置生成镜像,您可以通过ctr images pull命令来获取该镜像。

ctr images pull <registry>/<image>:<tag>

至此,您已经成功使用Kaniko完成了容器镜像的构建。

Kaniko的认证方式

/kaniko/.docker 是Kaniko容器中的默认目录,用于存放Docker配置文件(config.json),这个配置文件包含Docker客户端的配置和认证信息。Kaniko是一个独立于Docker守护进程的容器镜像构建工具,因此无法直接使用主机上的Docker配置文件。为了让Kaniko能够访问和认证私有的Docker镜像仓库,您需要将Docker配置文件挂载到Kaniko容器中的/kaniko/.docker目录下。

默认情况下,Kaniko会在/kaniko/.docker目录中查找名为config.json的配置文件,以获取Docker客户端的配置信息。通过挂载这个配置文件,Kaniko可以获得登录私有Docker镜像仓库所需的认证凭据,从而能够安全地拉取和推送镜像。

Kaniko支持在不依赖Docker守护进程的情况下进行镜像构建,并且能够通过一些配置选项实现对Docker镜像仓库的认证。

以下是Kaniko进行认证的方法:

  1. Docker配置文件挂载:Kaniko支持将Docker配置文件挂载到容器内,从而实现对私有Docker镜像仓库的认证。您可以将包含身份验证凭据的Docker配置文件(config.json)挂载到Kaniko容器中的/kaniko/.docker目录。这样Kaniko就可以使用挂载的配置文件来获取登录凭据,以访问私有仓库。
# 假设您的Docker配置文件位于 /root/.docker/config.json
docker run -v /root/.docker/config.json:/kaniko/.docker/config.json gcr.io/kaniko-project/executor:latest \
  --dockerfile /root/Dockerfile \
  --destination your-registry/your-image:tag \
  --context /root/build/context
  1. Docker配置文件内容传递:您还可以将Docker配置文件的内容直接传递给Kaniko容器,而不是挂载整个文件。这可以通过将配置文件的内容作为环境变量传递给Kaniko容器来实现。
# 将Docker配置文件的内容传递给环境变量DOCKER_CONFIG,然后作为参数传递给Kaniko容器
DOCKER_CONFIG=$(cat /root/.docker/config.json)

docker run -e DOCKER_CONFIG=$DOCKER_CONFIG gcr.io/kaniko-project/executor:latest \
  --dockerfile /root/Dockerfile \
  --destination your-registry/your-image:tag \
  --context /root/build/context
  1. 使用镜像凭据文件:除了Docker配置文件,Kaniko还支持直接将镜像凭据文件传递给容器,以实现认证。通过--secret参数指定镜像凭据文件的路径,Kaniko将使用该文件中的凭据信息进行认证。
# 假设您有一个名为 image-creds.json 的镜像凭据文件
docker run -v /root/image-creds.json:/kaniko/secret/image-creds.json gcr.io/kaniko-project/executor:latest \
  --dockerfile /root/Dockerfile \
  --destination your-registry/your-image:tag \
  --context /root/build/context \
  --secret /kaniko/secret/image-creds.json

无论使用哪种方式,都可以实现对私有Docker镜像仓库的认证,确保Kaniko可以成功访问和推送镜像到私有仓库。请注意,在使用这些认证方法时,请确保对Docker镜像仓库的访问凭据是安全的,并且不会暴露敏感信息。

Kaniko缓存

Kaniko 提供了两种缓存模式:--cache--cache-repo

  1. --cache 缓存模式:该缓存模式用于在本地构建或与 Kubernetes 等环境结合构建时使用。在这个模式下,Kaniko 会尝试从之前构建的镜像中提取缓存。如果构建的上下文和 Dockerfile 没有发生变化,它会使用缓存来加速构建过程。但请注意,由于缓存是保存在本地的,因此在不同的机器或环境中构建时,缓存无法共享。
  2. --cache-repo 缓存模式:缓存模式适用于 CI/CD 等场景,可以在多个构建之间共享缓存,提高构建效率。在这个模式下,Kaniko 会将中间镜像层保存到指定的镜像仓库中。后续的构建任务可以从该仓库中提取缓存,避免重复构建相同的层。

使用缓存模式的命令示例:

# 使用 cache 缓存模式
docker run --rm \
  -v /root/lomtom:/workspace \
  -v /root/docker/config.json:/kaniko/.docker/config.json \
  gcr.io/kaniko-project/executor:latest \
  --context=/workspace \
  --cache=true \
  --cache-ttl=48h \
  --destination=docker.io/<username>/<image>:<tag>

# 使用 cache-repo 缓存模式
docker run --rm \
  -v /root/lomtom:/workspace \
  -v /root/docker/config.json:/kaniko/.docker/config.json \
  gcr.io/kaniko-project/executor:latest \
  --context=/workspace \
  --cache-repo=<cache-repo>/<image> \
  --destination=docker.io/<username>/<image>:<tag>

其中,--cache=true 表示启用缓存模式,--cache-ttl 可以设置缓存的有效期,--cache-repo 指定了缓存镜像的仓库地址。

Kaniko Vs Docker

Kaniko和Docker都是用于构建容器镜像的工具,但它们之间有一些重要的区别:

  1. 构建环境:
    • Docker:Docker构建镜像时,需要在主机上安装Docker引擎,因为Docker构建命令直接依赖于Docker引擎。
    • Kaniko:Kaniko是一个独立的容器镜像构建工具,它不依赖于Docker引擎或其他容器运行时。Kaniko可以在不同的容器环境中使用,包括不安装Docker引擎的环境。
  2. 构建过程:
    • Docker:Docker构建镜像时,将Dockerfile中的指令发送给Docker引擎,Docker引擎负责执行这些指令来构建镜像。构建过程在主机上执行,可能涉及到主机的权限和资源。
    • Kaniko:Kaniko将Dockerfile中的指令解析并在一个独立的容器中执行构建过程,而不是在主机上执行。这意味着Kaniko构建是隔离的,不需要主机的特权或访问主机的资源。
  3. 权限和安全性:
    • Docker:Docker构建镜像时,如果用户拥有足够的权限,可以访问主机上的文件和资源。这可能带来一些安全风险,特别是在CI/CD等自动化环境中。
    • Kaniko:Kaniko的构建过程在一个独立的容器中进行,不需要访问主机的文件和资源。这增加了构建的安全性,因为构建过程受到隔离并且不会访问主机的敏感信息。
  4. 镜像获取:
    • Docker:Docker构建完成后,镜像直接存储在Docker引擎中,并可以通过Docker命令进行访问和使用。
    • Kaniko:Kaniko构建完成后,镜像保存在指定的目标位置,例如Docker仓库或其他容器镜像仓库。您可以通过容器运行时(如Docker或Containerd.io)来获取和使用构建好的镜像。
  5. 构建上下文:
    • Docker:Docker构建镜像时,需要指定构建上下文,该上下文包含Dockerfile和构建所需的所有文件和目录。构建上下文会被发送到Docker引擎。
    • Kaniko:Kaniko构建镜像时,也需要指定构建上下文,但是该上下文是在Kaniko容器中解析和使用的,而不是发送给主机。

总的来说,Kaniko相比于Docker在构建容器镜像时更加灵活和安全,尤其适用于CI/CD等自动化环境,可以避免Docker引擎的直接访问和隔离性的问题。同时,Kaniko的独立性使得它可以在各种容器环境中使用,而不受Docker引擎的限制。

拓展

除了kaniko,社区中目前还有其他两款款工具可以支持无 docker daemon 化的构建:img 和 buildkit。

  1. img

img 🔗 是一个开源的、基于 Go 编写的命令行工具,用于在不需要 Docker 守护进程的情况下构建和管理 Docker 镜像。它旨在提供一个轻量级的替代方案,允许用户在不启动 Docker 守护进程的情况下执行镜像构建、层缓存和推送等操作。img 使用的是 BuildKit 的内部 API 来执行这些操作。

特点:

  • 无需 Docker 守护进程(Daemonless 模式): img 不需要运行 Docker 守护进程,这使得它更轻量、更适合 CI/CD 等环境。
  • 高效构建: 借助 BuildKit,img 可以执行高效的、并发的层缓存和构建操作。
  • OCI 镜像支持: img 可以构建符合 OCI(Open Container Initiative)标准的镜像,这些镜像可以被任何 OCI 兼容的容器运行时所使用。
  1. BuildKit

BuildKit 🔗 是 Docker 社区开发的一个高级镜像构建工具,它主要用于优化 Docker 镜像构建过程的性能和可维护性。BuildKit 可以使用 Docker CLI 或 Docker API 进行交互。与传统的 Docker 镜像构建方式相比,BuildKit 提供了更高的并发性、更好的缓存机制以及更高级的构建选项。

特点:

  • 并发构建: BuildKit 支持并发构建,可以在同一时间构建多个层,加速构建过程。
  • 缓存优化: BuildKit 的缓存机制更加智能,可以根据命令的不同部分进行缓存,从而提高层的重用率。
  • 无需 Docker 守护进程(Daemonless 模式): BuildKit 支持 Daemonless 模式,允许在不需要 Docker 守护进程的情况下构建镜像,提高效率。
  • 多平台构建: BuildKit 支持构建多个平台的镜像,例如 x86、ARM 等,可以在不同的体系结构上运行。

img 是一个特定于镜像构建的命令行工具,旨在提供一种无需 Docker 守护进程的构建方案,使用 BuildKit 的内部 API 进行操作。而 BuildKit 则是一个更为通用的镜像构建引擎,为 Docker 提供了高级的构建功能,包括高并发构建、智能缓存等。两者都旨在提升 Docker 镜像构建的性能和效率。

结论

Kaniko是一个强大的容器镜像构建工具,它在不依赖Docker守护进程的情况下实现了容器镜像的构建,具有较高的灵活性和安全性。通过并行构建和镜像缓存等特性,Kaniko能够高效地构建复杂的容器镜像,适用于各种构建场景和需求。因此,对于需要在Kubernetes集群中进行容器镜像构建的项目,Kaniko是一个值得考虑的优秀选择。您可以尝试使用Kaniko来提高构建效率并提升开发体验。

lomtom

标题:Kaniko:容器构建的灵活解决方案

作者:lomtom

链接:https://lomtom.cn/cihi7j5721g8z