• 第 4 章 容器


    实现容器的底层技术

    cgroup 和 namespace 是最重要的两种技术。

    • cgroup 实现资源限额
    • namespace 实现资源隔离

     

    cgroup

    • cgroup 全称 Control Group。

    Linux 操作系统通过 cgroup 可以设置进程使用 CPU、内存 和 IO 资源的限额。

    • 前面我们看到的--cpu-shares-m--device-write-bps 实际上就是在配置 cgroup。
    • cgroup 存在 /sys/fs/cgroup 文件中。

    举个例子:启动一个容器,设置 --cpu-shares=512

    在 /sys/fs/cgroup/cpu/docker 目录中,Linux 会为每个容器创建一个 cgroup 目录,以容器长ID 命名:

     1 root@ubuntu:~# docker run  --name container_C -it -c 512 progrium/stress --cpu 2
     2 stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
     3 stress: dbug: [1] using backoff sleep of 6000us
     4 stress: dbug: [1] --> hogcpu worker 2 [6] forked
     5 stress: dbug: [1] using backoff sleep of 3000us
     6 stress: dbug: [1] --> hogcpu worker 1 [7] forked
     7 
     8 root@ubuntu:~# docker ps 
     9 CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    10 2200e14c5e1d        progrium/stress     "/usr/bin/stress --v…"   10 seconds ago      Up 9 seconds                                 container_C
    11 f27eb6348026        registry:2          "/entrypoint.sh /etc…"   2 weeks ago         Up 2 weeks          0.0.0.0:5000->5000/tcp   vigilant_swartz
    12 root@ubuntu:~# 
    13 root@ubuntu:~# ll /sys/fs/cgroup/cpu/docker/2200e14c5e1db5fafd029405f210fc2b208b62823cfd8cbdd7a50bdfe2cf6522/
    14 total 0
    15 drwxr-xr-x 2 root root 0 Jan 29 07:32 ./
    16 drwxr-xr-x 4 root root 0 Jan  3 11:00 ../
    17 -rw-r--r-- 1 root root 0 Jan 29 07:32 cgroup.clone_children
    18 -rw-r--r-- 1 root root 0 Jan 29 07:31 cgroup.procs
    19 -r--r--r-- 1 root root 0 Jan 29 07:32 cpuacct.stat
    20 -rw-r--r-- 1 root root 0 Jan 29 07:32 cpuacct.usage
    21 -r--r--r-- 1 root root 0 Jan 29 07:32 cpuacct.usage_percpu
    22 -rw-r--r-- 1 root root 0 Jan 29 07:32 cpu.cfs_period_us
    23 -rw-r--r-- 1 root root 0 Jan 29 07:32 cpu.cfs_quota_us
    24 -rw-r--r-- 1 root root 0 Jan 29 07:31 cpu.shares
    25 -r--r--r-- 1 root root 0 Jan 29 07:32 cpu.stat
    26 -rw-r--r-- 1 root root 0 Jan 29 07:32 notify_on_release
    27 -rw-r--r-- 1 root root 0 Jan 29 07:32 tasks            
    28 root@ubuntu:~# cat /sys/fs/cgroup/cpu/docker/2200e14c5e1db5fafd029405f210fc2b208b62823cfd8cbdd7a50bdfe2cf6522/cpu.shares 
    29 512
    30 root@ubuntu:~#

    目录中包含所有与 cpu 相关的 cgroup 配置,文件 cpu.shares 保存的就是 --cpu-shares 的配置,值为 512。

    同样的,/sys/fs/cgroup/memory/docker 和 /sys/fs/cgroup/blkio/docker 中保存的是内存以及 Block IO 的 cgroup 配置。

    namespace

    在每个容器中,我们都可以看到文件系统,网卡等资源,这些资源看上去是容器自己的。拿网卡来说,每个容器都会认为自己有一块独立的网卡,即使 host 上只有一块物理网卡。这种方式非常好,它使得容器更像一个独立的计算机。

    Linux 实现这种方式的技术是 namespace。namespace 管理着 host 中全局唯一的资源,并可以让每个容器都觉得只有自己在使用它。换句话说,namespace 实现了容器间资源的隔离

    Linux 使用了六种 namespace,分别对应六种资源:Mount、UTS、IPC、PID、Network 和 User,下面我们分别讨论。

    Mount namespace

    Mount namespace 让容器看上去拥有整个文件系统。

    容器有自己的 / 目录,可以执行 mount 和 umount 命令。当然我们知道这些操作只在当前容器中生效,不会影响到 host 和其他容器。

    UTS namespace

    简单的说,UTS namespace 让容器有自己的 hostname。 默认情况下,容器的 hostname 是它的短ID,可以通过 -h 或 --hostname 参数设置。

    1 root@ubuntu:~# docker run -it -h myhost ubuntu
    2 root@myhost:/# 
    3 root@myhost:/# hostname
    4 myhost
    5 root@myhost:/#

     

    IPC namespace

    IPC namespace 让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与 host 和其他容器的 IPC 混在一起。

    PID namespace

    我们前面提到过,容器在 host 中以进程的形式运行。例如当前 host 中运行了两个容器:

    1 root@ubuntu:~# docker ps
    2 CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    3 2200e14c5e1d        progrium/stress     "/usr/bin/stress --v…"   38 minutes ago      Up 38 minutes                                container_C
    4 f27eb6348026        registry:2          "/entrypoint.sh /etc…"   2 weeks ago         Up 2 weeks          0.0.0.0:5000->5000/tcp   vigilant_swartz
    5 root@ubuntu:~# 

    通过 ps axf 可以查看容器进程:

    1  1015 ?        Ssl   11:01 /usr/bin/dockerd -H unix://
    2 15084 ?        Sl     0:01  \_ /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5000 -container-ip 172.17.0.2 -container-port 5000
    3  1023 ?        Ssl    7:15 /usr/bin/containerd
    4 15090 ?        Sl     0:44  \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/f27eb6348026862f5744a916f67c4079d36c54fd4609
    5 15108 ?        Ssl    1:28  |   \_ registry serve /etc/docker/registry/config.yml
    6 24252 ?        Sl     0:00  \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/2200e14c5e1db5fafd029405f210fc2b208b62823cfd
    7 24271 pts/0    Ss+    0:00      \_ /usr/bin/stress --verbose --cpu 2
    8 24305 pts/0    R+    38:57          \_ /usr/bin/stress --verbose --cpu 2
    9 24306 pts/0    R+    38:57          \_ /usr/bin/stress --verbose --cpu 2

    所有容器的进程都挂在 dockerd 进程下,同时也可以看到容器自己的子进程。 如果我们进入到某个容器,ps 就只能看到自己的进程了:

     1 root@ubuntu:~# docker exec -it 2200e14c5e1d bash
     2 root@2200e14c5e1d:/# 
     3 root@2200e14c5e1d:/# ps axf
     4   PID TTY      STAT   TIME COMMAND
     5     8 pts/1    Ss     0:00 bash
     6    15 pts/1    R+     0:00  \_ ps axf
     7     1 pts/0    Ss+    0:00 /usr/bin/stress --verbose --cpu 2
     8     6 pts/0    R+    41:49 /usr/bin/stress --verbose --cpu 2
     9     7 pts/0    R+    41:48 /usr/bin/stress --verbose --cpu 2
    10 root@2200e14c5e1d:/# 

    而且进程的 PID 不同于 host 中对应进程的 PID,容器中 PID=1 的进程当然也不是 host 的 init 进程。也就是说:容器拥有自己独立的一套 PID,这就是 PID namespace 提供的功能。

    Network namespace

    Network namespace 让容器拥有自己独立的网卡、IP、路由等资源。我们会在后面网络章节详细讨论。

    User namespace

    User namespace 让容器能够管理自己的用户,host 不能看到容器中创建的用户。

     1 root@ubuntu:~# docker exec -it 2200e14c5e1d bash
     2 root@2200e14c5e1d:/# 
     3 root@2200e14c5e1d:/# useradd aaa    
     4 root@2200e14c5e1d:/# 
     5 root@2200e14c5e1d:/# id aaa
     6 uid=1000(aaa) gid=1000(aaa) groups=1000(aaa)
     7 root@2200e14c5e1d:/# exit
     8 exit
     9 root@ubuntu:~# 
    10 root@ubuntu:~# id aaa
    11 id: ‘aaa’: no such user
    12 root@ubuntu:~#

    在容器中创建了用户 aaa,但 host 中并不会创建相应的用户。

    小结

    本章内容

    1. 容器的各种操作
    2. 容器状态之间如何转换
    3. 限制容器使用 CPU、内存和 Block IO 的方法
    4. 实现容器的底层技术:cgroup 和 namespace

    下面是容器的常用操作命令:

    • create      创建容器  
    • run         运行容器  
    • pause       暂停容器  
    • unpause     取消暂停继续运行容器  
    • stop        发送 SIGTERM 停止容器  
    • kill        发送 SIGKILL 快速停止容器  
    • start       启动容器  
    • restart     重启容器  
    • attach      attach 到容器启动进程的终端  
    • exec        在容器中启动新进程,通常使用 "-it" 参数  
    • logs        显示容器启动进程的控制台输出,用 "-f" 持续打印  
    • rm          从磁盘中删除容器

    ----------------引用来自------------------

    https://mp.weixin.qq.com/s?__biz=MzIwMTM5MjUwMg==&mid=2653587673&idx=1&sn=476207c0186182ecdfa70256fbc9853a&chksm=8d3080c0ba4709d62f1b01d631c3456e2536d44207d1ed40947898f9efd2592cd79460a68e00&scene=21#wechat_redirect

  • 相关阅读:
    软工课设第一周周五报告
    软工课设第一周周四报告
    软工课设第一周周三报告
    软工课设第一周周二报告
    软工课设第一周周一报告
    团队项目记录4
    团队项目记录3
    团队项目记录2
    jQuery 打气球小游戏 点击气球爆炸效果
    计网第二章:物理层
  • 原文地址:https://www.cnblogs.com/gsophy/p/10335682.html
Copyright © 2020-2023  润新知