每天5分钟玩转容器技术-读书笔记-第四章到第五章

前言

因为开发过程中各种环境的部署是一件让人非常头疼的事情,所以容器技术一直是笔者比较感兴趣的技术领域,工作之余找到了一本国人写的容器好书 每天5分钟玩转Docker容器技术,书名看起来比较不靠谱,实际在豆瓣评分中高居前列,评论也纷纷表扬该书是本入门的好书。这系列文章是该书的读书笔记。笔者主要以 问题和解答 作为读书笔记的写作形式,这样可以方便大家准备面试。

系列文章:

每天5分钟玩转容器技术-读书笔记-第一章到第三章

容器

  1. 简单说说可以用哪些方式指定容器启动时执行的命令?

    有三种方式可以实现这个需求。

    • CMD指令
    • ENTRYPOINT指令
    • docker run命令行中指定
  2. 如果想要让容器长期运行应该如何处理?

    容器的生命周期依赖于启动时执行的命令,一旦命令执行完毕,容器就退出了,所以想要让容器长期运行,就需要执行一个长期运行的命令。

  3. 如果想要让容器不占用当前在终端,应该如何写命令?

    在docker run中加入 -d参数,可以使容器在后台运行,不占用当前终端

  4. 如果想进入容器进行相关操作,应该如何做?

    • attach命令
      • docker attach 容器标识符,可以在当前的终端直接进入容器启动命令的终端,进行调试
      • 启动时需要指定 -it ,结束时,可以使用ctrl+p ctrl+q退出attach
    • exec命令(这个命令在之前公司使用过)
      • docker exec -it 容器标识符 bash,可以进入容器中,并新开一个终端
      • 使用exit,可以退出exec模式,但不会退出容器
  5. 如果想要直接查看容器启动命令的相关输出,有哪几种方式?

    • attach命令
    • docker logs -f 容器标识符,类似tail -f
  6. 你知道docker stop和docker kill的底层实现原理吗?

    容器在host中是一个进程

    • stop命令的本质是向进程发送了一个SIGTERM信号;进程是可以捕获SIGTERM信号并进行处理的。
    • kill命令的本质是向进程发送了一个SIGKILL信号。进程不会捕获SIGKILL信号,一定会退出。
  7. 服务类容器,如果想要退出后自动重启(包括正常退出),如何设置指令参数?

    在启动指令中加入--restart=always参数即可。

  8. 如果想要清空已经停止的容器如何写命令?

    ging@ubuntu:~$ sudo docker rm $(sudo docker ps -aq -f status=exited)
    
  9. 简单说说实现容器的底层技术

    实现容器的底层技术有两个,一个是cgroup,一个是namespace。

    • cgroup:可以实现资源限额。Linux系统会为进程分配一个文件夹 /sys/fs/cgoup/cpu/docker/容器长id,里面保存了该容器的cpu限额,同理,内存和IO的限额也会有一个路径保存下来。
    • namespace:可以实现资源隔离。namespace其实是创建linux进程的一个可选参数,通过namespace,可以修改被创建的进程看待计算机的视图,让他只看得到应该看的部分。
  10. docker中的网络有哪几种?应用场景是什么?

    • none网络:--network=none,容器只有一个LoopBack回环,适用于不需要联网的容器

      ging@ubuntu:~$ sudo docker run -it --network=none busybox
      Unable to find image 'busybox:latest' locally
      latest: Pulling from library/busybox
      9758c28807f2: Pull complete 
      Digest: sha256:a9286defaba7b3a519d585ba0e37d0b2cbee74ebfe590960b0b1d6a5e97d1e1d
      Status: Downloaded newer image for busybox:latest
      / # ifconfig
      lo        Link encap:Local Loopback  
                inet addr:127.0.0.1  Mask:255.0.0.0
                UP LOOPBACK RUNNING  MTU:65536  Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
      
    • host网络:--network=host,容器共享宿主机的网络栈,容器的网络配置就是宿主机的网络配置,优点是,性能比较好;缺点是,会牺牲一些灵活性,需要考虑端口被宿主机占用的问题。

      ging@ubuntu:~$ sudo docker run -it --network=host busybox
      / # ipconfig
      sh: ipconfig: not found
      / # ifconfig
      docker0   Link encap:Ethernet  HWaddr 02:42:89:D4:13:E8  
                inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
                UP BROADCAST MULTICAST  MTU:1500  Metric:1
                RX packets:0 errors:0 dropped:0 overruns:0 frame:0
                TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:0 
                RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
      
      ens33     Link encap:Ethernet  HWaddr 00:0C:29:CD:8D:E3  
                inet addr:192.168.202.129  Bcast:192.168.202.255  Mask:255.255.255.0
                inet6 addr: fe80::c3ad:f4b8:95e4:3195/64 Scope:Link
                UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
                RX packets:49533 errors:0 dropped:0 overruns:0 frame:0
                TX packets:8504 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:72918170 (69.5 MiB)  TX bytes:616361 (601.9 KiB)
      
      lo        Link encap:Local Loopback  
                inet addr:127.0.0.1  Mask:255.0.0.0
                inet6 addr: ::1/128 Scope:Host
                UP LOOPBACK RUNNING  MTU:65536  Metric:1
                RX packets:385 errors:0 dropped:0 overruns:0 frame:0
                TX packets:385 errors:0 dropped:0 overruns:0 carrier:0
                collisions:0 txqueuelen:1000 
                RX bytes:36681 (35.8 KiB)  TX bytes:36681 (35.8 KiB)
      
      / # exit
      ging@ubuntu:~$ ifconfig
      docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
              inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
              ether 02:42:89:d4:13:e8  txqueuelen 0  (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
      
      ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
              inet 192.168.202.129  netmask 255.255.255.0  broadcast 192.168.202.255
              inet6 fe80::c3ad:f4b8:95e4:3195  prefixlen 64  scopeid 0x20<link>
              ether 00:0c:29:cd:8d:e3  txqueuelen 1000  (Ethernet)
              RX packets 51781  bytes 76269794 (76.2 MB)
              RX errors 0  dropped 0  overruns 0  frame 0
              TX packets 8799  bytes 634327 (634.3 KB)
              TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      
      lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
              inet 127.0.0.1  netmask 255.0.0.0
              inet6 ::1  prefixlen 128  scopeid 0x10<host>
              loop  txqueuelen 1000  (Local Loopback)
              RX packets 385  bytes 36681 (36.6 KB)
              RX errors 0  dropped 0  overruns 0  frame 0
              TX packets 385  bytes 36681 (36.6 KB)
              TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
      
    • bridge网络:--network=bridge,docker安装时,会创建一个虚拟网桥docker0,如果不指定network,容器都会被挂到docker0上。网桥简单理解就是linux虚拟出来的一个交换机,挂到同一个网桥的容器可以彼此互通网络。我们也可以创建自己的虚拟网桥,如果想让不同网桥之间的容器彼此互通。原理就是在容器中加了一个新的网卡,并且把这个网卡连接到需要通信的网桥上即可。

      查看网桥的子网掩码和网关信息可以用下面的指令:

      ging@ubuntu:~$ sudo docker network inspect bridge
      [
          {
              "Name": "bridge",
              "Id": "051b83b92aac7b1c918409f485c5fa365cc916fd3069bc3427fe7d7c373f3b9d",
              "Created": "2020-11-09T22:21:02.47777443-08:00",
              "Scope": "local",
              "Driver": "bridge",
              "EnableIPv6": false,
              "IPAM": {
                  "Driver": "default",
                  "Options": null,
                  "Config": [
                      {
                          "Subnet": "172.17.0.0/16",
                          "Gateway": "172.17.0.1"
                      }
                  ]
              },
              "Internal": false,
              "Attachable": false,
              "Ingress": false,
              "ConfigFrom": {
                  "Network": ""
              },
              "ConfigOnly": false,
              "Containers": {
                  "df7736b2a6b8ff7da50e3f940c41b61d1cbd3027c8eb0b13d8fbf558e7068256": {
                      "Name": "crazy_blackburn",
                      "EndpointID": "049c0d492adbf0ca0714446db8a55535007c675dccd912e939684d1f9288af7a",
                      "MacAddress": "02:42:ac:11:00:02",
                      "IPv4Address": "172.17.0.2/16",
                      "IPv6Address": ""
                  }
              },
              "Options": {
                  "com.docker.network.bridge.default_bridge": "true",
                  "com.docker.network.bridge.enable_icc": "true",
                  "com.docker.network.bridge.enable_ip_masquerade": "true",
                  "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                  "com.docker.network.bridge.name": "docker0",
                  "com.docker.network.driver.mtu": "1500"
              },
              "Labels": {}
          }
      ]
      
  11. 简单说下在容器中ping www.baidu.com为什么能ping通,说下关键原理

    这个过程分为两个阶段,第一阶段是ping包如何从容器发送到外网的,第二阶段是ping包如何从外网返回到容器的。

    第一阶段:

    • 容器如果不指定network,默认是连接到docker0这个桥上的,容器首先发出ping包,ping包的源地址是虚拟网桥分配的地址,目标地址是baidu.com
    • docker0收到ping包,发现是给外网的,于是交给NAT处理
    • NAT将地址修改为dockerhost的网卡地址
    • ping包从宿主机的对应网卡发送出去,这样就实现了容器访问外网

    第二阶段:

    • ping包从外网到达宿主机网卡,网卡根据不同的echo端口号区别是哪个容器ping的,转发给对应容器的ping应用。

    查看进程也可以发现,每个容器内部ping都对应了一个ping进程。

          ging@ubuntu:~$ ps -ef | grep "ping"
          ging        2292    1871  0 Nov09 ?        00:00:00 /usr/libexec/gsd-housekeeping
          root        8205    8198  0 00:03 pts/1    00:00:00 ping www.baidu.com
          root        8256    8250  0 00:03 pts/1    00:00:00 ping www.baidu.com
          ging        8264    2929  0 00:05 pts/0    00:00:00 grep --color=auto ping
    
  12. 外网如何访问容器?

    通过端口映射做到的。在启动容器时可以指定端口映射,把host的端口映射到容器的端口,docker会自动开启一个docker-proxy进程来监听这个端口的流量,一旦发现有流量,就转发到容器。

posted @ 2020-11-10 16:12  Ging  阅读(130)  评论(0编辑  收藏  举报