1. 前言
Linux内核支持6种名称空间。
- UTS:主机名+域名
- USER:用户
- Mount:挂载文件系统
- IPC:进程间通信
- Pid:进程ID
- Net:网络
OVS:OpenVSwitch
SDN:软件驱动网络
Overlay Network:基于隧道叠加实现的另外一层网络通信。
C1要与C5通信,将报文发送给bridge上,由bridge发送给物理网卡,经由隧道转发。
四类网络模式
2. 容器虚拟化网络
1 | # docker默认有3种网络 |
- bridge:桥接网络,不是物理桥,默认是net桥。
自动在本机上创建一个 docker0 的软交换机,也可以当网卡使用。
启动每一个容器进程,都会自动分配一对虚拟网卡地址,一半在容器上,一半被关联到docker0上,如何关联?通过vethxxx 插在docker0上。
如何查看呢? 安装工具 yum -y install bridge-utils
1 | brctl show |
在容器中使用 ifconf 命令可查看另一半 eth0,即软网卡。
如何进入一个已经启动的容器内部呢?
1 | docker exec -it t2 /bin/sh |
busybox t2 启动,nginx web1 也启动,如何访问呢?
在同一个宿主机内的不同容器相互访问,通过bridge交换。
1 | docker exec -it t2 /bin/sh |
如果通过物理机访问 busybox呢?也是可以的,物理机把 bridge当网卡使用。
1 | curl 172.17.0.2 |
如果不在宿主机内的进程想要访问当前宿主机的busybox呢?
比如 node2 想访问 node1 上的 busybox、nginx容器呢?
容器启动默认是bridge模式,本宿主机上的其他容器都可以访问。只能在宿主机上添加dnet规则,让外部进程访问。
如果有多个web服务器呢?默认端口都是80,但物理机只有一个80端口只能分配给一个web容器,外部进程如何访问呢?
这种通过映射可能做起来非常麻烦,此时就想到了 Overlay Network。 C1 可以直接访问 C5的80端口,C5也可以直接访问C1的80端口,不需要在物理机上做映射。
每个容器内部拥有6个隔离独立的名称空间。 User/UTS/Mount/PID/NET/IPC
如果让不同容器只保存自己的 User、Mount、Pid,共享UTS/NET/IPC,共享另一个容器网络名称空间,对外提供统一的IP。看起来轻巧很多。
也可以共享宿主机的名称空间,a容器共享宿主机的网络名称空间,b容器通过桥接模式分配网络。
a容器改自己容器内的网络,宿主机也会跟着变。这就是 host模式,让容器使用宿主机的网络名称空间。
null模式:相当于只有lo,没有网卡,不能执行网络通信,信息孤岛,有些批处理任务容器不需要网络通信,处理完成直接打到卷里。
3. Docker4种网络架构
Closed Container: 只有 LO接口。
Bridged Container: 桥接式,有一个private interfave虚拟网卡(17.x.x.x),接到Docker bridge virtual interface。称为Net网络或是桥接式网络。
Joined Container:联盟式网络,User/Mount/Pid各自保管,Net/IPC/UTS 共享。
Open Container:开放式网络,直接共享宿主机的网络名称空间。
查看bridge网络的信息
1 | docker network ls |
inspect 可以查看docker的对象的详细信息
1 | docker network inspect bridge |
宿主机的 ip netns 可以模拟容器间通信
1 | ip netns help |
Docker 容器网络
None式网络
1 | docker run --name t1 -it --network none --rm busybox:latest |
桥接式
1 | # --rm 退出即删除 |
显示指定容器网络模式
1 | docker run --name t1 -it --network bridge --rm busybox:latest |
在容器启动时注入主机名
1 | # -h 注入 |
如果我们希望通过自定义dns来访问呢?
1 | # --dns 定义解析 |
1 | # --add-host:注入域名:IP 解析 |
总结
Opening inbound communication
操作,暴露80端口到宿主机随机端口上
1 | # -p 容器暴露出 80 端口,自动生成映射规则,删除容器自动删除规则 |
另起一个终端
1 | docker inspect myweb |
这只是同一个宿主机的不同容器可以相互通信。如果想要其他宿主机或其他宿主机的容器访问呢?
1 | # 查看80 与 宿主机端口的映射规则 |
以网页方式访问宿主机的 192.168.121.200:32768 会被转发到容器内的80端口上。(开放32768端口)
容器删除时,iptables 对应映射规则也会被删除
1 | docker kill myweb |
暴露在宿主机指定IP的随机端口
将容器内80端口映射到物理机上所有可用的端口
1 | # 指定宿主机固定IP的随机端口,:: 即宿主机使用什么端口,我也用该端口 |
暴露指定端口
1 | # 假设宿主机80端口没有被用到 |
暴露指定IP+指定端口
1 | docker run --name myweb --rm -p 192.168.121.200:8080:80 haoransun/httpd:v0.2 |
Nginx容器启动时默认暴露80端口,但外部依然无法访问,使用-P ,不用指定端口,使用默认端口,可以直接暴露
Joined Containers
效果相当于同一个主机上的两个进程一样
1 | # 创建 b1 b2 容器 |
1 | # 创建并启动b2容器时添加:--network container:b1 b2共享b1的网络命名空间 |
在b2上新起一个项目,在b1也能被访问到
1 | echo "hello world" > /tmp/index.html |
Host
共享宿主机的网络名称空间
1 | docker run --name b2 --network host -it --rm busybox |
如何更改Docker0默认的网络呢
以slave节点为例进行修改
1 | # 确保没有容器正在运行 |
docker默认守护进程的C/S,默认监听Unix Socket格式的地址,即本地通信,如果想在node2节点上,管理node1节点里的docker容器呢?
默认是不可以的。
1 | # 其中有 docker.sock文件 |
更改配置文件即可。
1 | systemctl stop docker |
在node1节点上,使用 docker ps 默认显示本机的,-H可以显示指定机器的容器、镜像。
1 |
|
自定义网络桥
1 | # 查看插件支持的 network |
1 | docker network --help |
1 | docker run --name t1 -it --net mybr0 busybox:latest |
两个桥上的机器能否通信呢?一个宿主机上创建了两个虚拟交换机,bridge和br0。
在宿主机上打开接口转发即可
1 | # 默认为1 就是打开的 |
设置两个网段可能就是为了不让通信的,没有必要让二者通信。