Write the underly/network chapter

pull/9/head
Baohua Yang 2014-09-21 13:40:10 +08:00
parent d544c2949f
commit 7b0e52f309
2 changed files with 72 additions and 2 deletions

View File

@ -15,15 +15,16 @@
* [CentOS](install/centos.md)
* [镜像](image/README.md)
* [列出](image/list.md)
* [使用Docker Hub管理镜像](image/dockerhub.md)
* [使用Docker Hub](image/dockerhub.md)
* [创建](image/create.md)
* [导出和导入](image/import_export.md)
* [存出和载入](image/save_load.md)
* [移除](image/rmi.md)
* [底层原理](image/internal.md)
* [容器](container/README.md)
* [启动](container/run.md)
* [守护态运行](container/daemon.md)
* [终止](container/stop.md)
* [导出和导入](container/import_export.md)
* [删除](container/rm.md)
* [仓库](repository/README.md)
* [Docker Hub](repository/dockerhub.md)

69
underly/network.md Normal file
View File

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