
在Kubernetes中构建Docker镜像
在Kubernetes上托管CI/CD平台在工程师中变得越来越普遍。这种方法通过自动化节省了时间,确保了部署的一致性,并使监控和管理微服务变得更加容易。然而,在Kubernetes集群中构建容器镜像涉及一些技术障碍,需要变通。
在这篇文章中,我们将探讨在Kubernetes集群中构建Docker镜像的一些方法,用于CI/CD流程。我们还将讨论使用这些方法的优势和劣势。
在Kubernetes中构建Docker镜像的工具
如果你曾经构建过一个容器镜像,你可能运行过类似docker build 。然后,当需要自动化这一过程时,你可能会对你的CI/CD工具编写脚本,以使用docker build 。这适用于简单的CI服务器,但你可能最终想部署一个基于Kubernetes的CI平台。
挑战在于,Docker守护程序不能从Kubernetes集群中自由访问。所以我们必须使用替代方案,同时确保不损害我们应用程序的完整性和基础设施。
有几个工具可以做到这一点。
- Buildah专注于构建开放容器倡议(OCI)镜像。它的命令复制了Docker文件的所有命令。它可以在没有Docker文件的情况下构建镜像,而不需要root权限。
- img是一个独立的、无守护程序的、无特权的Dockerfile和OCI兼容的容器镜像生成器。它的缓存效率高,可以同时执行多个构建阶段,因为它在内部使用BuildKit 的 DAG 解算器作为其镜像构建器。
- kaniko在容器或Kubernetes集群内从Docker文件构建容器镜像。kaniko不依赖Docker守护进程,完全在用户空间执行每个Docker文件命令。
- Docker in Docker是一个在Docker内运行Docker的秘方。它在Kubernetes集群中构建Docker容器,方法是将
/var/run/docker.sock文件挂载为Docker容器中的一个卷。 - Nestybox的Sysbox企业版(Sysbox-EE)让无根容器作为虚拟机运行Docker、systemd和Kubernetes等工作负载。
- BuildKit CLI在Kubernetes集群内构建单一和多架构的OCI和Docker镜像。它用kubectl build取代了docker build命令,在Kubernetes集群中创建镜像。
- 用于Java容器的Jib在不使用Dockerfile或需要Docker安装的情况下构建容器镜像。Jib插件可用于Maven和Gradle。Jib也可以作为一个Java库使用。
- KO是一个用于Go应用程序的快速而简单的容器镜像生成器。它通过在你的本地机器上有效地执行go build来构建镜像,所以它不需要安装Docker。
让我们关注一下在Kubernetes集群中构建Docker镜像的两种流行方法。Docker in Docker和kaniko。
Docker in Docker
Docker in Docker(DinD)方法通常用于CI/CD管道,在代码构建成功后构建镜像并推送。这种方法也用于将Jenkins集成到部署管道中(例如,在沙盒环境的测试期间)。
DIND的方法看起来很方便,很简单。然而,前Docker员工和DinD贡献者Jérôme Petazzoni坚持认为,Docker创建这种方法是为了加速内部流程,并暗指安全问题是不在生产环境中使用它的原因。
Docker最初使用DinD方法来构建容器,使其在特权模式下运行。Docker守护程序以root身份运行,所以容器在主机上以root身份运行。任何访问Docker套接字的人都有root权限,让他们有权限运行任何软件,创建新用户,并访问与容器连接的一切。这使得容器容易受到可能蔓延到整个架构的攻击。
此外,由于Kubernetes已经正式取消了对Dockershim的支持,将docker.sock 到主机上很可能在未来无法工作,除非我们将Docker添加到所有Kubernetes节点中。AWS提供了一个有用的工具来检测集群中Docker套接字的使用。
DIND方法也带来了关于存储驱动器兼容性的问题。此外,管理镜像缓存也是一种挑战,因为我们每次启动构建时都需要拉动Docker镜像。
解决这些问题的方法之一是使用不需要容器运行时间的工具来构建镜像。kaniko就是这样一个工具,它是谷歌在Kubernetes集群中构建Docker镜像的开源解决方案。
kaniko
kaniko从容器或Kubernetes集群内的Docker文件构建容器镜像。它不依赖Docker守护进程,而且完全在用户空间执行每个Dockerfile命令。这使你可以在不容易或不安全地运行Docker守护进程的环境中构建容器镜像--比如标准的Kubernetes集群。
我们将使用免费的、公开的工具来说明kaniko的工作流程。要遵循本教程,你需要。
- 在你的电脑上安装Docker Desktop,并启用Kubernetes
- 一个有效的Docker Hub账户,用于kaniko pod认证和推送Docker镜像
- kaniko的GitHub账户,用于访问Docker文件
我们将使用GitHub上的这个样本项目来说明kaniko如何工作。用git clone https://github.com/agavitalis/kaniko-kubernetes.git 来克隆它,以便进行跟踪。
这个样板项目有两个文件和一个README.md 文件。
#sample project directory
kaniko-build-demo
dockerfilepod.ymlREADME.md
dockerfile 包含这个图像构建命令的代码。
FROM ubuntu
ENTRYPOINT ["/bin/bash", "-c", "echo Hello to Kaniko from Kubernetes"]
pod.yml contains this code for the kaniko configurations:
apiVersion: v1
kind: Pod
metadata:
name: kaniko-demo
spec:
containers:
- name: kaniko-demo
image: gcr.io/kaniko-project/executor:latest
args: ["--context=git://github.com/agavitalis/kaniko-kubernetes.git",
"--destination=agavitalis/kaniko-build-demo:1.0.0",
"--dockerfile=dockerfile"]
volumeMounts:
- name: kaniko-secret
mountPath: /kaniko/.docker
restartPolicy: Never
volumes:
- name: kaniko-secret
secret:
secretName: reg-credentials
items:
- key: .dockerconfigjson
path: config.json
在kaniko配置代码中,kaniko镜像执行器使用最新版本。我们还指定了我们的Dockerfile和镜像仓库的位置,以及我们在Kubernetes中的镜像注册库凭证的名称。
kaniko如何工作
kaniko以一种相当简单的方式工作。kaniko执行器镜像gcr.io/kaniko-project/executor:latest ,运行Dockerfile命令来构建镜像。它读取指定的Dockerfile,将FROM命令中定义的基本镜像(本例中为ubuntu)拉到定义的容器文件系统中,然后将镜像推送到注册中心。
在从FROM指令中拉出基础镜像后,kaniko单独运行Dockerfile中的每一条命令,在执行每一条命令后对用户空间进行快照。然后它在每次运行时将快照层附加到基础层。
我们在pod.yml 文件中设置这些配置。
context:Dockerfile的位置。在这种情况下,Dockerfile是在版本库的根目录下。使用GIT_USERNAME和GIT_PASSWORD(API token) 变量在私有 Git 仓库中进行认证。destination:用你的用户名替换<dockerhub-username>,以便kaniko将镜像推送到Docker Hub注册表。docker-file:Dockerfile的路径与上下文相对应。
现在我们了解了kaniko的操作原理,让我们创建一个Kubernetes Secret。然后我们将用它来构建和部署一个镜像。
创建Docker Hub Kubernetes秘密
我们必须创建一个Kubernetes Secret,以便kaniko能够访问Docker Hub。要做到这一点,我们需要以下信息。
docker-server:托管你的镜像的Docker注册表服务器。如果你使用Docker Hub,这个值应该是https://index.docker.io/v1/。docker-username:你的Docker注册中心用户名。docker-password:你的Docker注册表密码。docker-email:在你的Docker注册表上配置的电子邮件。
运行下面的命令,适当地替换每个变量。
#bash
$ kubectl create secret docker-registry reg-credentials
--docker-server=<docker-server> --docker-username=<username> --docker-password=<password> --docker-email=<email>
上面的命令将这个Secret挂载在kaniko pod上,以便在将构建的镜像推送到Docker注册中心时方便认证。你应该收到一条类似这样的确认信息。

正在部署kaniko pod以构建Docker镜像
现在,让我们通过在Kubernetes集群中催生pod来启动构建。使用该命令部署pod。
#bash
$ kubectl apply -f pod.yaml

这将启动镜像构建过程,然后将镜像推送到指定的Docker注册中心。
你可以使用命令来列出Kubernetes集群中的可用pod。
#bash
$ kubectl get pod

这将显示可用的pod、它们的状态和它们的年龄。(注意,如果kaniko使用了错误的凭证或推送到错误的仓库,你可能会得到一个错误)。
如果你愿意,可以使用kubectl delete pod <pod-name> 命令来删除现有的pod。
要获得你刚刚部署的pod的全面细节,请使用该命令。
#bash
$ kubectl describe pod

你也可以使用命令查看构建日志。
#bash
$ kubectl logs kaniko-demo -f

查看kubectl小抄,了解你可以用来探索、排除故障和获得集群更多信息的其他命令。
接下来,去Docker Hub确认一切都成功了,你已经成功地将你的镜像部署到了Docker。

我们已经成功地从Kubernetes集群中使用kaniko构建并部署了我们的Docker镜像!
容器安全的Snyk
kaniko提供了一种在Kubernetes集群中构建Docker镜像的安全方式。它从定义的构建环境中抓取Docker文件,制作镜像,并将结果推送到镜像注册中心。它强大的缓存系统可以更快地创建你的镜像。
即使你不使用不安全的方法来制作Kubernetes中的Docker镜像,你仍然可能面临Kubernetes安全漏洞的风险。Snyk Container提供了一个可靠的容器安全解决方案,用于查找和修复云原生应用程序中的漏洞。Snyk与Docker、GitHub、Kubernetes、Jenkins和其他工具无缝集成,以确保你的应用和基础设施的安全。