Docker 实战

docker docker-compose

Posted by gomyck on May 31, 2022

从实战角度记录一下 docker 以及 docker compose 的一些应用技巧

镜像篇

需求: 搭建 kafka 集群

最终输出: shell 脚本, 完成一条指令搭建 kafka 集群

选型为公司原有 kafka 镜像仓库: debezium/kafka debezium/zookeeper

docker 的镜像可以在官方的 hub 上搜索: https://hub.docker.com/ 这个地址访问很慢, 需要梯子加速, 没梯子的可以联系我, 有偿提供按年付费(可看油管 1080 视频)

原理篇

docker 网络实现原理

bridge模式是 docker 默认的网络模式, 在容器启动时, docker 服务会为该容器申请一个独立的 network namespace(网卡, 回环loopback device, 路由表, ip table), 这些要素是构成网络协议栈的主要基础设施

每个容器都可以看做是一个独立的网络实体

在真实的物理机上,如果你想要实现两台主机之间的通信,最直接的办法,就是把它们用一根网线连接起来;而如果你想要实现多台主机之间的通信,那就需要用网线,把它们连接在一台交换机上。(二层或三层都可以呦)

在 linux 中, 能起到二层交换机作用的就是网桥 bridge, 他是工作在数据链路层的设备, 根据 mac 地址, 将流量转发到网桥不同的端口上, 为了实现这个目的, docker 会在宿主机上启动一个叫 docker0 的网桥, 凡是接入网桥的容器, 皆可以通过它来进行网络数据的传输

那容器是如何连接到 docker0 网桥的呢? : 使用 veth pair 设备, 可以把它理解成一个网线(因为容器 和 docker0 工作在两个不同的 network namespace)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
##### 在宿主机上
$ docker exec -it nginx /bin/bash

###### 在容器里
$ ifconfig

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::42:acff:fe11:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 364  bytes 8137175 (7.7 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 281  bytes 21161 (20.6 KiB)
        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 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

$ route

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

容器里的 eth0 网卡正是 veth pair 在容器这端的设备, 也就是在容器这一端的网线口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
##### 在宿主机上
$ ifconfig

docker0   Link encap:Ethernet  HWaddr 02:42:d8:e4:df:c1
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:d8ff:fee4:dfc1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:309 errors:0 dropped:0 overruns:0 frame:0
          TX packets:372 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:18944 (18.9 KB)  TX bytes:8137789 (8.1 MB)
veth9c02e56 Link encap:Ethernet  HWaddr 52:81:0b:24:3d:da
          inet6 addr: fe80::5081:bff:fe24:3dda/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:288 errors:0 dropped:0 overruns:0 frame:0
          TX packets:371 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:21608 (21.6 KB)  TX bytes:8137719 (8.1 MB)

$ brctl show

bridge name bridge id  STP enabled interfaces
docker0  8000.0242d8e4dfc1 no       veth9c02e56

可以看到 veth 这个网卡是 docker0 网桥的接口, 那么容器是如何与容器互相通信的呢?

通过 ARP 缓存知道IP 对应的 mac 地址, 如果目标地址是 目标主机, 则在交换机阶段就直接走二层转发, 否则目标 mac 是网关, 交换机会把封包转发给网关的 mac, 网关在从封包中拿到 IP 对路由表进行查询, 把对应的封包转发到对应的端口(网口), 在转发的过程中, 目标 mac 地址会变换成最终的 mac 地址, 或下一跳路由的 mac 地址