# Docker 网络

#### 博客作者：联系请[点击](https://hezhiqiang.gitbook.io/about-the-author/lian-xi-zuo-zhe)，搬运不易，希望请作者喝咖啡，可以点击[联系博客作者](https://hezhiqiang.gitbook.io/about-the-author/lian-xi-zuo-zhe)

Docker使用到的与Linux网络有关的技术分别有：namespace、Veth、Iptables、网桥、路由。

Docker 的网络实现其实就是利用了 Linux 上的网络命名空间（ namespace ）和虚拟网络设备（ veth pair ）。

## 基本原理

* **namespace：**&#x7F51;络命名空间(Network Namespace)，把Linux网络协议栈隔离到不同的命名空间中，完全隔离，彼此之间无法进行网络通信，通过这种对网络资源的隔离，就能在一个宿主机上虚拟多个不同的网络环境。
* **veth pair ：**&#x6210;对出现的一种虚拟网络设备，数据从一端进，从另一端出，用于解决网络命名空间之间隔离。
* **docker0 ：**&#x7F51;桥是一个二层网络设备，通过网桥可以将Linux支持的不同的端口连接起来，并实现类似交换机那样的多对多的通信。

Docker 中的网络接口默认都是虚拟的接口，虚拟接口的优势之一是转发效率较高。 Linux 通过在内核中进行数据复制来实现虚拟接口之间的数据转发，发送接口的发送缓存中的数据包被直接复制到接收接口的接收缓存中。对于本地系统和容器内系统看来就像是一个正常的以太网卡，只是它不需要真正同外部网络设备通信，速度要快很多。

Docker 容器网络就利用了这项技术，它在本地主机和容器内分别创建一个虚拟接口，并让它们彼此连通。

<figure><img src="https://139036132-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lx53lMutrsyPUks5pJf%2Fuploads%2F6v6r5ITkczoO3c5z75XJ%2Fimage.png?alt=media&#x26;token=6a80059e-4790-4457-af6f-22149d3845c0" alt=""><figcaption><p>Docker网络模型</p></figcaption></figure>

## Docker 使用iptables 实现网络通信原理

* DNAT：外部访问容器目标网络地址转换
* SNAT ：容器访问外部源的址转换

<figure><img src="https://139036132-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lx53lMutrsyPUks5pJf%2Fuploads%2FvCihldpj6cGFg092mZn6%2Fimage.png?alt=media&#x26;token=74d067c6-ff2e-4d91-afa0-f781d22daf6c" alt=""><figcaption></figcaption></figure>

## 网络参数

Docker 创建一个容器的时候，会执行如下操作：

* 创建一对虚拟接口，分别放到本地主机和新容器中；
* 本地主机一端桥接到默认的 docker0 或指定网桥上，并具有一个唯一的名字；
* 容器一端放到新容器中，并修改名字作为 eth0，这个接口只在容器的命名空间可见；
* 从网桥可用地址段中获取一个空闲地址分配给容器的 eth0，并配置默认路由到桥接网卡。

完成这些之后，容器就可以使用 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 将新容器放到隔离的网络栈中，但是不进行网络配置。之后，用户可以自己进行配置。

| 设备                | 作用总结                                                                                       |
| ----------------- | ------------------------------------------------------------------------------------------ |
| network namespace | 主要提供了关于网络资源的隔离，包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、/sys/class/net目录、端口（socket）等。     |
| linux Bridge      | 功能相当于物理交换机，为连在其上的设备（容器）转发数据帧。如docker0网桥                                                    |
| iptables          | 主要为容器提供NAT以及容器网络安全。                                                                        |
| veth pair         | 两个虚拟网卡组成的数据通道。在Docker中，用于连接Docker容器和Linux Bridge。一端在容器中作为eth0网卡，另一端在Linux Bridge中作为网桥的一个端口 |
