2023-08-23:Docker概念
学习自:02 核心概念:镜像、容器、仓库,彻底掌握 Docker 架构核心设计理念
1、Docker核心概念
Docker的操作围绕镜像、仓库、容器三大核心概念展开。
镜像
镜像是只读文件、目录的组合,它包含了容器运行时所需的所有基础文件和配置信息,是容器启动的基础。
如果你想启动一个容器,那首先必须有一个镜像。镜像是Docker容器启动的先决条件。
如果要使用一个镜像,通常有两种方式:
- 自己创建镜像。通常情况下,一个镜像是基于一个基础镜像构建的,我们可以在基础镜像上添加一些用户自定义的内容。例如,我们可以基于centos镜像制作业务镜像,首先安装nginx服务,然后部署我们的应用程序,最后做一些自定义配置,这样一个业务镜像就完成了;
- 从镜像仓库拉取别人制作好的镜像。一些常用软件或者系统(nginx、Ubuntu、centos、mysql等)都有官方已经制作好的镜像,我们可以去Docker Hub 下搜索并下载它们。
容器
容器是镜像运行的实体。
镜像是静态的只读文件,容器带有运行时需要的可写文件层,并且容器中的进程属于运行状态。也就是说,容器中运行着真正的应用进程,容器有初建、运行、停止、暂停、删除五种状态。
虽然容器本质上是主机上运行的一个进程,但是容器有自己的命名空间隔离和资源限制。在容器内部,无法看到主机上的进程、环境变量、网络等信息,这是容器与直接运行在主机上进程的本质区别。
仓库
Docker有镜像仓库,类似于代码仓库,用于存储和分发Docker镜像。
镜像仓库分为公共和私有镜像仓库。Docker Hub是Docker官方的公开镜像仓库,它不仅有很多应用或者操作系统的官方镜像,还有很多组织或者个人开发的镜像供我们免费下载使用。除了公开镜像仓库,我们也可以构建自己的私有镜像仓库。
仓库-镜像-容器关系图
从这张图中可以看出,容器是由镜像创建的,一个镜像可以创建多个容器,容器是镜像运行的实体,仓库是用于存放和分发镜像。
2、容器的发展史
容器技术随着Docker的出现变得炙手可热,很多公司都在积极拥抱容器技术。但是容器的标准是什么,由谁制定却是在Docker出现后需要讨论的问题。
除了容器标准之外,容器编排之争也很激烈,Docker出现后有三家容器编排技术:Docker Swarm、Kubernetes、Mesos。它们希望有不同的调度形式。
在这种背景下,OCI应运而生。
OCI,即Open Container Initiative 开放容器标准,是一个轻量级、开放的治理结构。OCI旨在为用户围绕工业化容器格式和运行时制定一个开放的容器标准。目前主要有两个标准文档:容器运行时标准(runtime spec)、镜像标准(image spec)。
现在的Docker技术架构如下图所示
Docker整体架构采用C/S(客户端/服务器)模式,C端负责发送操作命令,S端负责接收和处理指令。
C和S间存在多种通信方式,既可以在同一台及其上通过UNIX套接字通信,也可以通过网络连接远程通信。
Docker客户端
Docker客户端其实是个泛称。其中docker命令是Docker用户与Docker服务端交互的主要方式。
除了用docker命令外,还可以使用直接请求REST API的方式与Docker服务端进行交互,甚至还能用各种语言的SDK来与Docker进行交互。目前社区维护着Go、Java、Python、PHP等数十种语言的SDK,足以满足我们的日常需求。
Docker服务端
S端是Docker所有后台服务的统称。其中dockerd是一个重要的后台管理程序,它负责响应和处理来自C端的请求,再将C端请求转化为Docker的具体操作。例如镜像、容器、网络、挂载卷等具体对象的操作与管理。
从1.11版本开始,dockerd已经成为了独立二进制,此时容器也不是直接由dockerd来启动了,而是集成了containerd、runC等多个组件。
虽然Docker架构在不停重构,但是各个模块的基本功能与定位没有变化。它和一般的C/S系统一样,S端负责与C端交互,并管理镜像、容器、网络等资源。
3、Docker重要组件
在Docker的安装路径下,输入指令ls就能看到与docker有关的二进制文件。
如果采用dnf安装时未指定目录,那默认安装目录在/usr/bin下,可以输入以下指令来查找(这些项不一定是在最后或者最前边,但是大多数情况下是挨在一起的):
ls -trl /usr/bin -rwxr-xr-x. 1 root root 5190 7月 22 04:33 dockerd-rootless.sh -rwxr-xr-x. 1 root root 13951 7月 22 04:33 dockerd-rootless-setuptool.sh -rwxr-xr-x. 1 root root 99975880 7月 22 04:38 dockerd -rwxr-xr-x. 1 root root 2180492 7月 22 04:38 docker-proxy -rwxr-xr-x. 1 root root 35913304 7月 22 04:39 docker -rwxr-xr-x. 1 root root 12250248 7月 22 04:40 rootlesskit -rwxr-xr-x. 1 root root 7852016 7月 22 04:40 rootlesskit-docker-proxy -rwxr-xr-x. 1 root root 27178688 7月 30 03:50 ctr -rwxr-xr-x. 1 root root 9502720 7月 30 03:50 containerd-shim-runc-v2 -rwxr-xr-x. 1 root root 9474048 7月 30 03:50 containerd-shim-runc-v1 -rwxr-xr-x. 1 root root 7352320 7月 30 03:50 containerd-shim -rwxr-xr-x. 1 root root 52345280 7月 30 03:50 containerd -rwxr-xr-x. 1 root root 13623192 7月 30 03:50 runc
可以看到Docker有很多组件与工具,这里先介绍runC与containerd
- runC:Docker官方按照OCI容器运行时标准的一个实现。换句话说,runC是一个用来运行容器的轻量级工具,是真正用来运行容器的。
- containerd:Docker的S端一个核心组件,它是从dockerd中剥离出来的,是OCI容器标准化的产物。containerd通过containerd-shim启动并管理runC,可以说containerd真正管理了容器的生命周期。
S端组件调用关系图
通过上图可以看出,dockerd通过gRPC与containerd通信,由于dockerd与真正容器运行时,runC中间有了containerd这一OCI标准层,使得dockerd可以确保接口向下兼容。
- gRPC是一种远程服务调用。官网:https://grpc.io
- containerd-shim作用是将containerd与真正容器进程解耦,使用container-shim作为容器进程的父进程,从而实现重启containerd不影响已启动的容器进程。
为了了解docker、containerd、runC之间的关系,可以通过启动一个Docker容器来验证:
启动一个busybox容器
1 | docker run -d busybox sleep 3600 |
查看dockerd的PID
1 2 | ps -ef | grep dockerd root 4147 1 0 09:28 ? 00:00:01 /usr/bin/dockerd -H fd: // --containerd= /run/containerd/containerd .sock |
通过该结果可以得到dockerd的PID为1225,为了验证之前那张图(最近那张)中Docker各组件间的调用关系,可以用pstree来查看一下进程父子关系:
1 2 3 4 5 | pstree -l -a -A 4147 dockerd |-containerd --config /var/run/docker/containerd/containerd .toml --log-level info | |-containerd-shim -namespace moby -workdir /var/lib/docker/containerd/daemon/io .containerd.runtime.v1.linux /moby/d14d20507073e5743e607efd616571c834f1a914f903db6279b8de4b5ba3a45a -address /var/run/docker/containerd/containerd .sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc | | |- sleep 3600 |
以上为教程中所讲的显示内容,我自己实操时并没有显示出这一结果。
事实上,dockerd启动时,containerd就随之启动了,dockerd与containerd一直存在,当执行docker run命令(即通过busybox镜像创建并启动容器)时,containerd会创建containerd-shim,然后启动容器的真正进程sleep 3600。这个过程和架构图是完全一致的。
回顾
1、Docker有三大概念:镜像、容器、仓库
镜像
镜像是静态、未运行的文件与目录的组合,这些文件、目录包含了容器运行时所需的基础文件和配置信息,是容器运行的依据。另外,这些文件、目录都是只读的。
容器的启动依赖于一个镜像,没有镜像就启动不了容器。
镜像的获取和使用方式有两种:
- 自己创建。自建的镜像一般依赖于某个基础镜像,通过在基础镜像上添加一些用户自定义的内容,来实现特定的需求。
- 从仓库拉取别人制作好的镜像。常用软件或系统都有官方制作好的镜像,我们可以去Docker Hub搜索并下载它们。
一个业务镜像的制作过程:挑选某个基础镜像(如centos镜像)作为原材料,在其基础上修改内容,例如安装nginx服务,部署我们的应用程序,再加一些自定义配置。这样就得到了一个业务镜像。
容器
之前说过镜像是静态文件的组合,那容器就是运行起来的镜像实体。
镜像是只读文件,容器则带有运行时的可写文件层,容器中的进程属于运行状态,其中运行着真正的应用程序。
容器本身是主机上运行的一个进程,但是容器内的进程看不到主机上的资源(进程、环境变量、网络)的情况,因为实现容器需要命名空间隔离和系统资源的限制。
能否看到主机上的资源是容器与主机进程的本质区别。
仓库
仓库理解起来最简单,就是存放镜像的空间。
仓库分为公有和私有两种:
- 公有是指官方提供的,比如Docker Hub,它里边有很多应用和OS的官方镜像。
- 私有是指我们在实际的业务工作中构建出的自己的私有镜像仓库。
2、OCI:Open Container Initiative 开放容器标准,制定了两个标准:容器运行时标准、镜像标准。
3、Docker技术架构
Docker是一个C/S模式的架构:C发送操作命令,S接收和处理命令。
C和S如果位于同一台,可以通过Socket通信,位于远程连接可以用网络连接远程通信。
4、Docker C端
C与S的交互方式有两种:docker命令(主要)、直接请求REST API、各种语言的SDK。
5、Docker S端
1)S端是所有Docker后台服务的统称;
2)dockerd是一个重要的后台管理程序,负责响应、处理来自C端的请求,再将C端请求转为具体的Docker操作(对镜像、容器、网络、挂载这些具体对象的操作);
3)Docker经历了多次重构,1.11版本之后,dockerd成为了独立的二进制文件,Docker也不是直接由dockerd启动了,而是集成了containerd、runC等多个组件;
4)虽然经历了多次重构,但是C/S的结构并没有变化,各个模块的功能与定位也没变。
6、在docker安装路径下,可以看到一些二进制文件:
containerd containerd-shim ctr docker docker-init docker-proxy dockerd runc
其中:
- runC是Docker官方按照OCI运行时标准化的实现。用于运行容器的轻量级工具。
- containerd是Docker S端的核心组件,是从dockerd中剥离出来的OCI容器标准化的产物。container通过containerd-shim启动并管理runC,它是容器生命周期的真正管理者。
7、S端
1)dockerd与containerd进行通信(通过gRPC,一种远程服务调用),containerd是一个OCI标准层,可以保证接口向下兼容。
2)containerd-shime将containerd与真正容器进程解耦,使用shim作为容器进程的父进程,可以保证重启containerd不影响已启动的容器进程。
3)runc负责管理容器运行
8、
1 | docker run -d busybox sleep 3600 |
dockerd启动时(systemctl start docker),containerd就随之启动了,二者会一直存在。当docker run创建镜像并启动容器时,containerd会创建containerd-shim,再启动容器的真正进程 sleep 3600。此为之前C/S架构图中所说的工作流程。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性