本笔记是记录一些学习微信公众号CloudMan的Docker的文章。本篇介绍容器的网络。

网络

Docker 安装时会自动在 host 上创建三个网络,可用 docker network ls 命令查看:

[root@finix-docker2 docker]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
6150b3bd13e6        bridge              bridge              local
834acba0d887        host                host                local
30e8599df623        none                null                local

none 网络

故名思议,none 网络就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。
容器创建时,可以通过 –network=none 指定使用 none 网络。

host 网络

连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样。
可以通过 –network=host 指定使用 host 网络。

在容器中可以看到 host 的所有网卡,并且连 hostname 也是 host 的。

直接使用 Docker host 的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择 host 网络。
不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host 上已经使用的端口就不能再用了。

bridge网络

Docker 安装时会创建一个命名为 docker0 的 linux bridge。如果不指定–network,创建的容器默认都会挂到 docker0 上。

容器创建时,docker 会自动从 172.17.0.0/16 中分配一个 IP,这里 16 位的掩码保证有足够多的 IP 可以供容器使用。

当前 docker0 上没有任何其他网络设备,创建一个容器看看有什么变化:
一个新的网络接口 veth28c57df 被挂到了 docker0 上,veth28c57df就是新创建容器的虚拟网卡。
用ifconfig看,容器有一个网卡 eth0@if34. 为什么不是veth28c57df 呢?
实际上 eth0@if34 和 veth28c57df 是一对 veth pair.
veth pair 是一种成对出现的特殊网络设备。 可以把它们想象成由一根虚拟网线连接起来的一对网卡,一张网卡(eth0@if34)在容器中,另一张网卡(veth28c57df)挂在网桥 docker0 上,其效果就是将 eth0@if34 也挂在了 docker0 上。

如何自定义容器的网络

Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan.
overlay 和 macvlan 用于创建跨主机的网络,后面有章节单独讨论。

可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:

[root@finix-docker2 ~]# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.0242c27c5710   no      vethf649665[root@finix-docker2 ~]# docker network create --driver bridge my_net
be9999cfd17c4fa7e9e5964fc0ab0927a54581ae1c7766ed6a2826b0e3b1f7fb[root@finix-docker2 ~]# brctl show
bridge name bridge id       STP enabled interfaces
br-be9999cfd17c     8000.024229c5bc26   no
docker0     8000.0242c27c5710   no      vethf649665

注:
如果docker host是cloud image的CentOS,那么可能没有安装brctl. 可以运行 yum install bridge-utils 来安装。

上面新增了一个网桥 br-be9999cfd17c,这里 be9999cfd17c 正好新建 bridge 网络 my_net 的短 id。
执行 docker network inspect 查看一下 my_net 的配置信息:

[root@finix-docker2 ~]# docker network inspect my_net
[{"Name": "my_net","Id": "be9999cfd17c4fa7e9e5964fc0ab0927a54581ae1c7766ed6a2826b0e3b1f7fb","Created": "2017-12-31T15:32:43.344450519Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.18.0.0/16","Gateway": "172.18.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]

这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段。

可以自己指定 IP 网段吗?
答案是:可以。只需在创建网段时指定 –subnet 和 –gateway 参数:

[root@finix-docker2 ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net_2
502c09fbf79f07e422e0950d3eca81deb9fd5ddf295a2e2281f3dba863591002
[root@finix-docker2 ~]# docker network inspect my_net_2
[{"Name": "my_net_2","Id": "502c09fbf79f07e422e0950d3eca81deb9fd5ddf295a2e2281f3dba863591002","Created": "2017-12-31T15:38:15.288155518Z","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.22.16.0/24","Gateway": "172.22.16.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]

这里我们创建了新的 bridge 网络 my_net_2,网段为 172.22.16.0/24,网关为 172.22.16.1。
与前面一样,网关在 my_net_2 对应的网桥 br-502c09fbf79f 上。运行brctl show可看到。

容器要使用新的网络,需要在启动时通过 –network 指定:

[root@finix-docker2 ~]# docker run -it --network my_net_2 busybox
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever
34: eth0@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ffinet 172.22.16.2/24 scope global eth0valid_lft forever preferred_lft forever

容器分配到的 IP 为 172.22.16.2。

到目前为止,容器的 IP 都是 docker 自动从 subnet 中分配,能否指定一个静态 IP 呢?
答案是:可以,通过–ip指定。

[root@finix-docker2 ~]# docker run -it --network=my_net_2 --ip=172.22.16.10 busybox
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft forever
36: eth0@if37: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:16:10:0a brd ff:ff:ff:ff:ff:ffinet 172.22.16.10/24 scope global eth0valid_lft forever preferred_lft forever
/ #

注:只有使用 –subnet 创建的网络才能指定静态 IP。

理解容器之间的连通性

前提:
两个 busybox 容器都挂在 my_net2 上,它们之间能够互通。而httpd挂在默认的bridge网络docker0上。

my_net2 与默认 bridge 网络 docker0 能通信吗?不能。

不同的网络如果加上路由应该就可以通信了吧?
确实,如果 host 上对每个网络的都有一条路由,同时操作系统上打开了 ip forwarding,host 就成了一个路由器,挂接在不同网桥上的网络就能够相互通信。
看看 ip forwarding:

# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1

ip forwarding已经启用了。但此时为何mynet2和docker0为何不能连通呢?再看看 iptables:

# iptables-save
......
-A DOCKER-ISOLATION -i br-5d863e9f78b6 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-5d863e9f78b6 -j DROP
......

原因找到了:iptables DROP 掉了网桥 docker0 与 br-5d863e9f78b6 之间双向的流量。
从规则的命名 DOCKER-ISOLATION 可知 docker 在设计上就是要隔离不同的 netwrok。

怎样才能让 busybox 与 httpd 通信呢?
答案是:为 httpd 容器添加一块 my_net2 的网卡。这个可以通过docker network connect 命令实现。

docker network connect my_net2 <short id of httpd container>

通过ip addr命令可以看出,httpd容器中新增了一块网卡,它连到了my_net2. 这样,httpd容器和2个busybox容器就可以互相连通了。

容器间通信的3种方式

方式一 加入同一个网络

两个容器要能通信,必须要有属于同一个网络的网卡。满足这个条件后,容器就可以通过 IP 交互了。
具体做法是在容器创建时通过 –network 指定相应的网络,或者通过 docker network connect 将现有容器加入到指定网络。
可参考上一节 httpd 和 busybox 的例子,这里不再赘述。

方式二 使用内嵌的DNS server

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信。
方法很简单,只要在启动时用 –name 为容器命名就可以了。

docker run -it --network=my_net2 --name=bbox1 busybox
docker run -it --network=my_net2 --name=bbox2 busybox

然后,bbox2 就可以直接 ping 到 bbox1 了。
使用 docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的。

方式三 joined容器

joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。

举例如下:
先创建一个 httpd 容器,名字为 web1。

docker run -d -it --name=web1 httpd

然后创建 busybox 容器并通过 –network=container:web1 指定 jointed 容器为 web1:

docker run -it --network=container:web1 busybox

busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈。busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。

joined 容器非常适合以下场景:
- 不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。
- 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

容器如何访问外部世界

如果docker host可以访问外网,那么容器默认也能访问外网。

原理如下:
busybox容器位于docker0这个bridge网络中,当busybox的ping包往外发的时候,首先由NAT功能将该包的源地址替换成docker host的地址再发送出去。
docker0 收到 busybox 的 ping 包,源地址为容器 IP 172.17.0.2,这没问题,交给 MASQUERADE 处理。这时,在 docker host 的网卡上我们看到了变化:
ping 包的源地址变成了主机网卡的 IP 10.0.2.15

External Network <– docker host NIC <– NAT <– docker0 <– busybox

外部世界如何访问容器

答案是:端口映射
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器。容器启动时通过-p参数映射端口。

容器启动后,可通过 docker ps 或者 docker port 查看到 host 映射的端口。
除了映射动态端口,也可在 -p 中指定映射到 host 某个特定端口,例如可将 container port 映射到 host port

docker run -d -p <host port>:<container port> httpd

每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量:

ps -elf | grep docker-proxy

Docker笔记(四)网络相关推荐

  1. Docker笔记四 发布自制DockerImage 到 Dockerhub

    Docker笔记 四 发布自制DockerImage 到 Dockerhub 1.注册Dockerhub账号 https://hub.docker.com/ 2.制作准备上传的dockerp_w_pi ...

  2. kali linux学习笔记(四) : 网络端口大全介绍

    端口大全介绍 2端口:管理实用程序 3端口:压缩进程 5端口:远程作业登录 7端口:回显 9端口:丢弃 11端口:在线用户 13端口:时间 17端口:每日引用 18端口:消息发送协议 19端口:字符发 ...

  3. Docker(十四):Docker:网络模式详解

    Docker作为目前最火的轻量级容器技术,牛逼的功能,如Docker的镜像管理,不足的地方网络方面. Docker自身的4种网络工作方式,和一些自定义网络模式 安装Docker时,它会自动创建三个网络 ...

  4. Docker学习四:Docker 网络

    前言 本次学习来自于datawhale组队学习: 教程地址为: https://github.com/datawhalechina/team-learning-program/tree/master/ ...

  5. Docker的四种网络模式

    docker run创建Docker容器时,可以用–net选项指定容器的网络模式,Docker有以下4种网络模式: bridge模式:使用–net =bridge指定,默认设置: host模式:使用– ...

  6. 5、Docker 的四种网络模式

    5.1 Docker 的四种网络模式 网络模式 网络配置 说明 host(开放式网络模式) –network host 容器和宿主机共享 Network namespace container(联合挂 ...

  7. docker学习笔记(三)docker中的网络

    目录 Linux中的网卡 Network Namespace Docker中的Bridge网络 使用自定义Bridge网络创建容器 Container中的其他网络 Host网络 None网络 Linu ...

  8. docker系列四之网络

    基础材料 CentOS7.6 minimal  关闭selinux 关闭swap分区 关闭NetworkManager 关闭firewalld Docker-ce 18.09.0 Docker支持的网 ...

  9. Docker教程(四) Docker镜像构建

    Docker教程(四) Docker镜像构建 本文链接:https://blog.csdn.net/yuan_xw/article/details/77744272 Docker教程(四) Docke ...

最新文章

  1. 那些按烂的Linux命令集合贴
  2. 基于模糊聚类的色彩迁移算法
  3. Hibernate实现对多个表进行关联查询
  4. 2020-12-17 Halcon初学者知识【4】区域和分割
  5. CodeForces - 1332B Composite Coloring(数论+构造)
  6. 理解音视频 PTS 和 DTS
  7. mysql标识列从一开始_mysql中标识列是什么意思有什么用
  8. mysql 事务回滚_简短截说阐述redis中事务的使用
  9. Java Web的分页工具类
  10. a - 数据结构实验之串一:kmp简单应用_数据结构(C语言版)_笔记_3
  11. 计算机专业小米笔记本推荐,小米笔记本电脑怎么样有哪些型号,哪款性价比高?...
  12. BZOJ 4565 字符合并 (区间 DP 状压 DP)
  13. 地方论坛门户网站运营之我见-上篇
  14. 浏览器开发者模式下你不可错过的Network面板知识
  15. 迷你图书管理器1.2 - 面向对象+集合
  16. 现代 React Web 开发实战——kanban实现卡片拖拽
  17. LeetCode刷题之575.分糖果
  18. java圆的面积_JAVA求圆的面积
  19. IP-Guard安全U盘使用说明书
  20. Leetcode 组合总和II

热门文章

  1. jQuery的基本使用方法
  2. SOA精华的内容和实用的知识
  3. PMP考试报名对培训有什么要求?
  4. html网页设计模板网站
  5. 数组的常用方法-(部分带有重构函数)
  6. 维基百科:数据库下载
  7. TCP头部分析与确认号的理解
  8. Yupoo(又拍网)的系统架构
  9. 3.六大原则例子-- 依赖倒置原则(DIP)例子
  10. 超简单修改富文本字体样式