docker_practice/underly/network.md

70 lines
4.5 KiB
Go
Raw Normal View History

# Docker 网络实现
2014-09-21 05:40:10 +00:00
Docker 的网络实现其实就是利用了 Linux 上的网络命名空间和虚拟网络设备特别是 veth pair建议先熟悉了解这两部分的基本概念再阅读本章
2014-09-21 05:40:10 +00:00
## 基本原理
2014-09-21 05:40:10 +00:00
首先要实现网络通信机器需要至少一个网络接口物理接口或虚拟接口来收发数据包此外如果不同子网之间要进行通信需要路由机制
Docker 中的网络接口默认都是虚拟的接口虚拟接口的优势之一是转发效率较高
2014-11-06 02:41:26 +00:00
Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中对于本地系统和容器内系统看来就像是一个正常的以太网卡只是它不需要真正同外部网络设备通信速度要快很多
2014-09-21 05:40:10 +00:00
Docker 容器网络就利用了这项技术它在本地主机和容器内分别创建一个虚拟接口并让它们彼此连通这样的一对接口叫做 `veth pair`
2014-09-21 05:40:10 +00:00
## 创建网络参数
Docker 创建一个容器的时候会执行如下操作
2014-11-06 02:58:28 +00:00
* 创建一对虚拟接口分别放到本地主机和新容器中
* 本地主机一端桥接到默认的 docker0 或指定网桥上并具有一个唯一的名字 veth65f9
* 容器一端放到新容器中并修改名字作为 eth0这个接口只在容器的命名空间可见
* 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0并配置默认路由到桥接网卡 veth65f9
2014-09-21 05:40:10 +00:00
完成这些之后容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络
2014-09-21 05:40:10 +00:00
可以在 `docker run` 的时候通过 `--net` 参数来指定容器的网络配置有4个可选值
2014-09-21 05:40:10 +00:00
* `--net=bridge` 这个是默认值连接到默认的网桥
* `--net=host` 告诉 Docker 不要将容器网络放到隔离的命名空间中即不要容器化容器内的网络此时容器使用本地主机的网络它拥有完全的本地主机接口访问权限容器进程可以跟主机其它 root 进程一样可以打开低范围的端口可以访问本地网络服务比如 D-bus还可以让容器做一些影响整个主机系统的事情比如重启主机因此使用这个选项的时候要非常小心如果进一步的使用 `--privileged=true`容器会被允许直接配置主机的网络堆栈
* `--net=container:NAME_or_ID` Docker 将新建容器的进程放到一个已存在容器的网络栈中新容器进程有自己的文件系统进程列表和资源限制但会和已存在的容器共享 IP 地址和端口等网络资源两者进程可以直接通过 `lo` 环回接口通信
* `--net=none` Docker 将新容器放到隔离的网络栈中但是不进行网络配置之后用户可以自己进行配置
2014-09-21 05:40:10 +00:00
## 网络配置细节
用户使用 `--net=none` 可以自行配置网络让容器达到跟平常一样具有访问网络的权限通过这个过程可以了解 Docker 配置网络的细节
2014-09-21 05:40:10 +00:00
首先启动一个 `/bin/bash` 容器指定 `--net=none` 参数
2017-11-13 10:54:38 +00:00
```bash
$ docker run -i -t --rm --net=none base /bin/bash
2014-09-21 05:40:10 +00:00
root@63f36fc01b5f:/#
```
在本地主机查找容器的进程 id并为它创建网络命名空间
2017-11-13 10:54:38 +00:00
```bash
$ docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
2014-09-21 05:40:10 +00:00
2778
$ pid=2778
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
```
检查桥接网卡的 IP 和子网掩码信息
2017-11-13 10:54:38 +00:00
```bash
2014-09-21 05:40:10 +00:00
$ ip addr show docker0
21: docker0: ...
inet 172.17.42.1/16 scope global docker0
...
```
创建一对 veth pair 接口 A B绑定 A 到网桥 `docker0`并启用它
2017-11-13 10:54:38 +00:00
```bash
2014-09-21 05:40:10 +00:00
$ sudo ip link add A type veth peer name B
$ sudo brctl addif docker0 A
$ sudo ip link set A up
```
将B放到容器的网络命名空间命名为 eth0启动它并配置一个可用 IP桥接网段和默认网关
2017-11-13 10:54:38 +00:00
```bash
2014-09-21 05:40:10 +00:00
$ sudo ip link set B netns $pid
$ sudo ip netns exec $pid ip link set dev B name eth0
$ sudo ip netns exec $pid ip link set eth0 up
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
```
以上就是 Docker 配置网络的具体过程
2014-09-21 05:40:10 +00:00
2014-11-06 02:41:26 +00:00
当容器结束后Docker 会清空容器容器内的 eth0 会随网络命名空间一起被清除A 接口也被自动从 `docker0` 卸载
2014-09-21 05:40:10 +00:00
此外用户可以使用 `ip netns exec` 命令来在指定网络命名空间中进行配置从而配置容器内的网络