docker的Namespace技术介绍

三、Linux Namespace 技术

当一个宿主机运行了 N 个容器,多个容器带来的以下问题怎么解决:
1.怎么样保证每个容器都有不同的文件系统并且能互不影响?
2.一个 docker 主进程内的各个容器都是其子进程,那么实现同一个主进程下不 同类型的子进程?各个进程间通信能相互访问(内存数据)吗?
3.每个容器怎么解决 IP 及端口分配的问题?
4.多个容器的主机名能一样吗?
5.每个容器都要不要有 root 用户?怎么解决账户重名问题? 


Linux Namespace 技术:
namespace 是 Linux 系统的底层概念,在内核层实现,即有一些不同类型的命名 空间被部署在核内,各个 docker 容器运行在同一个 docker 主进程并且共用同一 个宿主机系统内核,
各 docker 容器运行在宿主机的用户空间,每个容器都要有 类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现 运行指定服务的运行环境,
并且还可以保护宿主机内核不受其他进程的干扰和 影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现 容器运行空间的相互隔离:

隔离类型                         功能                 系统调用参数     内核版本
MNT Namespace(mount)                  提供磁盘挂载点和文件系统的隔离能力 CLONE_NEWNS      Linux 2.4.19
IPC Namespace(Inter-Process Communication)   提供进程间通信的隔离能力         CLONE_NEWIPC     Linux 2.6.19
UTS Namespace(UNIX Timesharing System)      提供主机名隔离能力              CLONE_NEWUTS      Linux 2.6.19
PID Namespace(Process Identification)     提供进程隔离能力                CLONE_NEWPID     Linux 2.6.24
Net Namespace(network)                 提供网络隔离能力               CLONE_NEWNET      Linux 2.6.29
User Namespace(user)                         提供用户隔离能力               CLONE_NEWUSER      Linux 3.8

1.MNT Namespace

 每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动 服务并且使用容器的运行环境,即一个宿主机是 ubuntu 的服务器,

可以在里面 启动一个 centos 运行环境的容器并且在容器里面启动一个 Nginx 服务,此 Nginx 运行时使用的运行环境就是 centos 系统目录的运行环境,

但是在容器里面是不 能访问宿主机的资源,宿主机是使用了 chroot 技术把容器锁定到一个指定的运 行目录里面。

例如:/var/lib/containerd/容器 ID

[root@localhost7C ~]# docker info  | grep "Docker Root Dir"
  WARNING: You're not using the default seccomp profile
Docker Root Dir: /var/lib/docker

[root@localhost7C ~]# docker run -d --name nginx2 -p 81:80 nginx

[root@localhost7C ~]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
5668e1f40b8e        nginx               "/docker-entrypoin..."   4 minutes ago       Up 4 minutes        0.0.0.0:81->80/tcp   nginx2
[root@localhost7C ~]# ll /var/lib/docker/containers
总用量 0
drwx------ 5 root root 168 10月 11 17:06 5668e1f40b8eea1ddc982a57b7f52069ba9d3e3dd1302856e3e14f4feb0d371d

[root@localhost7C ~]# docker exec -it nginx2 sh
# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

 2。IPC Namespace:

  一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访 问,但是不能夸容器访问其他容器的数据。

 

3。UTS Namespace:  UTS namespace(UNIX Timesharing System 包含了运行内核的名称、版本、底层 体系结构类型等信息)用于系统标识,其中包含了 hostname 和域名 domainname ,

它使得一个容器拥有属于自己 hostname 标识,这个主机名标识 独立于宿主机系统和其上的其他容器。

[root@localhost7C ~]# docker exec -it nginx2 sh
# cat /etc/issue
Debian GNU/Linux 11 \n \l

  # apt install procps (top 命令)
  # apt install iputils-ping (ping 命令)
  # apt install net-tools (网络工具)

# apt-get update
Get:1 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:2 http://deb.debian.org/debian-security bullseye-security InRelease [48.4 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [44.1 kB]
Get:4 http://deb.debian.org/debian bullseye/main amd64 Packages [8184 kB]
Get:5 http://deb.debian.org/debian-security bullseye-security/main amd64 Packages [189 kB]
Get:6 http://deb.debian.org/debian bullseye-updates/main amd64 Packages [6344 B]
Fetched 8587 kB in 2s (3687 kB/s)                         
Reading package lists... Done

# uname -a
Linux 5668e1f40b8e 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 GNU/Linux 

4。PID Namespace:

Linux 系统中,有一个 PID 为 1 的进程(init/systemd)是其他所有进程的父进程,那么在每个 容器内也要有一个父进程来管理其下属的子进程,

那么多个容器的进程通 PID namespace 进程 隔离(比如 PID 编号重复、器内的主进程生成与回收子进程等)。 例如:下图是在一个容器内使用 top 命令看到的 PID 为 1 的进程是 nginx:

dockerd: 被client直接访问,其父进程为宿主机的systemd守护进程。
docker-proxy: 每个进程docker-proxy实现对应一个需要网络通信的容器,管理宿主机和容器的之间端口映射,其父进程为dockerd,如果容器不需要网络则无需启动
containerd: 被dockerd进程调用以实现与runc交互
containerd-shim: 真正运行容器的载体,每个容器对应一个containerd-shim进程,其父进程为containerd

 

dockerf进程之间关系图:

 

 老版本说明:

新版本说明:

 

 5.Net Namespace: 

每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP 协议栈等, Docker 使用 network namespace 启动一个 vethX 接口,这样你的容器将拥有它 自己的桥接 ip 地址,通常是 docker0,

而 docker0 实质就是 Linux 的虚拟网桥,网 桥是在 OSI 七层模型的数据链路层的网络设备,通过 mac 地址对网络进行划 分,并且在不同网络直接传递数据。

  查看宿主机的网卡信息和 桥接设备:

[root@localhost7B ~]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:9ff:fed6:cd79  prefixlen 64  scopeid 0x20<link>
        ether 02:42:09:d6:cd:79  txqueuelen 0  (Ethernet)
        RX packets 2473  bytes 102859 (100.4 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3062  bytes 10048794 (9.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

vethd305791: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500  
        inet6 fe80::bc3a:f0ff:fed5:8eaa  prefixlen 64  scopeid 0x20<link>
        ether be:3a:f0:d5:8e:aa  txqueuelen 0  (Ethernet)
        RX packets 2473  bytes 137481 (134.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3057  bytes 10047634 (9.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

vethfdbd9e2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::b8df:b1ff:fe8b:b771  prefixlen 64  scopeid 0x20<link>
        ether ba:df:b1:8b:b7:71  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 22  bytes 2514 (2.4 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 52:54:00:ec:da:b8  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@localhost7B ~]# 
[root@localhost7B ~]# brctl  show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.024209d6cd79    no        vethd305791
                                       vethfdbd9e2
virbr0
8000.525400ecdab8 yes virbr0-nic

 

 

 6:User Namespace:  各个容器内可能会出现重名的用户和用户组名称,或重复的用户 UID 或者 GID,那么怎么隔离各个容器内的用户空间呢?

User Namespace 允许在各个宿主机的各个容器空间内创建相同的用户名以及相 同的用户 UID 和 GID,只是会把用户的作用范围限制在每个容器内,

即 A 容器 和 B 容器可以有相同的用户名称和 ID 的账户,但是此用户的有效范围仅是当前 容器内,不能访问另外一个容器内的文件系统,即相互隔离、互补影响、永不 相见

[root@localhost7B ~]# docker exec  -it  nginx1 bash
root@41da1df38e16:/# 
root@41da1df38e16:/# 
root@41da1df38e16:/# id
uid=0(root) gid=0(root) groups=0(root)

root@41da1df38e16:/# cat /etc/passwd
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
...
... nobody:x:
65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false

 

posted @ 2022-10-11 17:42  yuanbangchen  阅读(326)  评论(0编辑  收藏  举报