目录

容器化进阶

docker

docker进程

docker容器本质上是一个进程,通过namespace实现PID资源隔离,但是一个容器并不是只能有一个进程。

Docker 容器的设计理念通常是“单一进程”的,也就是说,容器的主要目的是运行一个主要的应用程序进程。这个主要进程通常是容器的入口点,它会在容器启动时开始运行,并在容器停止时结束。

Docker与虚拟机的区别是什么?

  • 虚拟机通过添加Hypervisor层(虚拟化中间层),虚拟出网卡、内存、CPU等虚拟硬件,再在其上建立虚拟机,每个虚拟机都有自己的系统内核

  • 而Docker容器则是通过隔离(namesapce)的方式,将文件系统、进程、设备、网络等资源进行隔离,再对权限、CPU资源等进行控制(cgroup),最终让容器之间互不影响,容器无法影响宿主机。

与虚拟机相比,容器资源损耗要少。同样的宿主机下,能够建立容器的数量要比虚拟机多

但是,

  • 虚拟机的安全性要比容器稍好,而docker容器与宿主机共享内核、文件系统等资源,更有可能对其他容器、宿主机产生影响。
  • 容器劣势的主要原因,正是因为容器共享宿主机操作系统内核,因此不能像虚拟机一样模拟出完整的硬件机器充当沙盒,从而实现完全隔离。也就是说,容器是进程级的隔离,它可以通过影响宿主机操作系统内核来影响其他容器。

容器网络模式

host模式

host 模式 :使用 --net=host 指定

相当于VMware 中的桥接模式,与宿主机在同一个网络中,但是没有独立IP地址

container模式

container模式:使用–net=contatiner:NAME_or_ID 指定

这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围等。 可以在一定程度上节省网络资源,容器内部依然不会拥有所有端口。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/dfb0923408e017e9ae9ec40fd4745789/bc1b043429bbf984ba49bb1088a8ef37.png

none 模式

none模式:使用 --net=none指定

使用none 模式,docker 容器有自己的network Namespace,但是并不为Docker 容器进行任何网络配置。也就是说,这个Docker 容器没有网卡,ip, 路由等信息。

这种网络模式下,容器只有lo 回环网络,没有其他网卡。

这种类型没有办法联网,但是封闭的网络能很好的保证容器的安全性

bridge 模式使用docker run -p 时,docker实际是在iptables做了DNAT规则,实现端口转发功能。)

相当于Vmware中的 nat 模式,容器使用独立network Namespace,并连接到docker0虚拟网卡。通过docker0网桥以及iptables nat表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/dfb0923408e017e9ae9ec40fd4745789/ab1c125cd25b7526adb1e7d7c242b333.png

docker挂载

挂载目录数据卷,修改立即可见

挂着文件,修改了互不影响,除非重新运行。

Docker的文件系统是什么

UnionFS(联合文件系统)

AUFS 即 Advanced UnionFS 其实就是 UnionFS 的升级版,它能够提供更优秀的性能和效率。

UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,UnionFs联合文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

可读性特性

Union File System 联合了多个不同的目录,并且把他们挂载到一个统一的目录上。

在这些「联合」的子目录中, 有一部分是可读可写的,但是有一部分只是可读的。

当你对只读的目录内容做出修改的时候,其结果只会保存到可写的目录下,不会影响只读的目录。

比如,我们可以把我们的服务的源代码目录和一个存放代码修改记录的目录「联合」起来构成一个 AUFS。前者设置只读权限,后者设置读写权限。

在 AUFS 中还有一个特殊的概念需要提及一下:

branch – 就是各个要被union起来的目录。

Stack 结构 - AUFS 它会根据branch 被 Union 的顺序形成一个 Stack 的结构,从下至上,最上面的目录是可读写的,其余都是可读的。如果按照我们刚刚执行 aufs 挂载的命令来说,最左侧的目录就对应 Stack 最顶层的 branch。

所以:下面的命令中,最为左侧的为 home,而不是 company

1
2
3
mount -t aufs -o dirs=./home:./company none ./mnt

# 一共两个目录,./home, ./company 。那么第一个home目录将会是可写的,其他的是可读的。

Docker 是通过 AUFS 来管理 Images 的

docker制作镜像相关?(基于AUFS)

分层结构

所有的容器都是共享宿主机的内核kernel

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/dfb0923408e017e9ae9ec40fd4745789/3967a37da2f6681c528a571d3c0f27c5.png

容器 Copy-on-Write 特性

当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。 只有容器层是可写的,容器层下面的所有镜像层都是只读的

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/dfb0923408e017e9ae9ec40fd4745789/e9dde80e1f3f7aace0de4b342a967f22.png

rootfs根目录

它是操作系统启动时首先挂载的文件系统,包含了操作系统启动所需的基本文件和目录结构。rootfs 是整个系统的基础,所有其他文件系统都是以它为基础构建的。

在 Linux 系统中**,rootfs 可以是各种类型的文件系统,例如 ext4、XFS、Btrfs 等。它通常被挂载在根目录 /**

rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。

通过引入层(layer)的概念,实现了 rootfs 的复用。不必每次都重新创建一个 rootfs,而是基于某一层进行修改即可。

**在 Docker 容器启动过程中,首先会通过 chroot 系统调用将容器内的根文件系统切换到容器镜像中定义的根目录。**这样做的效果是,容器内的进程在看到的文件系统根目录会被限定在容器镜像所定义的文件系统层次结构内,而不会看到主机的其他文件系统内容。

namespace实现进程(容器)间的隔离

命名空间(namespaces)是 Linux 为我们提供的用于分离进程树、网络接口、挂载点以及进程间通信等资源的方法。在日常使用 Linux 或者 macOS 时,我们并没有运行多个完全分离的服务器的需要,但是如果我们在服务器上启动了多个服务,这些服务其实会相互影响的,每一个服务都能看到其他服务的进程,也可以访问宿主机器上的任意文件,这是很多时候我们都不愿意看到的,我们更希望运行在同一台机器上的不同服务能做到完全隔离,就像运行在多台不同的机器上一样。

通过这七个选项, 我们能在创建新的进程时, 设置新进程应该在哪些资源上与宿主机器进行隔离。具体如下:

Namespace Flag Page Isolates
Cgroup CLONE_NEWCGROUP cgroup_namespaces Cgroup root directory
IPC CLONE_NEWIPC ipc_namespaces System V IPC,POSIX message queues 隔离进程间通信
Network CLONE_NEWNET network_namespaces Network devices,stacks, ports, etc. 隔离网络资源
Mount CLONE_NEWNS mount_namespaces Mount points 隔离文件系统挂载点
PID CLONE_NEWPID pid_namespaces Process IDs 隔离进程的ID
Time CLONE_NEWTIME time_namespaces Boot and monotonic clocks
User CLONE_NEWUSER user_namespaces User and group IDs 隔离用户和用户组的ID
UTS CLONE_NEWUTS uts_namespaces Hostname and NIS domain name 隔离主机名和域名信息

Docker Engine 使用了以下 Linux 的隔离技术:

The pid namespace: 管理 PID 命名空间 (PID: Process ID).

The net namespace: 管理**网络命名空间(**NET: Networking).

The ipc namespace: 管理进程间通信命名空间(IPC: InterProcess Communication).

The mnt namespace: 管理文件系统挂载点命名空间 (MNT: Mount).

The uts namespace: Unix 时间系统隔离. (UTS: Unix Timesharing System).

User and group IDs 隔离用户和用户组的ID

  • 注意,每个进程都是有uid和gid的属性的,如果通过在容器内设置相应用户的uid。可以在一定程度上,借助docker实现提权。

通过这些技术,运行时的容器得以看到一个和宿主机上其他容器隔离的环境。

Cgroups实现资源限制分组

Control Groups(简称 CGroups)能够隔离宿主机器上的物理资源,例如 CPU、内存、磁盘 I/O 和网络带宽。

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。具体实操参见:Docker教程(三)—深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs -

CGroups 提供了四大功能:

  • 资源限制:CGroups 可以对任务需要的资源总额进行限制。比如设定任务运行时使用的内存上限,一旦超出就发 OOM。
  • 优先级分配:通过分配的 CPU 时间片数量和磁盘 IO 带宽,实际上就等同于控制了任务运行的优先级。
  • 资源统计:CGroups 可以统计系统的资源使用量,比如 CPU 使用时长、内存用量等。
  • 任务控制:CGroups 可以对任务执行挂起、恢复等操作

总结

docker为LXC+AUFS组合:

  • LXC负责资源管理
  • AUFS负责镜像管理;

而LXC包括cgroup,namespace,chroot等组件,并通过cgroup资源管理,那么,从资源管理的角度来看,Docker,Lxc,Cgroup三者的关系是怎样的呢?

cgroup是在底层落实资源管理,LXC在cgroup上面封装了一层,随后,docker有在LXC封装了一层;

https://raw.githubusercontent.com/kengerlwl/kengerlwl.github.io/refs/heads/master/image/dfb0923408e017e9ae9ec40fd4745789/3cba446703a74edd32773ac3a138a833.png

ref

Docker底层原理(图解+秒懂+史上最全) - 疯狂创客圈 - 博客园

Docker教程(三)—深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs -