docker 系列:底层知识

简介: Docker 采用的是 **C/S 架构**,使用 REST API、UNIX 套接字或网络接口进行通信。一般客户端会和 Docker 服务运行在同一台机子上,像我们平常使用的 docker build、pull、run 等命令就是发送到本地客户端上的,本地客户端再发送给 Docker 服务端。另外,客户端也可以独立部署,像 Docker Compose。

总体架构

Docker 采用的是 C/S 架构,使用 REST API、UNIX 套接字或网络接口进行通信。一般客户端会和 Docker 服务运行在同一台机子上,像我们平常使用的 docker build、pull、run 等命令就是发送到本地客户端上的,本地客户端再发送给 Docker 服务端。另外,客户端也可以独立部署,像 Docker Compose。

Docker 服务一般是以守护进程的形式运行,它会监听客户端的请求,并且进行容器的构建、运行和分发,下面即 Docker 的总体架构

docker 架构

  • Docker 守护进程:侦听 Docker API 请求并管理 Docker 对象,例如镜像、容器、网络和卷。守护进程还可以与其他守护进程通信以管理 Docker 服务。
  • Docker 客户端:通过 Docker API 发送命令给 Docker 守护进程(dockerd),让守护进程执行对应的命令动作,例如发送 docker run 命令。
  • Docker Registry:存储了 Docker 镜像。像 Docker Hub 就是一个任何人都可以使用的公共注册中心,Docker 会默认地从 Docker Hub 上查找镜像。当然,我们也可以自己搭建个 Docker Registry。

容器的演变

一开始,Docker 是基于 Linux 内核提供的技术进行容器管理的,它将 Linux 复杂的容器管理进行了简化,形成了自己独有的一套命令体系。后来,Docker 将底层技术进行了抽象,定义了一组接口,只要实现了这组接口,那么就可以进行容器的管理,这就是 Libcontainer

随着 Docker 的火热,越来越多的公司加入容器技术的开发,在 2015 年谷歌、微软、Docker 等公司成立了 OCI 组织,致力于定制一致的容器标准。在 Libcontainer 的基础上推出了容器引擎: runC

可能大家会比较好奇的是 windows 的容器架构又是怎么样的?其实在 windows 上也抽象出来了 CGroupNamespace,它也是符合 OCI 容器标准的,如下图:

容器之windows

容器之Linux

(图片来自 Black Belt 在 DockerCon 的演讲:Docker 与 Windows 容器揭秘

底层技术

Docker 是用 Go 语言编写的,所以天生就支持这种跨平台的部署。不过主流的服务器都是 Linux 系统,所以我们来看看关于 Linux 的容器底层技术:Namespaces(资源隔离)CGroups (资源限制)UnionFS (镜像和容器分层)

Namespaces(资源隔离)

Namespaces 是 Linux 内核在 2.4.19 版本后陆续引入的概念,它将系统的全局资源通过抽象划分,使得在同一 namespace 中的进程看起来拥有自己的全局资源。当前 Linux 支持以下六种 Namespace

namespace 隔离的系统资源
Mount namespaces 文件系统挂接点
IPC namespaces 特定的进程间通信资源
UTS namespaces nodename 和 domainname
PID namespaces 进程 ID
Network namespaces 网络相关的系统资源
User namespaces 用户和组 ID 空间

我们可以看到有 Network 网络的,也有用户 User 的 隔离。当容器被创建时,会创建上面对应的 Namespace 实例,然后将容器进程划分到此 Namespace 里,以此实现了隔离功能。

CGroups(资源限制)

上面的 Namespace 为我们提供了环境隔离的功能,但这还远远不够,因为各个进程所使用的资源还是没有限制的,比如 CPU、内存等。一旦某个容器超过上限,则有可能会被 kill。因此,对资源的限制使用就很重要了,而 Linux 内核的 CGroups 就提供了此功能。

当我们创建了一个容器时,默认的会在 /sys/fs/cgroup 目录下生成对应的资源使用目录,比如 docker run nginx:test,则会在 /sys/fs/cgroup/memory/docker/nginx容器ID 目录下有对应的资源描述文件:

资源限制

使用命令 docker run --memory 1024M nginx:test时,就可以进行内存资源的限制了。其他资源限制命令也类似。

UnionFS(镜像和容器分层)

Linux 的 UnionFS (联合文件系统) 技术是用来将不同物理位置的目录合并挂载到同一个目录中。实际上 UnionFS 在不同的系统上有不同的实现,现在主流的是 AUFS、Devicemapper 和 OverlayFS。在 Docker 中最常用的是 AUFS,我们主要来看看 AUFS 的相关知识。

首先,默认情况下 AUFS 有个特点,就是要联合的第一个文件是可读可写的,后面的文件目录则只能只读。例如,我们将 teacher、student 目录联合到 mnt 目录下:

# 将 teacher 和 student 联合到 mnt
sudo mount -t aufs -o dirs=./teacher:./student none ./mnt

├── teacher
│   ├── A
│   └── C
└── student
    ├── B
    └── C

# 查看./mnt
$ tree ./mnt

├── A
├── B
└── C

当我们对 mnt 下的 C 目录修改后,会在 teacher 目录下同步看到修改,但 student 目录就不会被修改了,因为它是只读的。那这样的机制在 Docker 里有什么作用呢?

首先,Docker 将文件系统分为容器层和镜像层,这里的容器层相当于上面的 teacher 目录,镜像层相当于 student 目录。也就是容器层文件是可读可写,而镜像层是只读的。这样的话,有利于多个容器共享一个镜像文件。

而且 Docker 在一开始的时候并不会创建容器层,而是先使用镜像层文件,只有当容器里的文件发生了修改,此时才会真正的创建出可读可写的容器层,以保证不影响镜像层文件。而这种类似写时复制技术,为系统节省了很多不必要的存储文件。

Docker 的安全

在审查 Docker 的安全性时,主要从下面四个方面考虑:

(一)Namespaces、CGroups 的安全

Docker 容器与 LXC 容器非常相似,它们具有一样的安全特性。Namespaces 提供了第一种也是最直接的隔离形式,使得在容器内运行的进程无法看到在另一个容器或主机系统中运行的进程。每个容器也有属于自己的网络堆栈,这意味着一个容器不能获得对另一个容器的套接字或接口的特权访问。

CGroups 是 Linux 容器的另一个关键组件,能对资源进行核算和限制,提供了许多有效指标,确保每个容器获得公平的资源使用(例如内存、CPU、磁盘 I/O),使得单个容器无法耗尽系统资源。这在多租户平台(例如 PaaS)上尤为重要,能保证用户一致的正常运行性能。

(二)Docker 守护进程的安全性

运行 Docker 守护进程是需要 root 特权的,因此只有受信任的 User 才能运行 Docker 守护进程。但是由于 Docker 是允许主机和容器共享文件夹的,如果我们将系统文件映射到 Docker 容器里,那肯定也是能突破系统防护的。不过,这主要取决于我们关联的主机文件,一般还比较好控制。

Docker 也需要防止某些非法请求创建了破坏性的容器。在 0.5.2 之后为了防止一些恶意用户的跨站脚本攻击,Docker 使用了本地的 UNIX 套接字而不是绑定在 127.0.0.1 上的 TCP 套接字,这样就允许用户进行本地权限检查,以进行安全访问了。

(三)Linux 内核的安全

默认情况下,Docker 启动的是一组功能受限的容器,这使得容器中的“root”比真正的“root”拥有更少的特权,例如:

  • 禁止任何挂载操作;
  • 禁止访问本地套接字(以防止数据包欺骗);
  • 禁止某些文件系统的操作,例更改文件所有者或属性;
  • 禁止模块加载;

这使得入侵者设法升级到容器内的 root,也很难以对主机造成严重性的破坏。

(四)其他内核安全特性

  • 允许配置只能拉取指定秘钥签名的镜像仓库
  • 使用 GRSEC 和 PAX 运行内核,在编译和运行时增加许多安全检查
  • 使用具备安全特性的容器模板
  • 自定义访问控制策略
相关文章
|
数据可视化 关系型数据库 MySQL
《docker从零到壹》相关系列 目录
《docker从零到壹》相关系列 目录
131 0
|
Ubuntu 数据中心 开发者
[Docker系列·0] Docker101
###Docker是什么 [翻译自 whatisdocker](https://www.docker.com/whatisdocker/) >Docker is an open platform for developers and sysadmins to build, ship, and run distributed applications. Consisting of Docke
3633 1
|
程序员 虚拟化 Docker
Docker深入浅出系列——Docker简介
我是架构师张飞洪,钻进浩瀚代码,十年有余,人不堪其累,吾不改其乐。如果你和我的看法不一样,请关注我的头条号,我们一起奇闻共赏,疑义相析。 本节属于入门简介,从三个小方面进行简单介绍Docker。
1294 0
|
Shell Linux Docker
[Docker系列·1] Docker第一步
###安装Docker Docker支持很多种宿主操作系统(详见[installation](https://docs.docker.com/installation/ )),这里以CentOS为例,简述安装: Docker使用EPEL发布,RHEL系的OS首先要确保已经持有EPEL仓库,否则先检查OS的版本,然后安装相应的EPEL包。 **6.5 yum安装** ```
2753 0
|
4天前
|
JSON JavaScript 开发者
Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
【8月更文挑战第7天】Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
Composerize神器:自动化转换Docker运行命令至Compose配置,简化容器部署流程
|
2天前
|
Docker 容器
|
1天前
|
缓存 开发者 Docker
Dockerfile是Docker容器化过程中的核心组件,它允许开发者以一种可重复、可移植的方式自动化地构建Docker镜像
【8月更文挑战第19天】Dockerfile是构建Docker镜像的脚本文件,含一系列指令定义镜像构建步骤。每条大写指令后跟至少一个参数,按序执行,每执行一条指令即生成新的镜像层。常用指令包括:FROM指定基础镜像;RUN执行构建命令;EXPOSE开放端口;CMD指定容器启动行为等。优化策略涉及减少镜像层数、选择轻量基础镜像、利用缓存及清理冗余文件。示例:基于Python应用的Dockerfile包括设置工作目录、复制文件、安装依赖等步骤。掌握Dockerfile有助于高效自动化构建镜像,加速应用部署。
|
1天前
|
应用服务中间件 Linux nginx
Linux虚拟机磁盘扩容、Docker容器磁盘满的问题、Docker安装nginx
这篇文章讨论了Linux虚拟机磁盘扩容的方法,包括外部配置、具体扩容步骤和扩容后的效果验证。同时,文章还涉及了Docker容器磁盘满的问题及其解决方法,如删除不必要的镜像和容器,以及调整Docker的安装路径。此外,还提到了意外情况的处理,例如误删除停止的容器后的应对措施。最后,文章还提供了使用Docker安装nginx的步骤和成功访问的截图。
Linux虚拟机磁盘扩容、Docker容器磁盘满的问题、Docker安装nginx
|
2天前
|
网络协议 Linux 网络安全
遇到Docker容器网络隔断?揭秘六种超级实用解决方案,轻松让Docker容器畅游互联网!
【8月更文挑战第18天】Docker容器内网络不通是开发者常遇问题,可能因网络配置错、Docker服务异常或防火墙阻碍等原因引起。本文提供六种解决策略:确认Docker服务运行状态、重启Docker服务、检查与自定义Docker网络设置、验证宿主机网络连接、临时禁用宿主机IPv6及检查防火墙规则。通过这些步骤,多数网络问题可得以解决,确保容器正常联网。
9 1
|
3天前
|
安全 Ubuntu Docker
深度挖掘Docker 容器
【8月更文挑战第16天】Docker容器间的连接是容器化技术的关键,支持容器与宿主机的数据交换。主要方法包括:1) 利用Docker网络驱动创建自定义网络,使容器相连通信;2) 采用Docker Compose通过配置文件简化多容器应用的部署与互联;3) 虽不推荐,早期使用--link参数实现容器互联;4) 通过环境变量配置连接信息;5) 共享卷支持文件共享和间接通信。推荐使用Docker网络和Docker Compose以实现高效灵活的容器间通信。
18 3