Kubernetes平台上更安全的构建容器镜像工具-Kaniko

背景

在云原生趋势下,用容器的方式来进行软件产品交付越来越普通,对于云原生的DevOps,它的CICD环境完全运行在容器中,镜像的构建也是在容器中完成的。而我们不仅要考虑如何在容器中成功构建镜像,也需要考虑如何以更安全的方式来构建容器镜像。

容器内构建镜像的方式

容器中构建镜像一般分为两种:

  • 在Docker容器中运行Docker,依赖Docker Daemon
  • Kaniko -K8s中构建镜像,不依赖Docker Daemon

下面分开来讨论两种方式

在Docker容器中运行Docker

在Docker中实现Docker的二种方法:

  1. 通过挂载docker.sock运行docker:需要root权限
  2. dind(docker in docker):需要privileged特权

通过挂载docker.sock运行docker

要在docker内部运行docker,要做的只是在默认Unix套接字docker.sock作为卷的情况下运行docker 。

docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker

缺点:只有root权限才能访问docker daemon进程,在docker daemon无法暴露或者用户没有权限获取docker daemon进程的前提下,用 docker build 来构建镜像就不可行了。

dind(docker in docker)

docker build镜像就是需要docker命令可以成功运行,只要在容器里面安装一个docker就可以。这种方式不需要挂载宿主机的socket文件,但是需要以 --privileged 权限来以dind镜像创建一个容器

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

缺点:该方式需要提供特权,可能会看到宿主机上的一些设备,并且可以执行mount命令。

比较

这两种方式,一种需要root权限,一种需要privileged特权,从安全角度来看是有风险的。特别是在K8S多租户的场景下,这种方式不能被接受。同时当一台机器上同时运行多个docker build流水线时,因为这批流水线用的是宿主机上同一个docker进程,会出现阻塞的情况。因此Google提供了一个工具Kaniko用来解决这个问题

Kaniko

Kaniko是一个Google开源的方便我们在k8s中使用dockfile构建镜像的工具。它不依赖docker daemon进程,并完全在用户空间执行dockfile文件的每一条命令。这样我们就可以在一些没法获取docker daemon进程的环境下也可以构建镜像。比如在K8S上。

kaniko会先提取基础镜像的文件系统,然后根据Dockerfile中的描述,一条条执行命令,每一条命令执行完之后都会在用户空间创建一个snapshot,并于存储在内存中的上一个状态做对比,若有变化,将新的修改生成一个镜像层添加在基础镜像上面,并将相关修改信息写入到镜像元数据中,等全部命令执行完,Kaniko会将最终镜像推送到指定的远端镜像仓库。

下面给出一个利用kaniko来构建镜像的示例

前提条件

  1. 一个Kubernetes集群
  2. 一个dockerhub账户,用于push镜像

为kaniko准备配置文件

kaniko以容器镜像的方式运行,同时需要三个参数:Dockerfile,context 以及远端镜像仓库的地址。需要准备几个配置文件来在k8s中创建资源,他们是:

  • kaniko_build_image.yaml 用于启动kaniko容器用来构建镜像
  • configmap 存放Dockerfile文件
  • secret 存放dockerhub授权信息

创建一个Dockerfile文件

编写一个Dockerfile文件:

FROM ubuntu
ENTRYPOINT ["/bin/bash", "-c", "echo hello"]

并创建一个configmap:
kubectl create configmap kanikodockerfile --from-file=./Dockerfile

创建一个保存远端镜像仓库凭证的Secret

k8s集群使用docker-registry类型的Secret去授权docker仓库去推送镜像。创建这个Secret:

kubectl create secret docker-registry regcred --docker-server=<your-registry-server> --docker-username=<your-name> --docker-password=<your-pword> --docker-email=<your-email>

<your-registry-server>: 你的私有Docker仓库地址,DockerHub是https://index.docker.io/v1/
<your-name>: 你的仓库用户名
<your-pword>: 你的仓库密码
<your-email>: 你的仓库邮箱 可选

这个Secret会在pod.yaml,也就是用kaniko创建镜像的容器中使用。

或者编辑名为config.json的文件,并生成Secret,后需要以secret的方式挂载到/kaniko/.docker/这个目录下。文件内容为:

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

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

准备kaniko_build_image.yaml 用于启动kaniko容器用来构建镜像

apiVersion: v1
kind: Pod
metadata:
  name: kaniko
spec:
  containers:
  - name: kaniko
    image: gcr.io/kaniko-project/executor:latest
    args: ["--dockerfile=/workspace/dockerfile",
            "--context=dir://workspace",
            "--destination=<user-name>/<repo>"] # replace with your dockerhub account
    volumeMounts:
      - name: kaniko-secret
        mountPath: /kaniko/.docker
      - name: dockerfile
        mountPath: /workspace
  restartPolicy: Never
  volumes:
    - name: kaniko-secret
      secret:
        secretName: regcred
        items:
          - key: .dockerconfigjson
            path: config.json
    - name: dockerfile
       configMap:
         name: kanikodockerfile

构建

现在就是创建pod,查看状态,并看log是否正常完成。
创建构建podkubectl apply -f kaniko_build_image.yaml

测试

用kaniko生成的镜像来测试下是否可用:sudo docker run -it <user-name>/<repo-name>

参考链接

https://cloud.tencent.com/developer/article/1697053
https://www.shangmayuan.com/a/38d1cc5f039540899ceb0d43.html
https://www.yinyubo.com/2021/06/25/自定义一个kaniko镜像/

posted @ 2022-04-30 22:35  EndeavourOne  阅读(854)  评论(0编辑  收藏  举报