前言
随着各企业上云过程的减速,用容器的形式来交付软件产品也变得越来越广泛,如何以更平安的形式来构建容器镜像,也就成了大家关注的话题。
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
作者:小马哥