每天5分钟玩转容器技术-读书笔记-第四章到第五章
前言
因为开发过程中各种环境的部署是一件让人非常头疼的事情,所以容器技术一直是笔者比较感兴趣的技术领域,工作之余找到了一本国人写的容器好书 每天5分钟玩转Docker容器技术,书名看起来比较不靠谱,实际在豆瓣评分中高居前列,评论也纷纷表扬该书是本入门的好书。这系列文章是该书的读书笔记。笔者主要以 问题和解答 作为读书笔记的写作形式,这样可以方便大家准备面试。
系列文章:
容器
-
简单说说可以用哪些方式指定容器启动时执行的命令?
有三种方式可以实现这个需求。
- CMD指令
- ENTRYPOINT指令
- docker run命令行中指定
-
如果想要让容器长期运行应该如何处理?
容器的生命周期依赖于启动时执行的命令,一旦命令执行完毕,容器就退出了,所以想要让容器长期运行,就需要执行一个长期运行的命令。
-
如果想要让容器不占用当前在终端,应该如何写命令?
在docker run中加入 -d参数,可以使容器在后台运行,不占用当前终端
-
如果想进入容器进行相关操作,应该如何做?
- attach命令
- docker attach 容器标识符,可以在当前的终端直接进入容器启动命令的终端,进行调试
- 启动时需要指定 -it ,结束时,可以使用ctrl+p ctrl+q退出attach
- exec命令(这个命令在之前公司使用过)
- docker exec -it 容器标识符 bash,可以进入容器中,并新开一个终端
- 使用exit,可以退出exec模式,但不会退出容器
- attach命令
-
如果想要直接查看容器启动命令的相关输出,有哪几种方式?
- attach命令
- docker logs -f 容器标识符,类似tail -f
-
你知道docker stop和docker kill的底层实现原理吗?
容器在host中是一个进程
- stop命令的本质是向进程发送了一个SIGTERM信号;进程是可以捕获SIGTERM信号并进行处理的。
- kill命令的本质是向进程发送了一个SIGKILL信号。进程不会捕获SIGKILL信号,一定会退出。
-
服务类容器,如果想要退出后自动重启(包括正常退出),如何设置指令参数?
在启动指令中加入--restart=always参数即可。
-
如果想要清空已经停止的容器如何写命令?
ging@ubuntu:~$ sudo docker rm $(sudo docker ps -aq -f status=exited)
-
简单说说实现容器的底层技术
实现容器的底层技术有两个,一个是cgroup,一个是namespace。
- cgroup:可以实现资源限额。Linux系统会为进程分配一个文件夹 /sys/fs/cgoup/cpu/docker/容器长id,里面保存了该容器的cpu限额,同理,内存和IO的限额也会有一个路径保存下来。
- namespace:可以实现资源隔离。namespace其实是创建linux进程的一个可选参数,通过namespace,可以修改被创建的进程看待计算机的视图,让他只看得到应该看的部分。
-
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": {} } ]
-
-
简单说下在容器中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
-
外网如何访问容器?
通过端口映射做到的。在启动容器时可以指定端口映射,把host的端口映射到容器的端口,docker会自动开启一个docker-proxy进程来监听这个端口的流量,一旦发现有流量,就转发到容器。