首页 > 技术文章 > Docker网络通讯

wang-yy 2020-05-11 10:48 原文

Docker网络通讯

通讯流程

物理网卡与docker网桥通过NAT技术连接,虚拟网卡(对端出现)一端在docker0上,另一端在container,使其实现通讯。若有多个设备则,通过docker0转发而实现设备间的通讯。(docker0可以看做二层交换机制,container内拥有Namespace隔离机制)

Namespace - 网络(netns)

	netns 是在 linux 中提供网络虚拟化的一个项目,使用 netns 网络空间虚拟化可以在本地虚拟化出多个网络环境,目前 netns 在 lxc 容器中被用来为容器提供网络
	使用 netns 创建的网络空间独立于当前系统的网络空间,其中的网络设备以及 iptables 规则等都是独立的,就好像进入了另外一个网络一样 
# 创建虚拟网络空间
ip netns add r1

# 进入虚拟网络空间
ip netns exec r1 bash

# 添加一对 veth 设备
ip link add veth1.1 type veth peer name veth1.2

# 将其中一块网卡放入至 ns1 网络名称空间之中
ip link set veth1.1 netns r1

# 更改网络名称
ip link set veth1.1 name eth0

# 启动网卡
ip link set eth0 up

# 设置网卡名称
ip addr add 10.0.0.11/24 dev eth0

# 启动回环网卡
ip link set lo up

实验一:虚拟网络空间实现和内、外部通信

# 给虚拟的空间添加两个虚拟的网卡,一个网卡放于虚拟空间内,另一个放于外部虚拟网桥上,并赋予各自网络地址,实现通信。若有多个虚拟空间,则只需要将放于外部的网卡,放在同一网桥上,即可实现各个虚拟空间之间的通讯。容器与容器间的通信与此同理。
$ ip netns add r1 # 创建一个虚拟的网络空间
$ ip netns exec r1 bash # 进入虚拟网络空间
$ ip addr show # 展现网络接口(只拥有本地回环接口并处于关闭状态,ping不通任何网络)
$ ip link set lo up # 启动回环网卡
$ exit # 退出虚拟网络空间
$ ip link add veth1.1 type veth peer name veth1.2 # 添加虚拟对端网卡
$ ip addr show # 查看是否生成对端网卡
$ ip link set veth1.1 netns r1 # 将其中一个网卡放入虚拟网络空间中
$ ip addr show # 查看是否将网卡放入r1
$ ip netns exec r1 bash # 进入虚拟网络空间
$ ip addr show # 查看是否将网卡放入r1
$ ip link set veth1.1 name eth0 # 网卡改名(也可不改)
$ ip link set veth0 up # 启动虚拟空间内部网卡
$ ip addr show
$ ip addr add 192.168.67.100/24 dev eth0 # 虚拟空间内网卡添加网络信息(IP地址)
$ ifconfig # 查看网络信息
$ exit # 退出虚拟网络空间
$ ip link set veth1.2 up # 启动虚拟空间外的网卡
$ ip addr add 192.168.67.200/24 dev veth1.2# 虚拟空间内网卡添加网络信息(IP地址
$ ip addr show # 查看是否配置成功
$ ping 192.168.67.100 # 尝试能否实现虚拟网络空间内外通信

firewalld 规则

(1) 容器访问外部网络
$ iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -o docker0 -j MASQUERADE
(2) 外部网络访问容器
$ docker run -d -p 80:80 apache
$ iptables -t nat -A  PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
# DOCKER 在路由前捕获,判断是否是本地数据包,交给下一个命令处理
$ iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j  DNAT --to-destination 172.17.0.2:80

Docker网络通信方案

隔离:Namespace-network
通讯:
	容器间通讯(同主机)
			网桥
	容器与外部交流
		外部访问容器内部
			iptables-DNAT
		容器访问外部网络
			iptables-SNAT

Docker网络模式修改

Docker 进程修改

-b, --bridge=”” 指定 Docker 使用的网桥设备,默认情况下 Docker 会自动创建和使用 docker0 网桥设备,通过此参数可以使用已经存在的设备

--bip 指定 Docker0 的 IP 和掩码,使用标准的 CIDR 形式,如 10.10.10.10/24

--dns 配置容器的 DNS,在启动 Docker 进程是添加,所有容器全部生效

容器修改

--dns 用于指定启动的容器的 DNS
--net # 用于指定容器的网络通讯方式,有以下四个网络模式
	$ bridge:Docker # 默认方式,网桥模式
	$ none:# 容器没有网络栈
	$ container:使用其它容器的网络栈,Docker容器会加入其它容器的 network namespace		--network container:(ContainerName)	
	$ host:表示容器使用 Host 的网络,没有自己独立的网络栈。容器可以完全访问 Host 的网络,不安全	--network host

# 验证none容器没有网络栈:
	$ docker run --name test1 -d wyylinux/centos7.3:run
	$ docker run --name test2 --net=none -d wyylinux/centos7.3:run
	$ docker exec -it test1 /bin/bash
	$ ifconfig (若没有yum -y install net-tools) # 查看是否拥有对端网卡(172.)
	$ exit
	$ docker exec -it test1 /bin/bash
	$ ifconfig # 查看是否拥有对端网卡(172.)
	或
	$ docker inspect test1 # 查看是否拥有对端网卡(172.)
	$ docker inspect test2 # 查看是否拥有对端网卡(172.) 
	# 主要用于离线业务的使用
# 验证container使用其它容器的网络栈
	$ docker run --name test3 -d wyylinux/centos7.3:run
	$ docker run --name test4 --network container:test3 -d wyylinux/centos7.3:run
	$ dcoker exec -it test3 /bin/bash
	$ yum clean all
	$ yum -y install httpd
	$ /usr/bin/httpd # D-Bus(越权) 
	$ curl localhost # 查看是否可以访问
	$ hostname > /var/www/html/index.html
	$ curl localhost
	$ cd /root/
	$ touch why
	$ exit
	$ docker exec -it test4 /bin/bash
	$ curl localhost
	$ cd /root/
	$ ls
	# 可以看到在test3中修改的index.html文件,证明了,会共享与网络相关的,而其他的不会共享。

暴漏端口

-p / P 选项的使用格式
	> -p  <ContainerPort>:将制定的容器端口映射至主机所有地址的一个动态端口
	> -p  <HostPort>:<ContainerPort>:映射至指定的主机端口
	> -p  <IP>::<ContainerPort>:映射至指定的主机的 IP 的动态端口
	> -p  <IP>:<HostPort>:<ContainerPort>:映射至指定的主机 IP 的主机端口
	> -P(大):暴露所需要的所有端口
$ docker port ContainerName 可以查看容器当前的映射关系

自定义 Docker0 的网桥地址

修改 /etc/docker/daemon.json 文件
{
    "bip": "192.168.1.5/24", # 当前的docker0地址
    "fixed-cidr": "10.20.0.0/16", # 当前的docker0cidr(路由)
    "fixed-cidr-v6": "2001:db8::/64",
    "mtu": "1500",
    "default-gateway": "10.20.1.1", # 默认网关
    "default-gateway-v6": "2001:db8:abcd::89",
    "dns": ["10.20.1.2","10.20.1.3"]
}

常见的隔离方式

隔离:在空间内拥有独立的机制。
# wordpress搭建请参考https://www.cnblogs.com/wang-yy/p/14502718.html
$ docker-compose up -d # 启动wordpress
$ docker inspect ID(wordpress)
$ docker run --name test -d hub.c.163.com/public/centos:6.7-tools 
$ docker exec -it test /bin/bash
$ ping 172.19.03 # inspect 获取查看的ip,不通,是因为网卡放在了不同的广播域下。

基础命令说明

# 查看当前可用的网络类型
$ docker network ls 	
	NETWORK ID # ID号
   NAME   # 网络名称
   DRIVER  # 驱动类型
   SCOPE  # 作用域
# 网络空间名称
$ docker network create -d 类型 
	# 类型分为:
		# overlay network 全覆盖网络,可跨主机控制地址ping通
		# bridge network Docker默认方式,网桥模式

独立至不同的网络命名空间进行隔离

# 创建网桥
$ docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" my-bridge-network
# 给容器指定网桥
$ docker run -d --network=my-bridge-network --name test1  hub.c.163.com/public/centos:6.7-tools
# 给容器指定网桥	
$ docker run -d --name test2  hub.c.163.com/public/centos:6.7-tools

使用 Linux 桥接器进行主机间的通讯

# 删除 ens33 网络地址,(若有其他网卡先关闭)
$ ip addr del dev ens33 192.168.66.112/24

# 新建网桥 br0 ,并将 ens33 网卡桥接至 br0
$ ip link add link ens33 dev br0 type macvlan mode bridge

# 给网桥 br0 设置 ip 
$ ip addr add 192.168.66.112/24 dev br0

# 启用 br0
$ ip link set dev br0 up

# 给 br0 设置默认网关
$ ip route add default via 192.168.66.1 dev br0

# 为 Docker 容器指定 IP 地址
$ pipework br0 cmv3-manager 192.168.66.101/24@192.168.66.1

# 还原方案
$ ip link delete br0
$ service network restart
$ systemctl restart docker
# pipework下载地址
git clone https://github.com/jpetazzo/pipework

推荐阅读