乐趣区

关于云计算:Kaniko-以一种更安全可靠的方式在Kubernetes平台上构建容器镜像-IDCF

前言

随着各企业上云过程的减速,用容器的形式来交付软件产品也变得越来越广泛,如何以更平安的形式来构建容器镜像,也就成了大家关注的话题。

docker 构建镜像

docker 是最近几年十分炽热的容器技术,用 docker 来构建容器镜像也是罕用的办法,在具备构建容器镜像所需的两个因素 (Dockerfile & 上下文) 的前提下,用下述命令就能构建一个容器镜像进去

$ docker build -t your_registry/your_repository:tag .

而后用 docker push 将镜像推送到镜像仓库

$ docker push your_registry/your_repository:tag

当初 DevOps 的 CI/CD 环境大多数都会运行在容器内,镜像的形成也是在容器内实现的。这时候,通常用以下两种形式来实现容器内构建镜像的工作:

第一:挂载宿主机的 socket 文件到容器外部

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/kaniko:/tmp/kaniko docker

而后在容器外部用 docker build 构建镜像

$ docker build -t dllhb/kaniko-test:v0.1 .
Sending build context to Docker daemon  5.632kB
Step 1/4 : FROM alpine:latest
latest: Pulling from library/alpine
89d9c30c1d48: Already exists
Digest: sha256:c19173c5ada610a5989151111163d28a67368362762534d8a8121ce95cf2bd5a
Status: Downloaded newer image for alpine:latest
 ---> 965ea09ff2eb
Step 2/4 : MAINTAINER <devops008@sina.com xiaomage> 
 ---> Running in 8a2b1dc13d6b
Removing intermediate container 8a2b1dc13d6b 
 ---> bd535532278d
Step 3/4 : RUN apk add busybox-extras curl
 ---> Running in fc254ad3d088
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64/APKINDEX.tar.gz
(1/5) Installing busybox-extras (1.30.1-r3)
Executing busybox-extras-1.30.1-r3.post-install
(2/5) Installing ca-certificates (20190108-r0)
(3/5) Installing nghttp2-libs (1.39.2-r0)
(4/5) Installing libcurl (7.66.0-r0)
(5/5) Installing curl (7.66.0-r0)
Executing busybox-1.30.1-r2.trigger
Executing ca-certificates-20190108-r0.trigger
OK: 7 MiB in 19 packages
Removing intermediate container fc254ad3d088
 ---> 1bbe81600a67
Step 4/4 : CMD ["echo","Hello DevOps"]
 ---> Running in 4b92a6a4b37e
Removing intermediate container 4b92a6a4b37e
 ---> de712b8cd7e5
Successfully built de712b8cd7e5
Successfully tagged dllhb/kaniko-test:v0.1

因为 docker 依赖于 docker daemon 过程,docker daemon 过程是一个 Unixsocket 连贯,且 /var/run/docker.sock 文件是 root 权限,

$ ls -ltr /var/run/docker.sock
lrwxr-xr-x 1 root  daemon 69 Nov 26 15:13 /var/run/docker.sock

阐明只有 root 权限能力拜访 docker daemon 过程,在 docker daemon 无奈裸露或者用户没有权限获取 docker daemon 过程的前提下,用 docker build 来构建镜像就变的十分艰难了。

可能咱们会想,docker build 镜像无非就是须要 docker 命令能运行胜利,只有在容器外面装置一个 docker 不就胜利了吗?这也就是上面讲的第二种办法。

第二种: dind(docker-in-docker)

这种形式不须要挂载宿主机的 socket 文件,然而须要以 –privileged 权限来以 dind 镜像创立一个容器:

$ docker run --rm -it --privileged docker:18.06-dind

而后在容器外面构建容器镜像并推送至远端仓库。

dind 可能满足构建容器镜像的需要,然而从下面的命令看,有一个参数:–privileged。象征这这个容器具备一些特权,他可能会看到宿主机上的一些设施,而且可能执行 mount 命令。

dind 还有很多问题,只是不便 docker 开发人员来测试 docker,所以官网也说running Docker inside Docker is generally not recommended。具体的能够看看这篇博文: https://jpetazzo.github.io/20…

上述两种办法,都能满足在容器内构建容器镜像且推送镜像至远端仓库的需要,然而从 security 角度来讲,须要 root 权限(第一种形式),提供特权(第二种形式) 都使得危险增大,在 Kubernetes 多租户的场景下,这种危险是不能承受的。那是否有一种不须要非凡权限,还能疾速构建容器镜像的办法呢?答案就是上面将的 Kaniko。

Kaniko

Kaniko 是谷歌开源的一款用来构建容器镜像的工具。与 docker 不同,Kaniko 并不依赖于 Docker daemon 过程,齐全是在用户空间依据 Dockerfile 的内容逐行执行命令来构建镜像,这就使得在一些无奈获取 docker daemon 过程的环境下也可能构建镜像,比方在 规范的 Kubernetes Cluster上。

Kaniko 以容器镜像的形式来运行的,同时须要三个参数: Dockerfile,上下文,以及远端镜像仓库的地址

Kaniko 会先提取根底镜像 (Dockerfile FROM 之后的镜像) 的文件系统,而后依据 Dockerfile 中所形容的,一条条执行命令,每一条命令执行完当前会在用户空间上面创立一个 snapshot,并与存储与内存中的上一个状态进行比对,如果有变动,就将新的批改生成一个镜像层增加在根底镜像上,并且将相干的批改信息写入镜像元数据中。等所有命令执行完,kaniko 会将最终镜像推送到指定的远端镜像仓库。

Kaniko 构建镜像

上面看一个 demo。

$ cat Dockerfile
FROM alpine:latest
    
MAINTAINER <devops008@sina.com xiaomage>
    
RUN apk add busybox-extras curl
    
CMD ["echo","Hello DevOps"]

在 kubernetes cluster 下面创立一个 pod,yaml 文件如下:

apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
 containers:
 - name: kaniko
   image: gcr.io/kaniko-project/executor:latest
   args: ["--dockerfile=/workspace/Dockerfile",
          "--context=/workspace/",
          "--destination=dllhb/kaniko-test:v0.4"]
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: dockerfile
        mountPath: /workspace/Dockerfile
        subPath: Dockerfile
restartPolicy: Never
volumes:
      - name: dockerfile
        configMap:
          name: dockerfile
      - name: kaniko-secret
         projected:
         sources:
         - secret:
              name: regcred
              items:
                - key: .dockerconfigjson
                  path: config.json

须要阐明几点:

  • args 局部

这部分就是下面所讲的,kaniko 运行时须要三个参数: Dockerfile(–dockerfile),上下文(–context),远端镜像仓库(–destination)

  • secret 局部

推送至指定远端镜像仓库须要 credential 的反对,所以须要将 credential 以 secret 的形式挂载到 /kaniko/.docker/ 这个目录下,文件名称为 config.json,内容如下:

{   
    "auths": {
        "https://index.docker.io/v1/": {"auth": "AbcdEdfgEdggds="}
    }
    
}

其中 auth 的值为: echo"docker_registry_username:docker_registry_password"|base64

而后创立 pod,查看状态,并看 log

$ kubectl -n kaniko apply -f kaniko.yaml
pod/kaniko created
$ kubectl -n kaniko get pods
NAME     READY   STATUS      RESTARTS   AGE
kaniko 1/1 Running 0 21s
$ kubectl -n kaniko logs -f kaniko
 1 INFO[0000] Resolved base name alpine:latest to alpine:latest
 2 INFO[0000] Resolved base name alpine:latest to alpine:latest
 3 INFO[0000] Downloading base image alpine:latest
 4 INFO[0001] Error while retrieving image from cache: getting fileinfo: stat /cachesha256:e4355b66995c96b4b468159fc5c7e3540fcef961189ca13fee877798649f51a: no such file or directory
 5 INFO[0001] Downloading base image alpine:latest
 6 INFO[0001] Built cross stage deps: map[]
 7 INFO[0001] Downloading base image alpine:latest
 8 INFO[0001] Error while retrieving image from cache: getting fileinfo: stat /cachesha256:e4355b66995c96b4b468159fc5c7e3540fcef961189ca13fee877798649f51a: no such file or directory
 9 INFO[0001] Downloading base image alpine:latest
 10 WARN[0002] maintainer is deprecated, skipping
 11 INFO[0002] Unpacking rootfs as cmd RUN apk add busybox-extrascurl requires it.
 12 INFO[0002] Taking snapshot of full filesystem...
 13 INFO[0002] RUN apk add busybox-extras curl
 14 INFO[0002] cmd: /bin/sh
 15 INFO[0002] args: [-c apk add busybox-extras curl]
 16 fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/main/x86_64APKINDEX.tar.gz
 17 fetch http://dl-cdn.alpinelinux.org/alpine/v3.10/community/x86_64APKINDEX.tar.gz
 18 (1/5) Installing busybox-extras (1.30.1-r3)
 19 Executing busybox-extras-1.30.1-r3.post-install
 20 (2/5) Installing ca-certificates (20190108-r0)
 21 (3/5) Installing nghttp2-libs (1.39.2-r0)
 22 (4/5) Installing libcurl (7.66.0-r0)
 23 (5/5) Installing curl (7.66.0-r0)
 24 Executing busybox-1.30.1-r2.trigger
 25 Executing ca-certificates-20190108-r0.trigger
 26 OK: 7 MiB in 19 packages
 27 INFO[0003] Taking snapshot of full filesystem...
 28 INFO[0003] CMD ["echo","Hello DevOps"]

能够用新生成的镜像创立个容器来测试一下:

$ docker run --rm dllhb/kaniko-test:v0.5
Unable to find image 'dllhb/kaniko-test:v0.5' locally
v0.5: Pulling from dllhb/kaniko-test
89d9c30c1d48: Already exists
2beaee649353: Pull complete
Digest: sha256:461233efe63a8f16e8630ab92a31795fb0932d2910669131d9973f258070cca5
Status: Downloaded newer image for dllhb/kaniko-test:v0.5
Hello DevOps

能够看到输入了 HelloDevOps 这和 Dockerfile 所写是统一的。证实容器镜像曾经构建结束并已推送至远端仓库。

Kaniko 与 Jenkins pipeline 的集成

Jenkins pipeline 代码如下:

podTemplate(
       label: label,
        serviceAccount: "your service account",
        namespace: "your jenkins namespace",
        yaml: """
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: gcr.io/kaniko-project/executor:debug
    imagePullPolicy: Always
    command:
    - cat
    tty: true
    volumeMounts:
      - name: registry-secret
        mountPath: /kaniko/.docker
      - name: jenkins-home
        mountPath: /home/jenkins
  - name: maven
    image: maven:3-jdk-8
    imagePullPolicy: Always
    command:
    - cat
    tty: true
    volumeMounts:
      - name: jenkins-home
        mountPath: /home/jenkins
  volumes:
    - name: jenkins-home
      persistentVolumeClaim:
        claimName: jenkins-pvc
    - name: registry-secret
      secret:
        secretName: regcred
        items:
          - key: .dockerconfigjson
            path: config.json
"""
) {node(label)  {container('kaniko') {sh '/kaniko/executor -f Dockerfile -c . --destination=your_registry/your_repo:tag'}
    }
}

触发构建查看 jenkins log:

能够看出,Kaniko 能够在无奈获取宿主机 docker daemon 过程或者没有非凡权限的状况下构建容器镜像,这种形式是非常适合在 Kubernetes 平台上构建容器镜像的,而且易于集成到 DevOposJenkinspipeline 里。

参考资料: Kaniko github repo:https://github.com/GoogleCont…

dind 博文:https://jpetazzo.github.io/20…

起源:DevSecOps SIG
作者:小马哥

退出移动版