Docker 在启动时会创建一个虚拟网桥 docker0,默认地址为 172.17.0.1/16, 容器启动后都会被桥接到 docker0 上,并自动分配到一个 IP 地址。
ip addr ###可以看见
容器的四种网络模式:
bridge 桥接模式、host 模式、container 模式和 none 模式
启动容器时可以使用 --net 参数指定,默认是桥接模式。
Bridge 桥接模式的实现步骤主要如下:
(1) Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备
假设为veth0 和 veth1。
而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
(2) Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。
保证宿主机的网络报文可以发往 veth0;
(3) Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。
如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收
实现宿主机到Docker Container 网络的联通性;
同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。
bridge 桥接模式下的 Docker Container 在使用时,并非为开发者包办了一切。
最明显的是,该模式下 Docker Container 不具有一个公有 IP,
即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。
虽然 NAT 模式经过中间处理实现了这一点
但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器
内部服务的访问者需要使用服务发现获知服务的外部端口等。
另外 NAT 模式由于是在三层
网络上的实现手段,故肯定会影响网络的传输效率。
[root@foundation70 ~]# docker stop vm1 ###停掉一个容器
vm1
[root@foundation70 ~]# brctl show ##查看桥接为空
bridge name bridge id STP enabled interfaces
br0 8000.507b9d659cd9 no enp1s0
docker0 8000.02424b85c8cb no
virbr0 8000.5254003b8de4 yes virbr0-nic
docker run -it --name vm3 ubuntu
###创建一个容器
docker start vm1 ###再打开vm1容器
brctl show ###查看桥接会增加一个桥接
host 模式是 bridge 桥接模式很好的补充。
采用 host 模式的 Docker Container,可以直接使用
宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,
那么容器也拥有这个公有 IP。
同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。
当然,有这样的方便,肯定会损失部分其他的特性,
最明显的是 Docker Container 网络环境隔离性的弱化,
即容器不再拥有隔离、独立的网络栈。
另外,使用 host 模式的 Docker Container 虽
然可以让容器内部的服务和传统情况无差别、无改造的使用,
但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;
另外,容器内部将不再拥有所有的端口资源,
原因是部分端口资源已经被宿主机本身的服务占用,
还有部分端口已经用以 bridge 网络模式容器的端口映射。
docker run -it --name vm3 --net host ubuntu
###--net指定网络模式为host主机模式
(1) 查找 other container(即需要被共享网络环境的容器)的网络 namespace;
(2) 将新创建的 Docker Container(也是需要共享其他网络的容器)的 namespace,
使用other container 的 namespace。
Docker Container 的 other container 网络模式,
可以用来更好的服务于容器间的通信。
在这种模式下的 Docker Container
可以通过 localhost 来访问 namespace 下的其他容器,传输效率较高。
虽然多个容器共享网络环境,但是多个容器形成的整体依然与宿主机以及其他容器形成网络隔离。
另外,这种模式还节约了一定数量的网络资源。但是需要注意的是,
它并没有改善容器与宿主机以外世界通信的情况。
docker run -it --name vm4 --net container:vm1 ubuntu
###指定以容器模式运行
网络环境为 none,即不为 Docker Container 任何的网络环境。
一旦 Docker Container 采用了none 网络模式
那么容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。
可以说 none 模式为 Docker Container 做了极少的网络设定
但是俗话说得好“少即是多”在没有网络配置的情况下,作为 Docker 开发者
才能在这基础做其他无限多可能的网络定制开发。
这也恰巧体现了 Docker 设计理念的开放。
在 none 网络模式下分配固定 ip:netns 是在 linux 中提供网络虚拟化的一个项目
使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境
目前 netns 在 lxc 容器中被用来为容器提供网络。
使用 netns 创建的网络空间独立于当前系统的网络空间
其中的网络设备以及 iptables 规则
等都是独立的,就好像进入了另外一个网络一样。
[root@foundation70 ~]# docker run -it --name vm6 --net none ubuntu
###指定none网络模式创建并运行容器
root@048b0dea095b:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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
root@048b0dea095b:/# id
uid=0(root) gid=0(root) groups=0(root)
使用ctrl+p+q退出:
root@foundation70 ~]# docker inspect vm6 | grep Pid
"Pid": 14392,
"PidMode": "",
"PidsLimit": 0,
[root@foundation70 ~]# cd /proc/14392
[root@foundation70 14392]# ls
[root@foundation70 14392]# pwd
/proc/14392
[root@foundation70 14392]# cd ns/
[root@foundation70 ns]# ls
ipc mnt net pid user uts
[root@foundation70 ns]# ll
[root@foundation70 ns]# ip netns add test
[root@foundation70 ns]# ip netns list
test
[root@foundation70 ns]# cd /var/run/
[root@foundation70 run]# ls
[root@foundation70 run]# cd netns/
[root@foundation70 netns]# ls
test
[root@foundation70 netns]# ip netns del test
[root@foundation70 netns]# ls
[root@foundation70 netns]# pwd
/var/run/netns
[root@foundation70 netns]# ln -s /proc/14392/ns/net /var/run/netns/14392
[root@foundation70 netns]# ip netns list
14392
[root@foundation70 netns]# ip link add name veth0 type veth peer name veth1
###这里我们添加了一对veth设备,veth设备是成对出现的,
###两个设备之间的数据是相互贯通的,
###我们把veth1加入到test网络空间中:
[root@foundation70 netns]# ip addr
[root@foundation70 netns]# brctl addif docker0 veth0
[root@foundation70 netns]# brctl show
[root@foundation70 netns]# ip addr
##查看设备是DOWN状态
[root@foundation70 netns]# ip link set up veth0
激活设备veth0
[root@foundation70 netns]# ip link set up veth1
激活设备veth1
[root@foundation70 netns]# ip addr
[root@foundation70 netns]# ip link set veth1 netns 14392
### 添加到容器里面,在本地网络中已经无法查看到
[root@foundation70 netns]# ip netns exec 14392 ip link set veth1 name eth0
###设置容器名字为eth0的网卡
[root@foundation70 netns]# ip netns exec 14392 ip link set up dev eth0
[root@foundation70 netns]# docker container attach vm6
root@048b0dea095b:/#
root@048b0dea095b:/# ip addr
[root@foundation70 netns]# ip netns exec 14392 ip addr add 172.17.0.100/24 dev eth0
##添加一个虚拟IP
[root@foundation70 netns]# ip netns exec 14392 ip route add default via 172.17.0.1
###添加一个网关可以连接网络
[root@foundation70 netns]# route -n ###查看网关
[root@foundation70 netns]# docker container attach vm6
root@048b0dea095b:/# ping www.baidu.com