前言
随着各企业上云进程的加速,用容器的方式来交付软件产品也变得越来越普遍,如何以更安全的方式来构建容器镜像,也就成了大家关注的话题。 docker 构建镜像
docker是最近几年非常火热的容器技术,用docker来构建容器镜像也是常用的方法,在具备构建容器镜像所需的两个要素(Dockerfile & 上下文)的前提下,用下述命令就能构建一个容器镜像出来
|
|
然后用 docker push
将镜像推送到镜像仓库
|
|
现在DevOps 的CI/CD环境大多数都会运行在容器内,镜像的构成也是在容器内完成的。这时候,通常用以下两种方式来完成容器内构建镜像的工作:
挂载宿主机的socket文件
|
|
然后在容器内部用 docker build
构建镜像
|
|
由于docker依赖于 docker daemon
进程, docker daemon
进程是一个 Unixsocket
连接,且 /var/run/docker.sock
文件是root权限,
|
|
说明只有root权限才能访问 docker daemon
进程,在 docker daemon
无法暴露或者用户没有权限获取 docker daemon
进程的前提下,用 docker build
来构建镜像就变的非常困难了。
远程调用docker socket
docker daemon端开启远程调用
|
|
可以在容器里面使用docker client根据dockerfile远程调用docker socket执行构建
|
|
|
|
dind(docker-in-docker)
这种方式不需要挂载宿主机的socket文件,但是需要以 –privileged 权限来以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会将最终镜像推送到指定的远端镜像仓库。
前置条件
- 标准的kubernetes集群 (e.g. using GKE)
- Kubernetes Secret
- 构建上下文目录(Context)
Kubernetes secret
要在 Kubernetes 集群中运行 kaniko,您需要一个标准的运行 Kubernetes 集群和一个 Kubernetes secret,其中包含推送最终映像所需的身份验证。推送至指定远端镜像仓库须要credential的支持,因此须要将credential以secret的方式挂载到/kaniko/.docker/这个目录下,文件名称为kaniko_config.json,内容以下:
|
|
其中auth字段是认证信息,它是从用户名和密码通过base64编码而来:
|
|
运行创建secret
|
|
Pod示例
Kubernetes kaniko Pod 示例, args 参数按需修改:
|
|
执行构建
|
|