Docker容器的网络基础
- Docker提供的网桥
首先,查看一个名为docker0的“网络设备”:
[root@localhost ~]# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:2fff:fe56:7b2e prefixlen 64 scopeid 0x20<link>
ether 02:42:2f:56:7b:2e txqueuelen 0 (Ethernet)
RX packets 27406 bytes 2657911 (2.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 42036 bytes 58020300 (55.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
docker守护进程就是通过docker0为docker容器提供网络连接的各种服务。docker0实质事Linux的虚拟网桥;
-
Linux虚拟网桥的特点:
1- 可以设置IP地址
2- 相当于拥有一个隐藏的虚拟网卡 -
docker0的地址划分,例如:
IP:172.17.42.1 子网掩码: 255.255.0.0
MAC: 02:42:ac:11:00:00 到 02:42:ac:11:ff:ff
总共提供65534个地址
docker守护进程在一个容器启动时,实际上它要创建网络连接的两端。一端是在容器中的网络设备,而另一端是在运行docker守护进程的主机上打开一个名为veth*的一个接口,用来实现docker这个网桥与容器的网络通信。
查看网桥:
查看网桥,需要linux的网桥管理程序,在Ubuntu中通过 apt-get install bridge-utils 命令安装。如下查看网桥,可以看到一个叫docker0的网桥设备。
[root@localhost ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242ed943d02 no
可以对docker0进行修改,使之成为我们希望的网段。
- 语法:
ifconfig docker0 IP netmask NATMASK
- 实例:
[root@localhost docker]# ifconfig docker0 172.25.11.1 netmask 255.255.255.0
[root@localhost docker]# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.25.11.1 netmask 255.255.255.0 broadcast 172.25.11.255
inet6 fe80::42:2fff:fe56:7b2e prefixlen 64 scopeid 0x20<link>
ether 02:42:2f:56:7b:2e txqueuelen 0 (Ethernet)
RX packets 27406 bytes 2657911 (2.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 42047 bytes 58023011 (55.3 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@localhost docker]# service docker restart #最好重新启动下docker
Redirecting to /bin/systemctl restart docker.service
自定义虚拟网桥
有时候,不希望使用docker默认提供的虚拟网桥,就可以添加自定义的虚拟网桥,如下添加虚拟网桥:
- 语法:
#新建网桥
brctl addbr br_name(新建的网桥名)
#修改新建网桥的IP网段
ifconfig br_name IP netmask NETMASK_NAME
修改docker默认指定的网桥,需要修改/lib/systemd/system.docker.service文件,如下修改docker默认指定的网桥:
- 语法:
ExecStart=ExecStart=/usr/bin/dockerd -b=br_name //br_name 为宿主机的默认指定的网络桥接设备
#完成之后要重启docker服务
[root@localhost docker]# service docker restart
docker容器的网络设备查看 ( 如果没有ifconfig命令,通过apt-get install -y net-tools):
root@b2a3136f5425:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:145 errors:0 dropped:0 overruns:0 frame:0
TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:184985 (184.9 KB) TX bytes:4758 (4.7 KB)
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:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
启动容器后,docker已经自动创建了容器对应的eth0的网卡,注意观察ip地址和mac地址。不要退出容器,再运行如下查看网桥的状态,可以看到在interface中多了一个veth*的这样一个接口。通过ifconfig命令同样可以看到这个网络接口:
[root@localhost ~]# sudo brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242ed943d02 no veth95521e6
Docker容器的互联
用于测试的Docker镜像 Dockerfile:
FROM ubuntu:14.04
RUN apt-get install -y ping
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl
EXPOSE 80
CMD /bin/bash
- 允许所有容器互联
在同一宿主机下,docker的容器是通过“”虚拟网桥bridge“来进行连接的。那么在默认情况下,在同一宿主机中运行的容器都是可以互相连接的。
–icc=true 默认
[root@localhost docker]# docker run -it --name cct1 ubuntu:latest /bin/bash //构建容器cct1
root@db83f8dbedcc:/# nginx //启动cct1的nginx服务
root@db83f8dbedcc:/# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:24 errors:0 dropped:0 overruns:0 frame:0
TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1858 (1.8 KB) TX bytes:1862 (1.8 KB)
root@db83f8dbedcc:/# //使用ctrl+p ctrl+q 退出,启动守护式容器
[root@localhost docker]# docker run -it --name cct2 ubuntu:latest /bin/bash //构建容器cct2
root@2f8c3a090194:/# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)
root@2f8c3a090194:/# ping 172.17.0.2 //可以ping通cct1
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.102 ms
root@2f8c3a090194:/# curl 172.17.0.2 //可以访问cct1的nginx服务
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>
在同一个宿主机下都是通过虚拟网桥连接,但是容器的IP地址是不可靠的连接(容器的重启会导致容器IP的改变),在docker上提供的服务,以IP地址连接不可靠,所以在容器启动时可以添加–link选项:
–link:
docker run --link=[CONTAINER_NAME]:[ALIAS] [IMAGE] [COMMAND]
CONTAINER_NAME: 需要连接的容器名字;
ALIAS: 在容器中连接的代号,自己指定一个别名,用来连接指定;
#如下实例:
[root@localhost docker]# docker run -it --name cct3 --link=cct1:web_test ubuntu:latest /bin/bash //创建cct3,连接cct1,且别名为web_test
root@02bd05e6a6ab:/# ping web_test //可以直接ping通web_test
PING web_test (172.17.0.2) 56(84) bytes of data.
64 bytes from web_test (172.17.0.2): icmp_seq=1 ttl=64 time=0.110 ms
64 bytes from web_test (172.17.0.2): icmp_seq=2 ttl=64 time=0.105 ms
^C
--- web_test ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.105/0.107/0.110/0.010 ms
root@02bd05e6a6ab:/# env |grep WEB //可以看到有大量web_test的环境变量,在容器启动时,由docker添加
WEB_TEST_PORT_80_TCP_ADDR=172.17.0.2
WEB_TEST_PORT=tcp://172.17.0.2:80
WEB_TEST_PORT_80_TCP_PORT=80
WEB_TEST_NAME=/cct3/web_test
WEB_TEST_PORT_80_TCP=tcp://172.17.0.2:80
WEB_TEST_PORT_80_TCP_PROTO=tcp
root@02bd05e6a6ab:/# cat /etc/hosts //hosts文件里也有相关一些信息(web_test的地址映射)
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
172.17.0.2 web_test db83f8dbedcc cct1
172.17.0.4 02bd05e6a6ab
//重启cct3之后,也可以ping通cct1
-
查看在容器中产生的哪些影响,如:$ env
$ env 查看环境变量,可以看到大量以WEBTEST*开头的环境变量,这些环境变量是在容器启动时,由docker添加的。我们还可以查看在/ect/host文件,这里添加了webtest的地址映射。当docker重启启动容器时 /ect/host所对应的ip地址发生了变化。也就是说,针对于指定了link选项的容器,在启动时docker会自动修改ip地址和我们指定的别名之间的映射。环境变量也会做出相应的改变。
拒绝所有容器间互联
Docker守护进程的启动选项
–icc=false
修改vim /etc/default/docker,在末尾添加配置 DOCKER_OPTS="–icc=false"。
需要重启docker的服务 $ sudo service docker restart.
即使是link也ping不通。
允许特定容器间的连接
要允许特定容器连接,需要三个启动选项:
--icc=false
--iptables=true 允许docker容器将配置添加到Linux的iptables设置中
--link
#docker利用iptables中的机制,在icc=false时,阻断所有的docker容器间的访问,仅仅运行利用link选项配置的容器进行相互的访问。
示例:
- 关闭cct1、cct2、cct3
[root@localhost docker]# docker stop cct1 cct2 cct3
cct1
cct2
cct3
- 修改配置文件:/lib/systemd/system/docker.services
ExecStart=
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --iptables=true --icc=false
[root@localhost system]# systemctl daemon-reload //重启
[root@localhost system]# systemctl restart docker.service
- 重新启动cct1、cct2、cct3
[root@localhost docker]# docker start cct1 cct2 cct3
cct1
cct2
cct3
//attach到cct1、cct2、cct3,查看各自ip
- 测试:
[root@localhost docker_file]# docker attach cct2
root@c1ab09b07e87:/#
root@c1ab09b07e87:/# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 0 received, 100% packet loss, time 2999ms
//ping不通
root@c1ab09b07e87:/# curl 172.17.0.2
^C
//同样不能访问
[root@localhost rhel7mplayer]# docker attach cct3
root@0a3b40758348:/# curl web_test
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
</head>
<body>
<h1>Welcome to nginx!</h1>
</body>
</html>
//curl访问成功
- 查看宿主机上的iptables规则:
[root@localhost system]# iptables -L
Chain DOCKER (1 references)
target prot opt source destination
ACCEPT tcp -- 172.17.0.4 172.17.0.2 tcp dpt:http
ACCEPT tcp -- 172.17.0.2 172.17.0.4 tcp spt:http
ACCEPT tcp -- 172.17.0.5 172.17.0.2 tcp dpt:http
ACCEPT tcp -- 172.17.0.2 172.17.0.5 tcp spt:http
Chain DOCKER-ISOLATION (1 references)
target prot opt source destination
RETURN all -- anywhere anywhere
//可以看到,DOCKER表中放行了两个IP的http访问
- 注: 允许特定容器间的连接中如果出现容器间ping不通的情况,可能为iptables的问题(DROP规则在docker之前了)。
sudo iptables -L -n 查看iptables规则的情况
sudo iptables -F 清空iptables规则设置
sudo service docker restart 重新启用docker的服务
sudo iptables -L -n 再来查看iptables的设置,docker的规则链已经在第一位
# 然后重启容器即可
引用: