如何构建 Kubernetes 所需的何使容器镜像?我想你答案肯定是 Docker,没错,集镜像Docker 确实是群中首选。我们在使用 Jenkins 进行 CI/CD构建容器镜像的构建时候,做法通常是容器将 Jenkins 服务部署在物理机上,然后使用物理机的何使 docker build 命令来构建镜像。但是集镜像在 Jenkins on K8s 环境下,Jenkins Master 和 Jenkins Slave 都以 Pod 形式运行在 Kubernetes 集群的群中 Node 上,我们的构建构建环境都是 Pod ,没有 docker 命令。容器
众所周知 Kubernetes 在 V1.24.x 版本之后默认采用 containerd 作为容器运行时,不再支持 Docker,我们想用宿主机上的 /var/run/docker.sock 也用不了了。我们就需要另一种方式在 Kubernetes 集群中构建容器镜像,本文将介绍 Kaniko工具。
Github地址:https://github.com/GoogleContainerTools/kaniko
Kaniko 是Google开源的一款在 Kubernetes 用来构建容器镜像的工具,它是一个从 Dockerfile 构建容器镜像的工具,就像 Docker 一样,但主要区别在于 Kaniko 可以在容器内运行,这意味着它可以在 Kubernetes 集群内运行。不需要特权模式,也不需要公开任何套接字。不需要在我们集群的节点上运行 Docker,因此我们使用哪个容器引擎来运行容器并不重要。重要的是 Kaniko 可以在容器内构建容器镜像,并在 Kubernetes 集群内自动构建,这就和宿主机上的 Docker 解绑了,更加安全可靠。特点如下:
现在,让我们一步一步来探索 Kaniko。
Kaniko 以容器的方式来运行的,同时需要三个参数: Dockerfile,上下文,以及远端镜像仓库的地址。
工作原理:
前提条件:
编写一个Dockerfile 文件,并创建configmap 在k8s中:
[root@localhost ~]# cat DockerfileFROM ubuntuENTRYPOINT ["/bin/bash", "-c", "echo hello"]
[root@localhost ~]# kubectl create configmap kaniko-dockerfile --from-file=./Dockerfileconfigmap/kaniko-dockerfile created
创建一个配置kaniko推送到 阿里云镜像仓库的凭证,找一台有安装docker的机子,登录仓库:
[root@localhost ~]# docker login --username=xxx registry.cn-shanghai.aliyuncs.comPassword:WARNING! Your password will be stored unencrypted in /root/.docker/config.json.Configure a credential helper to remove this warning. Seehttps://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
登入成功之后,会生成一个config.json的文件,使用该文件创建一个secret供kaniko容器使用。
[root@localhost ~]# kubectl create secret generic kaniko-secret --from-file=/root/.docker/config.jsonsecret/kaniko-secret created
kaniko_build_image.yaml:
apiVersion: v1kind: Podmetadata: name: kanikospec: containers: - name: kaniko image: gcr.io/kaniko-project/executor:latest args: ["--dockerfile=/workspace/Dockerfile", "--context=dir://workspace", "--destination=registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo:1.0"] # 替换成自己的仓库地址 volumeMounts: - name: kaniko-secret mountPath: /kaniko/.docker - name: dockerfile mountPath: /workspace volumes: - name: kaniko-secret secret: secretName: kaniko-secret items: - key: config.json path: config.json - name: dockerfile configMap: name: kaniko-dockerfile
创建pod,查看状态,并看log是否正常完成。
[root@localhost ~]# kubectl apply -f kaniko_build_image.yamlpod/kaniko created
[root@localhost ~]# kubectl get podNAME READY STATUS RESTARTS AGEkaniko 1/1 Running 0 3s [root@localhost ~]# kubectl logs -f kanikoINFO[0000] Retrieving image manifest ubuntu INFO[0000] Retrieving image ubuntu from registry index.docker.ioINFO[0003] Built cross stage deps: map[] INFO[0003] Retrieving image manifest ubuntu INFO[0003] Returning cached image manifest INFO[0003] Executing 0 build triggers INFO[0003] Building stage 'ubuntu' [idx: '0', base-idx: '-1']INFO[0003] Skipping unpacking as no commands require it.INFO[0003] ENTRYPOINT ["/bin/bash", "-c", "echo hello"]INFO[0003] Pushing image to registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo:1.0INFO[0004] Pushed registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo@sha256:d1855cc00550f9048c88b507626e0f24acf4c22e02856e006b2b9fdb0b80e567
查看阿里云镜像仓库已经上传上去了:
用kaniko生成的镜像来测试下是否可用:
[root@localhost ~]# docker run -it --rm registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo:1.0Unable to find image 'registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo:1.0' locally1.0: Pulling from kubesre02/kaniko-demo445a6a12be2b: Pull completeDigest: sha256:49bb962115b70a15a99b87e48fda28a883758081e41aef14766833d3a1578069Status: Downloaded newer image for registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko-demo:1.0hello
出来hello即成功。
官方 kaniko 镜像是基于 scratch 构建的,里面没有 shell,想在 kaniko 原生镜像里在调用 shell 命令是很麻烦的。所以我们可以自定义我们自己私有的 Kaniko 镜像。kaniko 的关键文件其实是/kaniko目录下的二进制文件,官方推荐是用 gcr.io/kaniko-project/executor 镜像,我们就可以拷贝这个/kaniko目录下的 executor 到我们自己的私有镜像 Dockerfile:
FROM gcr.io/kaniko-project/executor:latest AS plugin FROM ubuntu ENV DOCKER_CONFIG /kaniko/.docker COPY --from=plugin /kaniko/executor /usr/local/bin/kaniko RUN mkdir -p /kaniko/.docker/COPY config.json /kaniko/.docker/
上面 Dockerfile 构建了一个基于Ubuntu的Docker镜像:
(1) FROM gcr.io/kaniko-project/executor:latest AS plugin
(2) FROM ubuntu
接下来创建一个新的Docker镜像,基于官方的Ubuntu基础镜像。
(3) ENV DOCKER_CONFIG /kaniko/.docker
设置环境变量DOCKER_CONFIG为/kaniko/.docker,这是Kaniko工具使用的Docker配置目录。这是为了确保Kaniko可以找到必要的Docker配置信息。
(4) COPY --from=plugin /kaniko/executor /usr/local/bin/kaniko
从之前构建的plugin阶段的镜像中复制/kaniko/executor文件到新的镜像的/usr/local/bin/kaniko路径下。这将把Kaniko二进制文件复制到新的Ubuntu镜像中,以便后续在该镜像中使用。
(5) RUN mkdir -p /kaniko/.docker/
在新的镜像中创建/kaniko/.docker/目录,用于存放Docker配置文件。
(6) COPY config.json /kaniko/.docker/
将本地的config.json文件复制到新的镜像的/kaniko/.docker/目录下。这个config.json文件很可能包含了Docker仓库的认证信息和其他配置,以便Kaniko可以访问和推送Docker镜像。
最终,这个Docker镜像将包含了Ubuntu操作系统和Kaniko工具,并配置了Kaniko所需的Docker环境,使得可以在容器内使用Kaniko构建Docker镜像,并且有了 shell 环境,同时保持了一定程度的隔离性和安全性。构建并上传镜像:
[root@localhost ~]# docker build -t registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko:latest .Sending build context to Docker daemon 212.1MBStep 1/6 : FROM gcr.io/kaniko-project/executor:latest AS plugin ---> 03375da0f864Step 2/6 : FROM ubuntu ---> aa786d622bb0Step 3/6 : ENV DOCKER_CONFIG /kaniko/.docker ---> Using cache ---> f7cd726aa130Step 4/6 : COPY --from=plugin /kaniko/executor /usr/local/bin/kaniko ---> Using cache ---> 8fcac536196fStep 5/6 : RUN mkdir -p /kaniko/.docker/ ---> Using cache ---> 1afce75446a3Step 6/6 : COPY config.json /kaniko/.docker/ ---> Using cache ---> 4a2873a75a7cSuccessfully built 4a2873a75a7cSuccessfully tagged registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko:latest [root@localhost ~]# docker push registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko:latestThe push refers to repository [registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko]0cb4fb37580b: Pushedc9dbd3644e5a: Pushed33a2214b827c: Pushedc5077dd8160b: Pushed948c7f86fd48: Pushed403aab81b15b: Pushed7bff100f35cb: Pushedlatest: digest: sha256:b5642885f1333a757625cbe36a9b1102aba27646f2572acab79861a74dba1050 size: 1783
更多参考 官方:https://github.com/GoogleContainerTools/kaniko#additional-flags
--cache-copy-layers 此参数在执行命令之前 kaniko 会检查层的缓存,如果存在 kaniko将拉取并提取缓存层,而不是执行命令。如果没有 kaniko将执行命令,然后将新创建的层推送到缓存。用户可以通过设置 --cache=true 参数决定是否启用缓存,并且可以通过--cache-repo 标志提供用于存储缓存层的远程存储库,如果未提供此标志则将从提供的 –destination 推断缓存的repo。通常 --cache=true --cache-copy-layers=true 这两个参数同时使用。
jenkins pipline 中使用:
基于 Kubernetes 的 动态生成 Jenkins Slave pod CI/CD,以下是一个简化的Pipeline示例:
// 镜像仓库地址def registry = "registry.cn-shanghai.aliyuncs.com/kubesre02/demo" pipeline { agent { kubernetes { yaml """kind: Podmetadata: name: kanikospec: containers: - name: kaniko # 使用自定义的 kaniko 镜像 image: registry.cn-shanghai.aliyuncs.com/kubesre02/kaniko:latest imagePullPolicy: Always command: - cat tty: true""" } } stages { stage('拉代码') { steps { git clone ... } } stage('构建镜像') { steps { // 使用 kaniko 来构建镜像 container(name: 'kaniko') { Dockerfile 内容... sh "kaniko -f Dockerfile -c ./ -d $registry:$BUILD_NUMBER --force" } } } stage('部署') { steps { 部署... } } }}
可以看出,Kaniko 是非常适合在Kubernetes平台上构建容器镜像的,而且易于集成到 DevOps Jenkins pipeline 里,好了,kaniko 就介绍到这里。
责任编辑:赵宁宁 来源: 云原生运维圈 Kubernetes(责任编辑:时尚)