docker容器网络配置
Linux内核实现名称空间的创建
创建Network Namespace
可以通过ip netns命令完成对Network Namespace 的相关操作
//创建一个ns0的命名空间
[root@docker ~]# ip netns add ns0
[root@docker ~]# ip netns list
ns0
新创建的 Network Namespace 会出现在/var/run/netns/
目录下
[root@docker ~]# ls /var/run/netns/
ns0
对于每个 Network Namespace 来说,它会有自己独立的网卡、路由表、ARP 表、iptables 等和网络相关的资源。
操作Network Namespace
ip命令提供了ip netns exec
子命令可以在对应的 Network Namespace 中执行命令。
查看新创建 Network Namespace 的网卡信息
[root@docker ~]# ip netns exec ns0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
默认为关闭状态,所以ping不通
[root@docker ~]# ip netns exec ns0 ping 127.0.0.1
connect: 网络不可达
ip netns exec 空间名 ip link set lo up
[root@docker ~]# ip netns exec ns0 ip link set lo up
[root@docker ~]# ip netns exec ns0 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.025 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.024 ms
转移设备
我们可以在不同的 Network Namespace 之间转移设备(如veth)。由于一个设备只能属于一个 Network Namespace ,所以转移后在这个 Network Namespace 内就看不到这个设备了。
其中,veth设备属于可转移设备,而很多其它设备(如lo、vxlan、ppp、bridge等)是不可以转移的。
veth pair
veth pair 全称是 Virtual Ethernet Pair,是一个成对的端口,所有从这对端口一 端进入的数据包都将从另一端出来,反之也是一样。
引入veth pair是为了在不同的 Network Namespace 直接进行通信,利用它可以直接将两个 Network Namespace 连接起来。
创建veth pair
[root@docker ~]# ip link add type veth
实现Network Namespace间通信
在创建一个命名空间
[root@docker ~]# ip netns list
ns1
ns0
将veth加入到命名空间
[root@docker ~]# ip link set veth0 netns ns1
[root@docker ~]# ip link set veth1 netns ns0
开启他们,并添加IP
[root@docker ~]# ip netns exec ns0 ip link set veth1 up
[root@docker ~]# ip netns exec ns0 ip addr add 192.168.30.100/24 dev veth1
[root@docker ~]# ip netns exec ns1 ip link set veth0 up
[root@docker ~]# ip netns exec ns1 ip addr add 192.168.30.101/24 dev veth0
查看这对veth pair的状态
[root@docker ~]# ip netns exec ns0 ip addr
5: veth1@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 22:15:5f:0c:01:e6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 192.168.30.100/24 scope global veth1
valid_lft forever preferred_lft forever
inet6 fe80::2015:5fff:fe0c:1e6/64 scope link
valid_lft forever preferred_lft forever
[root@docker ~]# ip netns exec ns1 ip addr
4: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether b2:f3:12:14:3f:b8 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 192.168.30.101/24 scope global veth0
valid_lft forever preferred_lft forever
inet6 fe80::b0f3:12ff:fe14:3fb8/64 scope link
valid_lft forever preferred_lft forever
在ns0上可以ping通对端的IP
[root@docker ~]# ip netns exec ns0 ping 192.168.30.101
PING 192.168.30.101 (192.168.30.101) 56(84) bytes of data.
64 bytes from 192.168.30.101: icmp_seq=1 ttl=64 time=0.034 ms
64 bytes from 192.168.30.101: icmp_seq=2 ttl=64 time=0.029 ms
64 bytes from 192.168.30.101: icmp_seq=3 ttl=64 time=0.029 ms
veth设备重命名
//关闭ns0
root@docker ~]# ip netns exec ns0 ip link set veth1 down
//指定name
[root@docker ~]# ip netns exec ns0 ip link set dev veth1 name eth1
//开启
[root@docker ~]# ip netns exec ns0 ip link set eth0 up
容器的常用操作
查看容器的主机名
[root@docker ~]# docker run --name web1 -it --rm busybox
/ # hostname
d60e0a202070
在容器启动时注入主机名
[root@docker ~]# docker run --name web2 -it --hostname web1 busybox
/ # hostname
web1
手动指定容器要使用的DNS
[root@docker ~]# docker run --name web3 -it --dns 114.114.114.114 busybox
/ # cat /etc/resolv.conf
nameserver 114.114.114.114
/ # nslookup -type=a www.baidu.com
Server: 114.114.114.114
Address: 114.114.114.114:53
Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 39.156.66.14
Name: www.a.shifen.com
Address: 39.156.66.18
手动往/etc/hosts文件中注入主机名到IP地址的映射
[root@docker ~]# docker run --name web4 -it --add-host=www.b.com:2.2.2.2 --rm busybox
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
2.2.2.2 www.b.com
开放容器端口
格式 | 解释 | 例子 |
---|---|---|
-p containerPort | 将指定的容器端口映射到宿主机(不常用) | -p 80 nginx |
-p ip:hostPort:containerPort | 映射指定地址的指定端口到虚拟机的指定端口(不常用) | -p 192.168.30.244:80:80 |
-p ip::containerPort | 映射指定地址的任意端口到虚拟机的指定端口(不常用) | -p 192.168.30.244::80 |
-p hostPort:containerPort | 映射本机的指定端口到虚拟机的指定端口(常用) | -p 80:80 |
-p containerPort
[root@docker ~]# docker run -d -p 80 nginx
[root@docker ~]# ss -anlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
LISTEN 0 128 :::32768 :::*
可以使用 docker port
查看详细信息
[root@docker ~]# docker port ef0ac3abe450
80/tcp -> 0.0.0.0:32768
-p ip:hostPort:containerPort
[root@docker ~]# docker run -d -p 192.168.30.244:80:80 nginx
[root@docker ~]# ss -anlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 192.168.30.244:80 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
-p ip::containerPort
[root@docker ~]# docker run -d -p 192.168.30.244::80 --rm nginx
[root@docker ~]# ss -anlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 192.168.30.244:32768 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
-p hostPort:containerPort
[root@docker ~]# docker run -d -p 80:80 nginx
[root@docker ~]# ss -anlt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::80 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
自定义docker0桥的网络属性信息
自定义docker0桥的网络属性信息需要修改/etc/docker/daemon.json
配置文件
{
"bip": "192.168.1.5/24",
"fixed-cidr": "192.168.1.5/25",
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "10.20.1.1",
"default-gateway-v6": "2001:db8:abcd::89",
"dns": ["10.20.1.2","10.20.1.3"]
}
在使用时,只用加上bip(指定docker0桥自身的IP地址),其他可以通过计算得出
docker自定义创建网桥
docker network create -d bridge --subnet=192.168.31.0/24 --gateway=192.168.31.1 br0
使用新创建的自定义桥来创建容器:
[root@docker ~]# docker run -it --name test1 --network br0 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
19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:c0:a8:1f:02 brd ff:ff:ff:ff:ff:ff
inet 192.168.31.2/24 brd 192.168.31.255 scope global eth0
valid_lft forever preferred_lft forever
在同一宿主机不同网段实现通信
//在使用bridge启动一个容器
[root@docker ~]# docker run -it --name test2 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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
此时是ping不懂test1
/ # ping 192.168.31.2
PING 192.168.31.2 (192.168.31.2): 56 data bytes
用brctl show看一下网桥信息
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-f5c91d28d1af 8000.02425929a4bb no veth47d14d2
将test2加入到br0
[root@docker ~]# docker network connect br0 test2
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-f5c91d28d1af 8000.02425929a4bb no veth47d14d2
vethe20e470
docker0 8000.0242d4e84be8 no vethbc4b404
test2可以ping通test1
/ # ping 192.168.31.2
PING 192.168.31.2 (192.168.31.2): 56 data bytes
64 bytes from 192.168.31.2: seq=0 ttl=64 time=0.178 ms
64 bytes from 192.168.31.2: seq=1 ttl=64 time=0.045 ms
/ # cat /etc/hosts
172.17.0.2 1123620b351c
192.168.31.3 1123620b351c