向Docker告别的时候到了
在容器的远古时期(大约4年前),Docker是容器游戏中仅有的参与者。但是现在情况不一样了,Docker不再是唯一的一个了,只是另一个容器引擎而已。Docker允许我们构建,运行,拉取,上传,查看容器镜像,但是对每一项任务都有其他可以比Docker做得更好的工具。因此,让我们看看现在的情况,卸载(只是可能)并且忘记Docker的全部信息。
不过,为什么不使用Docker?
如果你是一名Docker的老鸟,我想即使考虑使用不同的工具,也需要一些说服自己的理由。那么,理由就在这里:
首先,Docker是一个尝试做所有事情的工具,通常来说这并不是最好的方式。大多数情况下,最好选择一种专门只做一件事,并且能把这件事做得非常好的工具。
如果你担心切换到不同的工具后,不得不学着使用不同的CLI,不同的API或者通常不太一样的概念,那么这不会成为一个问题。选择接下来文章中的任何工具都是完全无缝的,因为它们(包括Docker)都遵循了OCI(Open Container Initiative)的相同规范。这个规范中包含了容器的运行时,分布式,镜像,涵盖了容器需要的所有特性。
由于OCI的存在,你可以选择一套最适合你的工具集,与此同时,仍然可以使用相同的API和CLI命令,就像Docker一样。
所以,如果你想尝试新的工具,接下来我们比较一下Docker和它的竞争对手都有哪些优缺点和特性,看看是不是有必要考虑放弃Docker,而使用一些新的亮瞎眼的工具。
容器引擎
在比较Docker和其他亮瞎眼的工具时,我们需要将其分解为组件。首先我们要讨论的是容器引擎。容器引擎是一种可以提供操作镜像和容器用户接口的一种工具,有了它你就不需要处理SECCOMP机制或者SELinux策略等一系列的事情。它的工作还包括从远程仓库中拉取镜像并将其扩展到硬盘。它看起来也运行容器,但实际上它的工作是创建容器清单和带有镜像层的目录。然后将他们传递到容器运行时,就像runc或crun(稍后讨论)。
现在有许多可用的容器引擎,但Docker众多的竞争中最突出的是Red Hat开发的Podman。和Docker不同的是,Podman不需要守护进程来运行,也不需要root权限,这是Docker长期以来关注的问题。Podman不仅可以运行容器,还可以运行pod。如果你不熟悉pod的概念,pod就是Kubernetes中的最小可部署计算单元。它由一个或多个容器组成执行任务。这使Podman的用户能更容易的将作业迁移到Kubernetes。因此,作为一个简单的演示,接下来就是如果在一个pod中运行两个容器:
~ $ podman pod create --name mypod
~ $ podman pod list POD ID NAME STATUS CREATED # OF CONTAINERS INFRA ID
211eaecd307b mypod Running 2 minutes ago 1 a901868616a5 ~ $ podman run -d --pod mypod nginx # First container
~ $ podman run -d --pod mypod nginx # Second container
~ $ podman ps -a --pod CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD POD NAME
3b27d9eaa35c docker.io/library/nginx:latest nginx -g daemon o... 2 seconds ago Up 1 second ago brave_ritchie 211eaecd307b mypod
d638ac011412 docker.io/library/nginx:latest nginx -g daemon o... 5 minutes ago Up 5 minutes ago cool_albattani 211eaecd307b mypod
a901868616a5 k8s.gcr.io/pause:3.2 6 minutes ago Up 5 minutes ago 211eaecd307b-infra 211eaecd307b mypod
最后,Podman提供来和Docker完全一样的CLI命令,你只需要将docker重命名为podman即可。
除了Docker和Podman,还有其他的容器引擎,但我认为它们都是穷途末路,或者不适合本地开发。但想要有一个完整的画面,我们至少要提到还有哪些:
- LXD——LXD是LXC(Linux容器)的容器管理器(守护进程)。该工具提供了运行系统容器的能力,这些系统容器提供了类似于VM的容器环境。它位于非常狭窄的空间中,没有许多用户,所以除非有具体的用例,你最好使用Docker或Podman。
- CRI-O——当你通过google查询什么是CRI-O时,你可能会发现它被描述成容器引擎。不过,它实际上是容器运行时。它是专门为Kubernetes运行时而构建的,而不是用户使用的终端。
- rkt——rkt是由CoreOS开发的容器引擎。这里提到了这个项目仅仅是为了画面的完整性,因为这个项目已经结束了,开发也停止了,因此它不该被使用。
构建镜像
对于容器引擎来说,Docker只有一种选择。但是当构建镜像时,我们可以有很多的选择。
首先介绍一下Buildah。这是Red Hat开发的另一个工具,它和Podman的组合更配。如果你已经安装了Podman,可能会注意到Podman的构建命令实际上是伪装的Buildah,因为它的二进制文件包含在Podman中。
作为它的特性,它和Padman有相同的路线——它是不需要守护进程和root权限,并产生OCI的镜像,所以它保证你的镜像能与Docker构建相同的方式运行。它还能从Dockerfile或者Containerfile构建镜像,这是两种相同的东西,但是有不同的名称。除此之外,Buildah还对镜像层提供了更好的控制,允许你在单一层中提交更改。但与Docker的区别是,由Buildah构建的镜像是属于特定用户的,因此你可以只列出来自己构建的镜像。
现在考虑到Buildah已经包含在了Podman CLI中,你可能会问,为什么还要使用单独的Buildah CLI?Buildah CLI是Podman中包含的命令的超集,所以你可能不需要接触Buildah CLI,通过使用它你可能会发现一些额外的特性。
综上所述,我们来看一个演示:
~ $ buildah bud -f Dockerfile . ~ $ buildah from alpine:latest # Create starting container - equivalent to "FROM alpine:latest"
Getting image source signatures
Copying blob df20fa9351a1 done Copying config a24bb40132 done Writing manifest to image destination
Storing signatures
alpine-working-container # Name of the temporary container
~ $ buildah run alpine-working-container -- apk add --update --no-cache python3 # equivalent to "RUN apk add --update --no-cache python3"
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
... ~ $ buildah commit alpine-working-container my-final-image # Create final image
Getting image source signatures
Copying blob 50644c29ef5a skipped: already exists
Copying blob 362b9ae56246 done Copying config 1ff90ec2e2 done Writing manifest to image destination
Storing signatures
1ff90ec2e26e7c0a6b45b2c62901956d0eda138fa6093d8cbb29a88f6b95124c ~ # buildah images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/my-final-image latest 1ff90ec2e26e 22 seconds ago 51.4 MB
从上面的脚本中你可以看出来,使用Buildah bud构建镜像是很简单的,bud的意思是使用Dockerfile来构建,但是你也可以使用脚本的方式使用Buildahs from,run和copy,这些命令和Dockerfile中是等价的。
下一个要介绍的是谷歌的Kaniko。Kaniko也是从Dockerfile构建镜像,与Buildah类似,它也不需要守护进程。Kaniko与Buildah的主要区别是Kaniko更专注于在Kubernetes中构建镜像。
Kaniko意味着通过使用gcr.io/kaniko-project/executor可以作为镜像被运行,这对于Kubernetes来说是有意义的,但是对于本地构建来说不太方便,并且在一定程度上违背了目的,因为你需要使用Docker来运行Kaniko镜像来构建你的镜像。这等于说,如果你在寻找在Kubernetes集群中构建镜像的工具,那么Kaniko可能是一个不错的选择,因为它是不需要守护进程,而且更安全。
以我的个人经验来看——我在Kubernetes/OpenShift集群中使用了Kaniko和Buildah来构建镜像,都能很好地完成工作,但在使用Kaniko时,我遇到了一些将镜像导入registry时的随机构建崩溃和失败。
第三个竞争者是buildkit,也被称为是下一代docker。它是Moby项目的一部分,可以使用DOCKER_BUILDKIT=1 启用Docker。那么,这到底会带来什么呢?它引入了许多改进和很牛的特性,包括并行构建步骤、跳过未使用阶段、更好的增量构建和无root构建。但另一方面,它仍然需要运行守护进程。所以,如果你不想摆脱Docker,但是想要一些新的特性和更好的改进,那么使用buildkit可能是最好的选择。
这里我们也有一些值得被提到的具体用例,但它们并不是我的首选:
- Source-To-Image (S2I) 是一个不使用Dockerfile直接从源代码构建镜像的工具包。这个工具在简单的、预期的场景和工作流中工作得很好,但是如果你需要很多的定制,或者项目没有预期的布局,那么它很快就会变得很烦人和笨拙。如果你对Docker还不是很有信心,或者在OpenShift集群上构建映像,你可能会考虑使用S2I,因为使用S2I构建是一个内置特性。
- Jib是谷歌开发的另一个工具,专门用于构建Java镜像。它包括Maven和Gradle插件,可以轻松地构建镜像,而不会干扰dockerfile。
- 最后但并非不重要的是Bazel,它是谷歌的另另另另一个工具。它不仅用于构建容器镜像,而是一个完整的构建系统。如果你只是想构建一个镜像,那么钻研Bazel可能有点过头,但绝对是一个很好的学习体验,所以如果你愿意,rules_docker部分是一个很好的起点。
容器运行时
最后一个难题是容器运行时,它负责运行容器。容器运行时是整个容器生命周期的一部分,除非你对su速度,安全有非常具体的要求,否则你可能不会修改它。所以,如果读到这里你觉得厌倦了,那么你可以跳过这一部分。另一方面,如果你只是想知道有哪些选择,具体如下:
runc是基于OCI容器运行时规范而创建的最流行的容器运行时。Docker(通过containerd)、Podman和CRI-O都在使用它,所以几乎所有东西都希望使用LXD。可以添加的东西不多,它是所有东西的默认值,所以即使你在阅读本文后放弃Docker,也很可能仍然会使用runc。
runc的另一种类似的方法是crun。这是Red Hat开发的工具,完全用C编写(runc是用Go编写的)。这使得它比runc更快,内存效率更高。考虑到它也是OCI兼容的运行时,如果你想自检的话,应该可以很容易地切换到它。尽管它现在还不是很流行,但在预览版中,它将作为一个替代OCI运行时的RHEL 8.3版本,考虑到它是Red Hat的产品,我们可能最终会看到它作为Podman或CRI-O的默认版本。
说到CRI-O。前面我说过,CRI-O不是一个真正的容器引擎,而是容器运行时。这是因为CRI-O不包括像推送镜像这样的特性,而这正是你所期望的容器引擎特性。作为运行时的CRI-O在内部使用runc运行容器。你不应该在机器上尝试使用这个运行时,因为它被构建为用于Kubernetes节点上的运行时,您可以看到它被描述为“Kubernetes需要的所有运行时,仅此而已”。因此,除非您正在设置Kubernetes集群(或OpenShift集群),否则您可能不应该接触这个。
本节的最后一个内容是containerd,它是CNCF的一个毕业项目。它是一个守护进程,充当各种容器运行时和操作系统的API。在后台它依赖于runc,是Docker引擎的默认运行时。它也被谷歌Kubernetes引擎(GKE)和IBM Kubernetes服务(IKS)使用。它是Kubernetes容器运行时接口的一个实现(与CRI-O相同),因此它是Kubernetes集群运行时的一个很好的候选对象。
镜像检测和分布式
容器栈的最后一部分是图像的检测与分布式。这有效地替代了docker检查,还增加了远程registry之间复制/镜像镜像的能力。
这里我要提到的唯一可以完成这些任务的工具是Skopeo。它由Red Hat制作,是Buildah, Podman和CRI-O的配套工具。除了我们都从Docker中知道的基本的skopeo检查之外,skopeo还能够使用skopeo copy复制镜像,它允许您在远程registry之间镜像映像,而无需首先将它们拉到本地registry。如果您使用本地registry,此功能也可以作为拉取/下载。
另外,我还想提一下Dive,这是一个检查、探索和分析镜像的工具。它对用户更友好一些,提供了更可读的输出,可以更深入地挖掘你的镜像,并分析和衡量其效率。它也适合在CI管道中使用,它可以测量你的镜像是否“足够高效”,或者换句话说——它是否浪费了太多空间。
结论
本文的目的并不是要说服你完全抛弃Docker,而是向您你展示构建、运行、管理和分发容器及其映像的整个场景和所有选项。包括Docker在内的每一种工具都有其优缺点,评估哪一组工具最适合你的工作流和用例是很重要的,我希望本文能在这方面帮助你。
欢迎关注我的公众号,如果你有喜欢的外文技术文章,可以通过公众号留言推荐给我。
向Docker告别的时候到了的更多相关文章
- 使用Docker构建持续集成与自动部署的Docker集群
为什么使用Docker " 从我个人使用的角度讲的话 部署来的更方便 只要构建过一次环境 推送到镜像仓库 迁移起来也是分分钟的事情 虚拟化让集群的管理和控制部署都更方便 hub.docke ...
- 隔离 docker 容器中的用户
笔者在前文<理解 docker 容器中的 uid 和 gid>介绍了 docker 容器中的用户与宿主机上用户的关系,得出的结论是:docker 默认没有隔离宿主机用户和容器中的用户.如果 ...
- 在Linux的Windows子系统上(WSL)使用Docker(Ubuntu)
背景 平时开发大部人都是在提供了高效GUI的window下工作,但是真正部署环境普遍都是在Linux中,所以为了让开发环境和部署环境统一,我们需要在windows模拟LInux环境,以前我们可能通过虚 ...
- 【02】循序渐进学 docker:如何安装
写在前面的话 我们接下来的操作都是 CentOS 7.5 以下完成的,为了避免你我结果不一致,建议你也采用 CentOS 7.5,原因如下: 1. 个人几年工作下来经历的公司,包括身边的运维朋友,90 ...
- docker持续集成部署、csphere监控平台【转:http://blog.csdn.net/java_dyq/article/details/51997024】
为什么使用Docker “ 从我个人使用的角度讲的话 部署来的更方便 只要构建过一次环境 推送到镜像仓库 迁移起来也是分分钟的事情 虚拟化让集群的管理和控制部署都更方便 hub.docker.com ...
- 十分钟搭建微服务框架(SpringBoot +Dubbo+Docker+Jenkins源码)
本文将以原理+实战的方式,首先对“微服务”相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统. 这套微服务框架能干啥? 这套系统搭建完之后,那可就厉害了: 微服务架构 你的整个应用程 ...
- 如何解决docker 官方镜像拉取慢的问题
转自: http://skycity.today/?thread-307.htm 国内从 docker 官方 Registry 拉取 image 慢的解决,步骤如下: 1.注册一个阿里云账号. 2.阿 ...
- 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)...
原文:手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 本文你将学到什么? 本文将以原理+实战的方式,首先对& ...
- windows下安装linux虚拟机(wsl2),并安装docker。
一.windows terminal(重要工具,但也可以不装) 这是微软官方推荐的终端工具,类似mac的iterm2,可同时开启多个终端,最开始默认有power shall,cmd,可下载gsudo集 ...
随机推荐
- JZOJ 11.14 提高B组反思
JZOJ 11.14 提高B组反思 T1 题目虽然有点高大上,但是很容易懂 有一个\(d\)维空间,同时有一个长度为\(2n\)的操作序列,每个操作往某一维的正方向或反方向走一格,问多少种方案使得最后 ...
- 极简Linux下安装极简桌面
sudo apt install -y xorg lxde-core vnc4server 设置密码:vncpasswd 然后先开启服务,然后再终止服务:(这是为了创建一个默认的配置文件)vncser ...
- PyQt(Python+Qt)学习随笔:QListView的selectionRectVisible属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QListView的selectionRectVisible属性用于控制视图中的选择矩形框是否可见, ...
- [BJDCTF 2nd]duangShell 反弹shell
[BJDCTF 2nd]duangShell [BJDCTF 2nd]duangShell 点击进去之后提示我们swp源代码泄露,访问http://xxx/.index.php.swp下载该文件 ...
- jarvisoj babyphp
jarvisoj babyphp 涉及知识点: (1)GitHack处理.git源码泄露 (2)php代码注入 解析: 进入题目界面. 看到题目中的用了git那么第一反应肯定是可能存在.git源码泄露 ...
- CTFHub Web题学习笔记(SQL注入题解writeup)
Web题下的SQL注入 1,整数型注入 使用burpsuite,?id=1%20and%201=1 id=1的数据依旧出现,证明存在整数型注入 常规做法,查看字段数,回显位置 ?id=1%20orde ...
- c++如何按照map的value进行排序?
static bool cmp(pair<char, int> a , pair<char,int> b) { return a.second>b.second; //按 ...
- js之数组乱序
这是最近面试遇到的,不过忘记了,之前也有印象刷到过这道题,就再次记录一下加深印象吧,听到最多的答案是利用sort方法,不过也有说这种方法不好,利用了快排和插入排序,那就整理下吧 <!DOCTYP ...
- jquery 执行a 标签 点击事件 跳转href 路径
<a href="./export.pdf" id="pdfdown" download="文件名.pdf">下载</a& ...
- 利用神经网络算法的C#手写数字识别(一)
利用神经网络算法的C#手写数字识别 转发来自云加社区,用于学习机器学习与神经网络 欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 下载Demo - 2.77 MB (原始地址):handwri ...