一文带你玩转Kaniko从此不用docker build

9,110 阅读5分钟

一、快速介绍

什么是Kaniko

kaniko 是一个在容器或 Kubernetes 集群内从 Dockerfile 构建容器镜像的工具 ( Build Container Images In Kubernetes );官方一共提供了两个镜像,分别是:

  • gcr.io/kaniko-project/executor:executor (该镜像基于 scratch,不包含 shell)
  • gcr.io/kaniko-project/executor:debug (该镜像由kaniko executor镜像和一个 busybox shell 组成,主要用于)

为啥用Kaniko

  • 由于 kaniko 不依赖于 Docker 守护进程,并且可以在用户空间中执行 Dockerfile 中的每个命令,这使得能够在轻松并且安全地运行在无Docker守护程序的环境(如标准Kubernetes集群 V1.24.x)中构建容器镜像。
  • 在 Kubernetes V1.24.x 版本之后默认采用 containerd.io 作为缺省的cri,不再支持 docker-shim 意味着我们不需要安装 docker 环境

二、Kaniko工作原理

Kaniko 是如何工作的

kaniko.png

  1. 读取并解析指定的Dockerfile
  2. 提取基础镜像的文件系统(Dockerfile 中的 FROM 镜像)
  3. 在独立的Dockerfile中分别运行每个命令
  4. 每次运行后都会对用户空间文件系统的做快照
  5. 每次运行时,将快照层附加到基础层并更新镜像元数据
  6. 最后推送镜像

Kaniko已知功能问题

  • kaniko 不支持构建 Windows 容器。
  • kaniko 不支持 v1 Registry API。(由于其不安全性当前基本都是使用V2协议, 例如 Harbor)
  • 不支持在官方 kaniko 镜像以外的任何 Docker 镜像中运行 kaniko(这包括将 kaniko 可执行文件从官方镜像复制到另一个镜像中)

Kaniko 支持的存储解决方案

kaniko 的构建上下文和发送 Docker 守护程序以进行镜像构建的构建上下文非常相似;它代表一个包含 Dockerfile 的目录,kaniko 将使用它来构建镜像。

例如, Dockerfile 中的 COPY 命令应该引用构建上下文中的文件, 所以需要将构建上下文存储在 kaniko 可以访问的位置。

目前kaniko 支持以下存储解决方案:

  • GCS Bucket
  • S3 Bucket
  • Azure Blob Storage
  • Local Directory
  • Local Tar
  • Standard Input
  • Git Repository

运行 kaniko 时,使用 --context 带有适当前缀的标志指定构建上下文的位置, 如果不指定前缀 kaniko 将假定一个本地目录, 该参数可用值:

SourcePrefixExample注意
Local Directorydir://[path to a directory in the kaniko container]dir:///workspace此选项是指 kaniko 容器内的目录。如果希望使用此选项,则需要在构建上下文中将其作为目录挂载到容器中。
Local Tar Gztar://[path to a .tar.gz in the kaniko container]tar://path/to/context.tar.gz此选项指的是 kaniko 容器中的 tar gz文件。如果希望使用此选项,则需要在构建上下文中将其作为文件挂载到容器中。
Standard Inputtar://[stdin]tar://stdinkaniko 允许的唯一标准输入是.tar.gz格式,如果要创建压缩 tar,可以运行tar -C -zcvf context.tar.gz命令。
GCS Bucketgs://[bucket name]/[path to .tar.gz]gs://kaniko-bucket/path/to/context.tar.gz如果使用 GCS 或 S3 存储桶,首先需要创建构建上下文的压缩 tar 并将其上传到存储桶。运行后,kaniko 将在开始镜像构建之前下载并解压构建上下文的压缩 tar。
S3 Buckets3://[bucket name]/[path to .tar.gz]s3://kaniko-bucket/path/to/context.tar.gz
Azure Blob Storagehttps://[account].[azureblobhostsuffix]/[container]/[path to .tar.gz]myaccount.blob.core.windows.net/container/p…
Git Repositorygit://[repository url][#reference][#commit-id]git://github.com/acme/myproject.git#refs/heads/mybranch#仅支持此种格式,http的那种不支持。

Kaniko 缓存构建

1.Caching Layers :kaniko 可以在远程存储库中缓存由RUN(由flag--cache-RUN-layers配置)和COPY(由flag--cache-COPY-layeers配置)命令创建的层。

在执行命令之前 kaniko 会检查层的缓存,如果存在 kaniko将拉取并提取缓存层,而不是执行命令。如果没有 kaniko将执行命令,然后将新创建的层推送到缓存。

用户可以通过设置 --cache=true 标志选择缓存,并且可以通过--cache-repo 标志提供用于存储缓存层的远程存储库, 如果未提供此标志则将从提供的--destination推断缓存的repo。

在缓存未命中后,kaniko无法从缓存中找到读取层,所有后续层都将在本地构建,而无需咨询缓存。

2.Caching Base Images: kaniko 可以将镜像缓存在本地目录中,该目录可以卷装载到KanikoPod中。为此必须首先填充缓存, 我们在 gcr.io/kaniko-project/warmer 提供了一个kaniko缓存预热镜像:

--image : 指定所需任意数量的镜像, 填充缓存后 使用与上述相同的 --cache=true 标志选择缓存, 本地缓存的位置通过 --cache-dir 标志提供,默认为 /cache 与缓存预热器一样, 在实践中通常与 Kubernetes 集群和持久缓存卷一起使用。

示例:

docker run -v $(pwd):/workspace gcr.io/kaniko-project/warmer:latest --cache-dir=/workspace/cache --image=<image to cache> --image=<another image to cache>

Kaniko参数

  • --build-arg:构建参数,类似于 Docker可以配置多个
  • --cache:--cache=true选择使用 kaniko 进行缓存
  • --cache-dir:以指定基本镜像的本地目录缓存,默认为 /cache;注意:必须和--cache一起使用
  • --cache-repo:指定将用于存储缓存层的远程存储库;如果未指定将从--destination中推算出存储库;列:如果--destination=gcr.io/kaniko-project/test,则缓存层将存储在gcr.io/kaniko-project/test/cache
  • --cache-copy-layers:缓存copy层
  • --cache-run-layers:缓存run层
  • --cache-ttl duration:以小时为单位的缓存超时。默认为两周
  • --cleanup:在构建结束时清理文件系统
  • --compressed-caching:将此设置为 false 以防止对缓存层进行 tar 压缩。这将增加构建的运行时间,但会减少内存使用量,尤其是对于大型构建。--compressed-caching=false如果您的构建因内存不足错误而失败,请尝试使用。默认为真。
  • --context-sub-path:当上下文是一个 git 存储库,并且想要构建其子文件夹之一而不是根文件夹时,它特别有用
  • --customPlatform:允许使用主机以外的另一个默认平台进行构建,类似于 docker build --platform xxx 该值必须在 form 上 --customPlatform=linux/arm,可接受的值列在此处:  GOOS/GOARCH。也可以指定 CPU ,将其添加为第三个参数(如 --customPlatform=linux/arm/v5);注意:这种指定cpu的方式只能用于arm架构;由于 OCI 镜像规范的限制,生成的镜像无法提供有关 CPU 的任何元数据;注意:这不是虚拟化,无法帮助构建构建主机本身不支持的架构;例如,这用于在 amd64 主机上构建 i386,或在 arm64 主机上构建 arm32。
  • --digest-file:设置此标志以指定容器中的文件;该文件将接收构建镜像的摘要,这可用于自动跟踪 kaniko 构建的确切镜像;例如,将标志设置为--digest-file=/dev/termination-log会将摘要写入该文件,Kubernetes 会自动将其拾取为 {{.state.terminated.message}}容器的摘要。
  • --dockerfile:要构建的 dockerfile 的路径。(默认“Dockerfile”)
  • --force:强制在容器外构建
  • --git:如果构建上下文是 git 存储库,则要克隆的分支(默认 branch=,single-branch=false,recurse-submodules=false)
  • --image-name-with-digest-file:指定一个文件来保存带有构建镜像摘要的镜像名称
  • --image-name-tag-with-digest-file:指定一个文件来保存带有镜像标签和构建镜像摘要的镜像名称。
  • --insecure:如果您想将镜像推送到纯 HTTP 注册表,请设置此标志。它应该仅用于测试目的,不应在生产中使用!
  • --insecure-pull:如果你想从普通的 HTTP 注册表中提取镜像,请设置此标志。它应该仅用于测试目的,不应在生产中使用!
  • --insecure-registry:您可以设置--insecure-registry 为在访问指定注册表时使用纯 HTTP 请求。它应该仅用于测试目的,不应在生产中使用!您可以为多个注册表多次设置它。
  • --label:设置此标志以--label key=value将一些元数据设置为最终镜像。这等同于LABEL在 Dockerfile 中使用。
  • --log-format:设置此标志以--log-format=设置日志格式;默认为color。
  • --log-timestamp:将此标志设置为--log-timestamp=将时间戳添加到 日志格式;默认为false。
  • --no-push:只构建镜像不推送
  • --oci-layout-path:设置此标志以指定容器中的目录,其中将放置构建镜像的 OCI 镜像布局。这可用于自动跟踪 kaniko 构建的确切镜像;例如,要显示在 Tekton 任务中构建的镜像摘要,应设置此标志以匹配镜像资源outputImageDir; 注意:根据构建的镜像,镜像清单的媒体类型可能是application/vnd.oci.image.manifest.v1+json或application/vnd.docker.distribution.manifest.v2+json。
  • --push-retry:将此标志设置为将镜像推送到远程目标时应该发生的重试次数;默认为0。
  • --registry-certificate:设置此标志可为与给定注册表的 TLS 通信提供证书;预期格式是my.registry.url=/path/to/the/certificate.cert。
  • --registry-mirror:如果您想使用注册表镜像而不是默认镜像,请设置此标志 index.docker.io;如果你想设置多个镜像,你可以多次使用这个标志;如果在第一个镜像上找不到镜像,Kaniko 将尝试下一个镜像,并在最后回退到默认注册表。预期格式mirror.gcr.io例如:
    • mirror.gcr.io
    • 127.0.0.1
    • 192.168.0.1:5000
    • mycompany-docker-virtual.jfrog.io
  • --reproducible:设置此标志以从构建的镜像中去除时间戳并使其可重现。
  • --single-snapshot:在构建结束时获取文件系统的单个快照,因此只会将一层附加到基础镜像。
  • --skip-tls-verify:push到注册表时跳过 TLS 证书验证。
  • --skip-tls-verify-pull:在从注册表中pull时跳过 TLS 证书验证
  • --skip-tls-verify-registry:您可以设置--skip-tls-verify-registry 在访问指定注册表时跳过 TLS 证书验证
  • --skip-unused-stages:跳过不必要的stage
  • --snapshotMode:您可以设置--snapshotMode=标志以设置 kaniko 将如何快照文件系统。
    • 如果--snapshotMode=full设置,则在拍摄快照时会考虑完整的文件内容和元数据;这是性能最低的选项,但也是最可靠的。
    • 如果--snapshotMode=redo设置,则在快照时将考虑文件的 mtime、大小、模式、所有者 uid 和 gid;这可能比“完整”快 50%,尤其是当您的项目有大量文件时。
    • 如果--snapshotMode=time已设置,则在拍摄快照时将仅考虑文件 mtime(请参阅与与 mtime 相关的限制)。
  • --tar-path:将此标志设置为--tar-path=将镜像另存为路径中的压缩包。您还需要设置--destination(例如--destination=image)。如果你只想将镜像保存为 tar包,你还需要设置--no-push。
  • --target:指示哪个构建阶段是目标构建阶段
  • --use-new-run:使用实验运行实现来检测更改而无需文件系统快照。在某些情况下,这可能会将构建性能提高 75%。
  • --verbosity:设置此标志以--verbosity=设置日志记录级别;默认为info。
  • --ignore-var-run:镜像快照时忽略 /var/run。将其设置为 false 以在目标映像中保留 /var/run/*。(默认为真)。
  • --ignore-path:-ignore-path=在镜像快照时忽略路径。为多个略路径设置多次。
  • --image-fs-extract-retry:设置为提取镜像文件系统应该发生的重试次数;默认为0。

三、使用

Run in K8s

环境依赖

  • kaniko镜像;这里可以直接用现成的,也可以选择自己拉源码构建:
    • registry.cn-hangzhou.aliyuncs.com/weiyigeek/kaniko-executor:latest
    • gcr.io/kaniko-project/executor:latest(这是谷歌官方镜像,正常是拉不下来的)
  • 一个 Kubernetes 集群 或者 一个 Containerd 容器运行环境;这里可以选择用Minikube或kubeadmin快速安装一个,具体细节我就不介绍了;
  • 一个镜像仓库;这里可以是DockerHub、Docker Regisitry、Harbor等;

各类镜像仓库类型secret创建

DockerHub

vim dockerhub-secret.sh
#!/bin/bash
export REGISTRY_SERVER=https://index.docker.io/v1/
export REGISTRY_USER=[xxx]
export REGISTRY_PASS=[xxx]
export REGISTRY_EMAIL=[xxx]
kubectl --namespace=default create secret     docker-registry regcred     --docker-server=$REGISTRY_SERVER     --docker-username=$REGISTRY_USER     --docker-password=$REGISTRY_PASS     --docker-email=$REGISTRY_EMAIL

运行脚本并创建secret:

kubectl create ns kaniko && bash dockerhub-secret.sh

Harbor

vim harbor-secret.sh
#!/bin/bash

REGISTRY_SERVER=https://harbor.wxd.cn/v2/
REGISTRY_USER=[xxx]
REGISTRY_PASS=[xxx]
REGISTRY_EMAIL=tom@163.com
kubectl --namespace=kaniko create secret   docker-registry  harbor-regcred     --docker-server=$REGISTRY_SERVER     --docker-username=$REGISTRY_USER     --docker-password=$REGISTRY_PASS     --docker-email=$REGISTRY_EMAIL

运行脚本并创建secret:

kubectl create  ns  kaniko && bash harbor-secret.sh

Docker Registry

vim registry-secret.sh
#!/bin/bash
REGISTRY_SERVER=https://docker.domain.com:5043/v2/
REGISTRY_USER=[xxx]
REGISTRY_PASS=[xxx]
REGISTRY_EMAIL=tom@163.com
kubectl --namespace=kaniko create secret   docker-registry  registry-regcred   --docker-server=$REGISTRY_SERVER     --docker-username=$REGISTRY_USER     --docker-password=$REGISTRY_PASS     --docker-email=$REGISTRY_EMAIL

运行脚本并创建secret:

kubectl create ns kaniko && bash registry-secret.sh

Kaniko构建镜像并推送至不同的镜像仓库

GitHub 推送 DockerHub

创建 DockerHub secrets,详情请参考上面 编写kaniko-git-dockerhub.yaml:

cat > kaniko-github-dockerhub.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    #image: gcr.io/kaniko-project/executor:debug
    image: ghostwritten/kaniko-project-executor:debug
    args: ["--context=git://github.com/ghostwritten/kaniko-demo",
            "--destination=ghostwritten/devops-toolkit:1.0.0"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: regcred
        items:
          - key: .dockerconfigjson
            path: config.json
EOF    

运行pod:

kubectl apply  -f kaniko-git-dockerhub.yaml -n kaniko

创建pod并查看日志:

 kubectl apply -f  kaniko-github-dockerhub.yaml -n kaniko
 kubectl logs  -f kaniko-github-dockerhub.yaml -n kaniko

GitLab 推送 Harbor

社区issue: github.com/GoogleConta… 创建 harbor-secret,详情请参考上面 编写kaniko-gitlab-harbor.yaml:

cat > kaniko-gitlab-harbor.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: harbor.wxd.cn/dev/application-component-image/kaniko:latest
    args: ["--context=git://gitlab.cn/wxd/kaniko-test#refs/heads/master",
            "--skip-tls-verify",
            "--destination=harbor.wxd.cn/dev/devops-toolkit-git:1.0.0"]
    env:
    - name: GIT_USERNAME
      value: wxd
    - name: GIT_PASSWORD
      value: 'Lmhy22cfiy55BQrDQhyE'
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: harbor-regcred
        items:
          - key: .dockerconfigjson
            path: config.json
EOF

注意: git仓库的填写格式不支持"https:"开头这样的格式,仅支持类似此格式:git://gitlab.cn/wxd/kaniko-test#refs/heads/master,kaniko-test的".git"后缀可加可不加 git仓库认证这边官方给了好几种填写的方式,什么TOKEN写在url前面、TOKEN通过环境变量GIT_TOKEN传进去等等,我试了都不行,唯一可行的是通过两个环境变量:GIT_USERNAME、GIT_PASSWORD(这个环境变量的值可以写) 运行pod:

kubectl apply -f kaniko-gitlab-harbor.yaml -n kaniko

创建pod并查看日志:

 kubectl apply -f  kaniko-gitlab-harbor.yaml -n kaniko
 kubectl logs  -f kaniko-gitlab-harbor.yaml -n kaniko

Local Directory 推送 Registry

创建secret脚本文件,详情请参考上面 创建Dockerfile:

cat > Dockerfile <<EOF
FROM nginx:1.14.2
COPY local-dir-registry.yaml /root
EXPOSE 80
EOF

编写local-dir-registry.yaml:

cat > local-dir-registry.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: harbor.wxd.cn/dev/application-component-image/kaniko:latest
    args: ["--dockerfile=/workspace/Dockerfile",
            "--skip-tls-verify",
            "--destination=docker.domain.com:5043/devops-toolkit:1.0.0"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: workspace
        mountPath: /workspace
      - name: hosts
        mountPath: /etc/hosts        
  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: registry-regcred
        items:
          - key: .dockerconfigjson
            path: config.json
    - name: workspace
      hostPath:
        path: /home/kaniko
    - name: hosts
      hostPath:
        path: /etc/hosts
EOF

注意:destination配置的推送镜像的地址如果需要配置域名解析,需要现在宿主机上配置后,然后把etc/hosts挂载到容器里面去

运行pod:

kubectl apply -f local-dir-registry.yaml -n kaniko

查看日志:

[root@node1 kaniko]# kubectl  logs -f kaniko -n kaniko
INFO[0000] Retrieving image manifest harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 
INFO[0000] Retrieving image harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 from registry harbor.wxd.cn 
INFO[0000] Built cross stage deps: map[]                
INFO[0000] Retrieving image manifest harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 
INFO[0000] Returning cached image manifest              
INFO[0000] Executing 0 build triggers                   
INFO[0000] Building stage 'harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2' [idx: '0', base-idx: '-1'] 
INFO[0000] Unpacking rootfs as cmd COPY local-dir-registry.yaml /root requires it. 
INFO[0004] COPY local-dir-registry.yaml /root           
INFO[0004] Taking snapshot of files...                  
INFO[0004] EXPOSE 80                                    
INFO[0004] Cmd: EXPOSE                                  
INFO[0004] Adding exposed port: 80/tcp                  
INFO[0005] Pushing image to docker.domain.com:5043/devops-toolkit:1.0.0 
INFO[0007] Pushed docker.domain.com:5043/devops-toolkit@sha256:6f4b3f80289970feaf23dbd81cc53d3c1a6131890e4e2ccabf2ee61ce465958f 

Local Directory 推送 Harbor

创建 harbor-secret,详情请参考上面 创建Dockerfile:

cat > Dockerfile <<EOF
FROM nginx:1.14.2
COPY Dockerfile /root
EXPOSE 80
EOF

创建 local-dir-harbor.yaml:

cat > local-dir-harbor.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: harbor.wxd.cn/dev/application-component-image/kaniko:latest
    args: ["--dockerfile=/workspace/Dockerfile",
          "--skip-tls-verify",
            "--destination=harbor.wxd.cn/dev/wxd/devops-toolkit:1.0.0"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: workspace
        mountPath: /workspace
      - name: hosts
        mountPath: /etc/hosts

  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: harbor-regcred
        items:
          - key: .dockerconfigjson
            path: config.json
    - name: workspace
      hostPath:
        path: /home/kaniko
    - name: hosts
      hostPath:
        path: /etc/hosts
EOF

运行pod:

kubectl apply -f local-dir-harbor.yaml -n kaniko

查看日志:

[root@node1 kaniko]# kubectl logs  -f kaniko -n kaniko
INFO[0000] Retrieving image manifest harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 
INFO[0000] Retrieving image harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 from registry harbor.wxd.cn 
INFO[0000] Built cross stage deps: map[]                
INFO[0000] Retrieving image manifest harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2 
INFO[0000] Returning cached image manifest              
INFO[0000] Executing 0 build triggers                   
INFO[0000] Building stage 'harbor.wxd.cn/dev/application-component-image/nginx:amd64-1.14.2' [idx: '0', base-idx: '-1'] 
INFO[0000] Unpacking rootfs as cmd COPY local-dir-registry.yaml /root requires it. 
INFO[0005] COPY local-dir-registry.yaml /root           
INFO[0005] Taking snapshot of files...                  
INFO[0005] EXPOSE 80                                    
INFO[0005] Cmd: EXPOSE                                  
INFO[0005] Adding exposed port: 80/tcp                  
INFO[0005] Pushing image to harbor.wxd.cn/dev/wxd/devops-toolkit:1.0.0 
INFO[0006] Pushed harbor.wxd.cn/dev/wxd/devops-toolkit@sha256:379ca7f822896ef9177c213228a23f87d7747ed77ee3436aaab14dc451ed1d08 

然后去harbor上查看下镜像是否推送成功: 可以看到镜像已经推上来了

image.png

Run in Docker

推送至 Harbor

环境依赖

Docker运行环境;我们可以在有Docker Demon的环境运行kaniko,从 Dockerfile 构建和推送镜像

创建config文件

  • USERNAME harbor用户名
  • PASSWORD harbor账号密码
  • EMAIL harbor账号绑定的邮箱
USERNAME=dev
PASSWORD=Developer123
EMAIL=develop@163.com
AUTH=$(printf "$USERNAME:$PASSWORD" | base64)
cat > config.json <<EOF
{
    "auths":{
        "https://harbor.wxd.cn/v2/":{
            "username":"$USERNAME",
            "password":"$PASSWORD",
            "email":"$EMAIL",
            "auth":"$AUTH"
        }
    }
}
EOF

创建Dockerfile

cat > Dockerfile <<EOF
FROM nginx:1.14.2
COPY Dockerfile /root
EXPOSE 80
EOF

运行脚本

docker run -v /home/kaniko:/workspace \
    -v /home/kaniko/config.json:/kaniko/.docker/config.json \
    harbor.wxd.cn/dev/application-component-image/kaniko:debug \
    --dockerfile /workspace/Dockerfile \
    --destination "harbor.wxd.cn/dev/wxd/devops-toolkit:2.0.0" \
    --context dir:///workspace/ \
    --skip-tls-verify

推送至 Docker Registry

步骤和推送到Harbor差不多,只是登录认证方式改了改

创建config文件

USERNAME=admin
PASSWORD=admin
EMAIL=
AUTH=$(printf "$USERNAME:$PASSWORD" | base64)
cat > config-registry.json <<EOF
{
    "auths":{
        "https://docker.domain.com:5043/v2/":{
            "username":"$USERNAME",
            "password":"$PASSWORD",
            "email":"$EMAIL",
            "auth":"$AUTH"
        }
    }
}
EOF

创建Dockerfile

cat > Dockerfile <<EOF
FROM nginx:14.2
COPY Dockerfile /root
EXPOSE 80
EOF

运行脚本

docker run -v /home/kaniko:/workspace \
    -v /etc/hosts:/etc/hosts \
    -v /home/kaniko/config-registry.json:/kaniko/.docker/config.json \
    harbor.wxd.cn/dev/application-component-image/kaniko:debug \
    --dockerfile /workspace/Dockerfile \
    --destination "docker.domain.com:5043/devops-toolkit:3.0.0" \
    --context dir:///workspace/ \
    --skip-tls-verify

Run in CICD Pipeline

准备

注意:

  • 首先需要创建一个推送镜像仓库的Secret,具体操作这里就不再赘述了。
  • CICD场景下使用Kaniko只能使用debug镜像,因为latest镜像基于 scratch构建,不包含 shell,无法进入容器。

流水线集成

pod声明

将下方容器yaml声明放到流水线脚本的pod声明里面:

   - image: harbor.wxd.cn/dev/application-component-image/kaniko:debug
    command: ["/busybox/sh"]
    name: imagebuildandpush
    tty: true
    resources:
      limits:
        memory: 1024Mi
        ephemeral-storage: 1Gi
        cpu: 1000m
    volumeMounts:
      - name: kaniko-secret #挂载目标仓库的用户名密码
        mountPath: /kaniko/.docker
      - name: workspace #挂载工作空间
        mountPath: /workspace
      - name: hosts #挂载宿主机的host,使用宿主机的域名解析
        mountPath: /etc/hosts

pod volume挂载

   volumes:
  - name: kaniko-secret
    secret:
      secretName: harbor-regcred
      items:
        - key: .dockerconfigjson
          path: config.json
  - name: workspace
    hostPath:
      path: /root/application/sharing/e2979973a5e440d897af913c6953b383/workspace/e2979973a5e440d897af913c6953b383 #jenkins的工作目录
  - name: hosts
    hostPath:
      path: /etc/hosts

pipeline step脚本

      steps {
        container('jnlp') {
          checkout ([$class: 'GitSCM', branches: [[name: 'master']],userRemoteConfigs: [[credentialsId: '091caf88db684cd8a62479c03535bd69',url: 'https://gitlab.wxd.cn/Haihe/application-center.git']]])
        }

        container('maven') {
          sh "mvn clean package -Dmaven.test.skip=true"
          sh "cp target/application-center-1.1.0.jar ./docker/"
          sh "cp entrypoint.sh ./docker/"
          sh "cp -r data/ ./docker/"
          sh "cp -r helm/ ./docker/"
        }

        container('imagebuildandpush') {
          sh "/kaniko/executor -f /workspace/docker/Dockerfile -c /workspace/docker --cache=true --skip-tls-verify --destination=harbor.wxd.cn/dev/wxd/devops-toolkit:2.0.0"
        }

      }

四、其他类似的镜像构建工具

对比:

  1. BuildKit和img可以在容器中作为非root用户执行,但需要禁用 seccomp 和 AppArmor 才能创建嵌套容器。 kaniko实际上并不创建嵌套容器,因此不需要禁用 seccomp 和 AppArmor。
  2. orca-build依赖于runc从 Dockerfiles 构建镜像,它不能在容器内运行。kaniko不使用runc,因此不需要使用内核命名空间技术。但是,orca-build不需要 Docker 或任何特权守护进程(因此构建可以完全在没有特权的情况下完成)。
  3. Buildah专门构建 OCI 镜像。Buildah 的命令复制了 Dockerfile 中的所有命令。这允许在不需要任何 root 权限的情况下使用和不使用 Dockerfile 构建镜像。Buildah 的最终目标是提供一个较低级别的 coreutils 接口来构建镜像。在没有 Dockerfiles 的情况下构建镜像的灵活性允许将其他脚本语言集成到构建过程中。Buildah 遵循简单的 fork-exec 模型,不作为守护进程运行,但它基于 golang 中的综合 API,可以供应给其他工具。