docker-网络基础
Posted mrwuzs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了docker-网络基础相关的知识,希望对你有一定的参考价值。
网络
Docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多个 host 的网络
Docker 安装时会自动在 host 上创建三个网络,
? [email protected] /home docker network ls
NETWORK ID NAME DRIVER SCOPE
4232d0b89e85 bridge bridge local
90b3cebedfb6 host host local
c1a576af27d2 none null local
? [email protected] /home
none 网络
挂在这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,可以通过?--network=none
?指定使用 none 网络。
? [email protected] /home docker run -it --network=none busybox
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ...
latest: Pulling from docker.io/library/busybox
8c5a7da1afbc: Pull complete
Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115fdff9bd
Status: Downloaded newer image for docker.io/busybox:latest
/ # ifconfig
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:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ #
一些对安全性要求高并且不需要联网的应用可以使用 none 网络。
host 网络
连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。可以通过?--network=host
?指定使用 host 网络
? ? [email protected] /home docker run -it --network=host busybox
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
link/ether 00:0c:29:0f:09:89 brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
link/ether 02:42:66:21:3f:9d brd ff:ff:ff:ff:ff:ff
21: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
link/ether c2:02:4f:c0:9e:5d brd ff:ff:ff:ff:ff:ff
27: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0
link/ether f2:56:d6:65:38:18 brd ff:ff:ff:ff:ff:ff
在容器中可以看到 host 的所有网卡,并且连 hostname 也是 host 的
直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。
bridge 网络
Docker 安装时会创建一个 命名为?docker0
?的 linux bridge。如果不指定--network
,创建的容器默认都会挂到?docker0
?上
? [email protected] /home brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024266213f9d no veth3e15456
vethed6909e
其中veth3e15456 vethed6909e
就是创建容器的虚拟网卡。
容器里的配置
? [email protected] /home docker exec -it 6b9f16f7de01 bash
[email protected]:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
28: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defau
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:4/64 scope link
valid_lft forever preferred_lft forever
[email protected]:/usr/local/apache2#
? vethed6909e和[email protected]是一对veth pair。veth pair 是一种成对出现的特殊网络设备, 想象成由一根虚拟网线连接起来的一对网卡,网卡的一头([email protected]
)在容器中,另一头(veth28c57df
)挂在网桥?docker0
?上,其效果就是将?[email protected]
?也挂在了?docker0
?上
[email protected]
?已经配置了 IP?172.17.0.4
,
通过?docker network inspect bridge
?看一下 bridge 网络的配置信息:
?bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。
容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以供容器使用
user-defined 网络
1.创建
? ? [email protected] ~ docker network create --driver bridge my_net
57fd498eab6a3202f2bac97ad91f6770dae73b9c3690b5a1a72c100ef5f9a060
创建一个user-defind 网络
新增了一个网桥?br-57fd498eab6a,这里?57fd498eab6a?正好新建 bridge 网络?my_net
?的短 id。
? [email protected] ~ brctl show
bridge name bridge id STP enabled interfaces
br-57fd498eab6a 8000.0242b1c813c6 no
docker0 8000.024266213f9d no veth3e15456
vethb35268d
vethed6909e
执行?docker network inspect
?查看一下?my_net
?的配置信息:
? [email protected] ~ docker network inspect my_net
[
{
"Name": "my_net",
"Id": "57fd498eab6a3202f2bac97ad91f6770dae73b9c3690b5a1a72c100ef5f9a060",
"Created": "2018-08-05T11:47:52.338929045-04:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
另外指定 子网和网关创建,如下
docker network create --driver bridge --subnet 192.168.0.0/24 --gateway 192.168.0.10 my_net2
2.使用
容器要使用新的网络,需要在启动时通过?--network
?指定
? [email protected] ~ docker run -it --network=my_net2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
32: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.1/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:c0ff:fea8:1/64 scope link
valid_lft forever preferred_lft forever
指定子网创建
docker run -it --network=my_net2 --ip 192.168.0.100 busybox
只有使用?--subnet?创建的网络才能指定静态 IP。
容器之间的连通性
1.查看路由
? [email protected] ~ ip r
default via 192.168.246.2 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-57fd498eab6a proto kernel scope link src 172.18.0.1
192.168.0.0/24 dev br-7119530cd62a proto kernel scope link src 192.168.0.10
192.168.246.0/24 dev ens33 proto kernel scope link src 192.168.246.138
2.查看防火墙
? [email protected] ~ iptables-save
# Generated by iptables-save v1.4.21 on Sun Aug 5 12:22:14 2018
*nat
:PREROUTING ACCEPT [7:1070]
:INPUT ACCEPT [7:1070]
:OUTPUT ACCEPT [94:7140]
:POSTROUTING ACCEPT [94:7140]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 192.168.0.0/24 ! -o br-7119530cd62a -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-57fd498eab6a -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i br-7119530cd62a -j RETURN
-A DOCKER -i br-57fd498eab6a -j RETURN
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed on Sun Aug 5 12:22:14 2018
# Generated by iptables-save v1.4.21 on Sun Aug 5 12:22:14 2018
*filter
:INPUT ACCEPT [1124:81571]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [746:87877]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o br-7119530cd62a -j DOCKER
-A FORWARD -o br-7119530cd62a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i br-7119530cd62a ! -o br-7119530cd62a -j ACCEPT
-A FORWARD -i br-7119530cd62a -o br-7119530cd62a -j ACCEPT
-A FORWARD -o br-57fd498eab6a -j DOCKER
-A FORWARD -o br-57fd498eab6a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i br-57fd498eab6a ! -o br-57fd498eab6a -j ACCEPT
-A FORWARD -i br-57fd498eab6a -o br-57fd498eab6a -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION -i br-57fd498eab6a -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i br-57fd498eab6a -o docker0 -j DROP
-A DOCKER-ISOLATION -j RETURN
COMMIT
# Completed on Sun Aug 5 12:22:14 2018
可以看到
-A DOCKER-ISOLATION -i docker0 -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i br-57fd498eab6a -o docker0 -j DROP
实现网络的隔离
3.docker连接网络
docker network connect my_net2 6b9f16f7de01
? ? [email protected] ~ docker exec -it amazing_lovelace bash
[email protected]:/usr/local/apache2# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
28: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:4/64 scope link
valid_lft forever preferred_lft forever
40: [email protected]: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.1/24 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::42:c0ff:fea8:1/64 scope link
valid_lft forever preferred_lft forever
容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。
1.IP通信
如上一节
2.Docker DNS Server通信
启动时用?--name
?为容器命名
只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的
示例:
docker run -it --network=my_net2 --name=bbox1 busybox
docker run -it --network=my_net2 --name=bbox2 busybox
/ # ping bbox1
PING bbox1 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: seq=0 ttl=64 time=0.062 ms
64 bytes from 192.168.0.2: seq=1 ttl=64 time=0.068 ms
3.joined 通信
可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。
1,创建一个http的容器
docker run -it --name web1 httpd
2.创建一个容器使用web1 的网络
docker run -it --network=container:web1 busybox
然后发现 web1的网络和busybox的网络完全一致
busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务
容器访问外部
1.查看主机路由
? ? [email protected] ~ ip r
default via 192.168.246.2 dev ens33 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-57fd498eab6a proto kernel scope link src 172.18.0.1
192.168.0.0/24 dev br-7119530cd62a proto kernel scope link src 192.168.0.10
192.168.246.0/24 dev ens33 proto kernel scope link src 192.168.246.138
2.查看nat表
? ? [email protected] ~ iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 192.168.0.0/24 ! -o br-7119530cd62a -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-57fd498eab6a -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i br-7119530cd62a -j RETURN
-A DOCKER -i br-57fd498eab6a -j RETURN
-A DOCKER -i docker0 -j RETURN
? [email protected] ~
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
来自 172.17.0.0/16 网段的包,目标地址是外网(! -o docker0),就把它交给 MASQUERADE 处理。而 MASQUERADE 的处理方式是将包的源地址替换成 host 的地址发送出去,即做了一次网络地址转换(NAT)
3.抓包分析
抓docker
? [email protected] ? ~ ? tcpdump -i docker0 -n icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:21:28.362520 IP 172.17.0.2 > 13.107.21.200: ICMP echo request, id 1792, seq 133, length 64
03:21:28.400419 IP 13.107.21.200 > 172.17.0.2: ICMP echo reply, id 1792, seq 133, length 64
03:21:29.363317 IP 172.17.0.2 > 13.107.21.200: ICMP echo request, id 1792, seq 134, length 64
03:21:29.402380 IP 13.107.21.200 > 172.17.0.2: ICMP echo reply, id 1792, seq 134, length 64
docker0 收到 busybox 的 ping 包,源地址为容器 IP 172.17.0.2
抓ens33
? [email protected] ~ tcpdump -i ens33 -n icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
03:22:30.405175 IP 192.168.246.138 > 13.107.21.200: ICMP echo request, id 1792, seq 195, length 64
03:22:30.442453 IP 13.107.21.200 > 192.168.246.138: ICMP echo reply, id 1792, seq 195, length 64
03:22:31.405493 IP 192.168.246.138 > 13.107.21.200: ICMP echo request, id 1792, seq 196, length 64
ping 包的源地址变成了 ens33 的 IP 192.168.246.138
busybox 发送 ping 包:172.17.0.2 > www.bing.com。
docker0 收到包,发现是发送到外网的,交给 NAT 处理。
NAT 将源地址换成 enp0s3 的 IP:192.168.246.138 > www.bing.com。
ping 包从 ens33 发送出去,到达 www.bing.com。
外部访问内部
使用端口映射的方式
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时通过-p
参数映射端口:
? [email protected] ~ docker run -d -p 80 httpd
f16876575a9bd742eaeab3b809685d257c51593a491f8b746490a3e2b22d664f
? [email protected] ~ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f16876575a9b httpd "httpd-foreground" 2 minutes ago Up 2 minutes 0.0.0.0:32768->80/tcp nostalgic_mccarthy
? [email protected] ~ curl 0.0.0.0:32768
<html><body><h1>It works!</h1></body></html>
指定绑定端口
? [email protected] ~ docker run -d -p 8080:80 httpd
026c43829faa0a5a9956dd76e029ad39943c9c74739026558634e9b3d9ad9e0d
? [email protected] ~ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
026c43829faa httpd "httpd-foreground" 3 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp tender_hawking
f16876575a9b httpd "httpd-foreground" 8 minutes ago Up 8 minutes 0.0.0.0:32768->80/tcp nostalgic_mccarthy
每一个映射的端口,host 都会启动一个?docker-proxy
?进程来处理访问容器的流量
? [email protected] ~ ps -ef | grep docker-proxy
root 1584 1 0 03:17 ? 00:00:02 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --signature-verification=false --storage-driver overlay2
root 2126 1584 0 03:26 ? 00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 32768 -container-ip 172.17.0.2 -container-port 80
root 2362 1584 0 03:35 ? 00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.3 -container-port 80
root 2525 1407 0 03:36 pts/0 00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn docker-proxy
以上是关于docker-网络基础的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装