编程导航容器话题讨论

容器

12 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

容器化初步——浅析 runc,containerd 和 docker

<html> <head></head> <body> <div class="content ql-editor"> <p>容器化技术很多人都不陌生,docker 作为一个运维和部署工具,已经快成为广大工程师的必备技能了。但是剖析docker 内部组件的文章却并不多。很多人可能不知道 docker 背后是由多个组件构成的,本文试图浅显地解释一下 docker 的几个核心组件,以及它们之间的关系。</p> <p><br></p> <h2>runc</h2> <p><br></p> <p>runc 是一个用来运行容器的命令行工具,没错,如果你只想运行一个“容器”,其实你并不需要 docker ,runc 就足够了,而且步骤相当简单。</p> <p><br></p> <p>为了介绍下面的部分,首先我们得理解一下容器是如何被描述的。为了被避免一个或多个商业公司垄断,容器的标准是由一个开放组织维护的,就是大名鼎鼎的 <a href="http://Open%20Container%20Initiative" target="_blank">OCI(Open Container Initiative)</a>。OCI 在 <a href="http://Open%20Container%20Initiative" target="_blank">runtime-spec</a> 这个仓库里描述了容器有关的具体标准(specification),各大厂家按照这个统一的标准做出来的各种组件,理论上就是可以通用的。统一标准而不是统一实现,这个思想和 Java 的 Servlet 以及 Python 的 WSGI 有异曲同工之妙。</p> <p><br></p> <p>OCI 定义的容器标准内容非常多,超出了这篇文章所想涉及的范畴,我们还是专注于实操。简单说一个容器的内容由两部分组成,一部分是<a href="http://config.json" target="_blank">config.json</a>用来存放描述性信息,另一部分是 rootfs 根文件系统,包含容器内部的实际内容。用 runc spec 可以生成一个config.json</p> <div class="ql-code-block-container"> <div class="ql-code-block"> mkdir liu_container </div> <div class="ql-code-block"> cd liu_container </div> <div class="ql-code-block"> runc spec </div> </div> <p>目录下会生成一个<a href="http://config.json" target="_blank">config.json</a>,内容如下:</p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-punctuation">{</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"ociVersion":</span> <span class="ql-token hljs-string">"1.0.2-dev",</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"process":</span> <span class="ql-token hljs-punctuation">{</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"terminal":</span> <span class="ql-token hljs-keyword">true,</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"user":</span> <span class="ql-token hljs-punctuation">{</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"uid":</span> <span class="ql-token hljs-number">0,</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"gid":</span> <span class="ql-token hljs-number">0</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-punctuation">},</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-attr">"args":</span> <span class="ql-token hljs-punctuation">[</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-string">"sh"</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-punctuation">},</span> </div> <div class="ql-code-block"> <span class="ql-token hljs-string">"..."</span> </div> <div class="ql-code-block"><span class="ql-token hljs-punctuation">}</span> </div> </div> <p>这个JSON里面就是容器的一些描述性信息。熟悉Linux的同学应该应该对rootfs不陌生,我们使用下面这个命令,获取一个docker镜像内部的rootfs:</p> <div class="ql-code-block-container"> <div class="ql-code-block"><span class="ql-token hljs-built_in">cd</span> liu_contaier </div> <div class="ql-code-block"><span class="ql-token hljs-built_in">mkdir</span> rootfs </div> <div class="ql-code-block"> docker <span class="ql-token hljs-built_in">export</span> $(docker create alpine) | tar -C rootfs -xf - </div> </div> <p>然后我们就可以使用下面这个命令运行容器了:</p> <div class="ql-code-block-container"> <div class="ql-code-block"> cd liu_container </div> <div class="ql-code-block"> sudo runc run liu_container </div> <div class="ql-code-block"> / # </div> </div> <p>当然这只是最基础的容器运行方法,不管是runc的配置还是命令行工具,都有大量的配置选项可供选择。通过这个部分我们应该了解了,总结一下,runc是一个运行容器的命令行工具,在底层为容器的运行提供了支持。</p> <blockquote> <div class="blockquote-item"> 前面提到过,runc面向的是OCI的spec。因此实现并不是唯一的,和runc实现了相同接口的,还有包括谷歌的 gvisor 等其他工具等,感兴趣的可以了解一下。 </div> </blockquote> <p><br></p> <h2>Containerd</h2> <p><br></p> <p>说完了runc,往上一层是containerd。熟悉Linux的同学应该知道,以d为结尾的程序,一般是守护进程。containerd就是一个管理容器的守护进程,它向下使用runc完成容器的执行,向上提供GPRC的API,方便完成各种管理操作。这里引用一张containerd官网的图片,用来描述containerd的架构:</p> <p><br></p> <p><img src="https://pic.code-nav.cn/planet_post_image/1650873084049141762/ej5nxf16.jpeg"></p> <p><br></p> <p>还是进入实操,到contaienrd这个级别,我们已经可以直接进行image和container的管理了。containerd实现了OCI的镜像标准,也就是说我们不用自己拼rootfs,而是可以直接使用现成的alpine镜像了。</p> <p><br></p> <p>我们使用containerd的管理工具ctr,可以直接这样操作:</p> <div class="ql-code-block-container"> <div class="ql-code-block"> $ sudo ctr image pull docker.io/library/alpine:latest </div> <div class="ql-code-block"> $ sudo ctr image list </div> <div class="ql-code-block"> REF TYPE DIGEST SIZE PLATFORMS LABELS </div> <div class="ql-code-block"> docker.io/library/alpine:latest application/vnd.docker.distribution.manifest.list.v2+json sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126 3.2 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - </div> </div> <p>当然运行container也不在话下:</p> <div class="ql-code-block-container"> <div class="ql-code-block"> $ sudo ctr run -t docker.io/library/alpine:latest my_demo_container sh </div> <div class="ql-code-block"> / # </div> </div> <p>查看当前运行的container:</p> <div class="ql-code-block-container"> <div class="ql-code-block"> $ sudo ctr container ls </div> <div class="ql-code-block"> CONTAINER IMAGE RUNTIME </div> <div class="ql-code-block"> my_demo_container docker.io/library/alpine:latest io.containerd.runc.v2 </div> </div> <p>可以看到containerd的操作实际上和docker已经比较接近了,只不过containerd相对要更底层一些,对上层调用来说会更方便。例如containerd同时支持了Kubernetes的CRI接口标准,因此Kubernetes可以直接使用containerd作为容器runtime。</p> <p><br></p> <h2>Docker</h2> <p><br></p> <p>说了这么多终于到了大家最熟悉的docker。docker实际上背后也是使用了containerd,然后在上层封装了自己的命令行工具和其他组件。docker的操作就是最方便的了:</p> <div class="ql-code-block-container"> <div class="ql-code-block"> $ docker run -t alpine:latest sh </div> <div class="ql-code-block"> / # </div> </div> <p>docker在containerd的基础增加了什么呢?简单说有这么几块:</p> <p><br></p> <ol> <li data-list="ordered"><span class="ql-ui"></span>方便的管理方式。docker在container的基础上,提供了cp,exec等命令,并且封装了volume和mount等操作,让我们无需接触底层的各种spec,也可以方便地完成容器有关的任务。</li> <li data-list="ordered"><span class="ql-ui"></span>高级网络管理。docker中可以完成container和主机之间的各种端口映射操作,背后依托的是一个叫<a href="https://windsock.io/the-docker-proxy/" target="_blank">docker-proxy</a>的额外程序。</li> <li data-list="ordered"><span class="ql-ui"></span>提供Docker Engine API。Docker本身自己也是有一套API标准的,还有一些<a href="https://github.com/docker/docker-py" target="_blank">docker-py</a>这样的SDK方便大家调用。</li> </ol> <p><br></p> <p>这篇文章到这就结束了,希望能让大家对docker背后的组件能有所了解。</p> </div> </body> </html>

Podman Desktop

地址:https://github.com/containers/podman-desktop

《AI开发者的Docker实践》

地址:https://www.aliyundrive.com/s/tNCCsjFrc19

《第一本 Docker 书》

提取码:asdf 地址:https://pan.baidu.com/share/init?surl=zUkLwiC8Y9rQ-1RXSO19Kg

《每天 5 分钟玩转 Docker 容器技术》

提起码:asdf 地址:https://pan.baidu.com/share/init?surl=T8RLPz-OK1wAvnuVJwNuzA

Docker的使用

Docker 是一个开源的应用容器引擎,基于 Go 语言开发。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。 地址:https://www.cnblogs.com/missjie/p/12096478.html

Moby

一个新的开源项目,旨在推动软件的容器化,并帮助生态系统使容器技术主流化。它提供了一个组件库,一个组装这些组件成为容器化体系的框架,和一个可以容纳所有容器爱好者的社区。 通过 Moby 可以将定制化的组件打包做成一个 Docker,而 Moby 就相当于一个组件仓库与 Docker 工厂。 地址:https://github.com/moby/moby

Docker Hub

地址:https://hub.docker.com

Docker Blog

阅读优秀的 Docker 文章,学习前沿技术 地址:https://www.docker.com/blog/

Docker 从入门到实践

本书既适用于具备基础 Linux 知识的 Docker 初学者,也希望可供理解原理和实现的高级用户参考。同时,书中给出的实践案例,可供在进行实际部署时借鉴。前六章为基础内容,供用户理解 Docker 的基本概念和操作;7 ~ 9 章介绍包括数据管理、网络等高级操作;第 10 ~ 12 章介绍了容器生态中的几个核心项目;13、14 章讨论了关于 Docker 安全和实现技术等高级话题。后续章节则分别介绍包括 Etcd、Fedora CoreOS、Kubernetes、容器云等相关热门开源项目。最后,还展示了使用容器技术的典型的应用场景和实践案例。 地址:https://vuepress.mirror.docker-practice.com/

下载 APP