趣谈网络协议---容器网络:来去自由的日子,不买公寓去合租

云计算解决了基础资源层的弹性伸缩,却没有解决 PaaS(平台即服务) 层应用随基础资源层弹性伸缩而带来的批量、快速部署问题。于是,容器应运而生。

容器如何将应用打包?

1、隔离技术,相当于制造集装箱。

  • namespace,负责看起来隔离,即每个 namespace 中的应用看到的是不同的 IP 地址、用户空间、进程号等。
  • cgroup,负责用起来隔离,一个应用只能用机器中的一部分 CPU、内存。

2、将集装箱标准化。

  • 镜像,将某一刻的状态保存在一系列文件,无论在哪里运行该镜像,都能完整还原当时的情况。

命名空间(namespace)

当一台 Linux 上跑多个进程时,如果觉得使用不同的路由策略,这些进程可能会冲突,需将这个进程放在一个独立的 namespace 中,方便独立配置网络。

网络的 namespace 由 ip netns 命令操作,可创建、删除、查询 namespace。

下图中,路由除了通过创建一个 Router 虚拟机实现外,还可通过 namespace 实现。
在这里插入图片描述

  • 创建一个 routerns,产生一个独立的网络空间,可设置自己的规则。
ip nets add routerns
  • 设置路由可转发。
ip netns exec routerns sysctl -w net.ipv4.ip_forward=1
  • 初始化 iptables,以配置 NAT 规则。
ip netns exec routerns iptables-save -c 
ip netns exec routerns iptables-restore -c
  • 作为路由器,需要一张网卡连接 到br0。创建网卡:
ovs-vsctl -- add-port br0 taprouter -- set Interface taprouter type=internal -- set Interface taprouter external-ids:iface-status=active -- set Interface taprouter external-ids:attached-mac=fa:16:3e:84:6e:cc
  • 网络创建完成,进入到 namespace。
ip link set taprouter netns routerns
  • 给网卡配置 IP,为虚拟机网络的网关地址。
ip netns exec routerns ip -4 addr add 192.168.1.1/24 brd 192.168.1.255 scope global dev taprouter
  • 为访问外网,需另一个网卡连接在外网网桥 br-ex 上,并塞在 namespace 中。
ovs-vsctl -- add-port br-ex taprouterex -- set Interface taprouterex type=internal -- set Interface taprouterex external-ids:iface-status=active -- set Interface taprouterex external-ids:attached-mac=fa:16:3e:68:12:c0

ip link set taprouterex netns routerns
  • 为该网卡分配一个与物理外网网络在一个网段的 IP。
ip netns exec routerns ip -4 addr add 16.158.1.100/24 brd 16.158.1.255 scope global dev taprouterex
  • 配置路由表。默认路由是去物理外网的;去虚拟机私网,走下面的网卡;去物理外网,走上面的网卡。
ip netns exec routerns route -n
Kernel IP routing table
Destination   Gateway     Genmask     Flags Metric Ref  Use Iface
0.0.0.0     16.158.1.1  0.0.0.0     UG  0   0    0 taprouterex
192.168.1.0    0.0.0.0     255.255.255.0  U   0   0    0 taprouter
16.158.1.0  0.0.0.0     255.255.255.0  U   0   0    0 taprouterex
  • 配置 NAT 规则。虚拟机为外界提供服务,客户端访问进来时,在外网网口 NAT 成虚拟机私网 IP。
ip netns exec routerns iptables -t nat -nvL
Chain PREROUTING
target  prot opt  in  out  source  destination
DNAT  all  --  *  *  0.0.0.0/0 16.158.1.103 to:192.168.1.3
Chain POSTROUTING
target  prot opt  in  out  source   destination
SNAT  all  --  *  *  192.168.1.3  0.0.0.0/0 to:16.158.1.103

至此,基于网络 namespace 的路由器实现完毕。

机制网络(cgroup)

全称 control groups,Linux 内核提供的一种可以限制、隔离进程使用的资源机制。

cgroup 子系统:

  • CPU 子系统,使用调度呈现为进程控制 CPU 的访问;
  • cpuset,如果时多核心的 CPU,为进程分配单独的 CPU 和内存;
  • memory 子系统,设置进程的内存限制及产生内存资源报告;
  • blkio 子系统,设置限制每个块设备的输入输出控制;
  • net_cls,使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序 tc 识别从具体 cgroup 中生成的数据包。

cgroup 提供了一个虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。cgroup 文件系统一般挂载在 /sys/fs/cgroup 目录下。

挂载 net_cls 的文件系统:

mkdir /sys/fs/cgroup/net_cls
mount -t cgroup -onet_cls net_cls /sys/fs/cgroup/net_cls

配置 TC,可按照 cgroup 设定规则:
在这里插入图片描述

  • 从 1.2.3.4 来,发送给 port 80 的包,从第一个分支 1:10 走;其他从 1.2.3.4 发送来的包从第二个分支 1:11 走;其他走默认分支。
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 1: cgroup

假设有两个用户 a、b,要进行带宽限制。

  • 创新两个 net_cls。
mkdir /sys/fs/cgroup/net_cls/a   
mkdir /sys/fs/cgroup/net_cls/b
  • 制定流表规则。net/cls/a/net_cls.classid 中放 flowid 1:10;net/cls/b/net_cls.classid 中放 flowid 1:11。0x00010010 = 0x0001 0010,0x00010011 = 0x0001 0011。
echo 0x00010010 > /sys/fs/cgroup/net_cls/a/net_cls.classid    
echo 0x00010011 > /sys/fs/cgroup/net_cls/b/net_cls.classid

容器中的网络如何融入物理网络?
在这里插入图片描述

一、容器外的网卡连 docker0 网桥,实现一台物理机上的容器间互相访问。

虚拟机中,有虚拟化软件,可通过 TUN/TAP 设备虚拟一张网卡,但容器中无虚拟化软件,可创建一对 veth pair 的网卡,从一边发包,另一边收包。

1、创建 veth pair 网卡。

ip link add name veth1 mtu 1500 type veth peer name veth2 mtu 1500

2、一边打到 docker0 网桥。

ip link set veth1 master testbr    
ip link set veth1 up

3、另一边放入容器。

  • 获取 namespace 的名字。一个容器的启动对应一个 namespace,对于 docker,pid 是 namespace 的名字,假设结果是 12065。
docker inspect '--format={{ .State.Pid }}' test
  • 默认 docker 创建的网络 namespace 不在默认路径下,ip netns 看不到,需 ln 软连接。
rm -f /var/run/netns/12065    
ln -s /proc/12065/ns/net /var/run/netns/12065
  • 将另一端 veth2 塞到 namespace 中。
ip link set veth2 netns 12065
  • 将容器内的网卡重命名。
ip netns exec 12065 ip link set veth2 name eth0
  • 给容器内网卡设置 IP。
ip netns exec 12065 ip addr add 172.17.0.2/24 dev eth0    
ip netns exec 12065 ip link set eth0 up

二、容器如何访问外网?

宿主机上,有一条 iptables 规则:

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

容器内发出的包,源 IP 转换为物理网卡的 IP。多个容器共享一个外网 IP,在 conntrack 表中,会记录出去的连接。

如果容器内是一个服务,需通过 Docker 的端口映射技术,将内部端口映射到物理机。

如 docker run 命令中的参数 -p 10080:80,将物理机的 10080 端口与容器的 80 端口映射起来。

docker 有两种转换端口的方式:

  • 通过一个进程 docker-proxy,监听 10080,转换为 80 端口。
/usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 10080 -container-ip 172.17.0.2 -container-port 80
  • 通过 DNAT 方式,在 -A PREROUTING 阶段增加一个规则,将端口 10080 的 IP DNAT 成容器的私网。
-A DOCKER -p tcp -m tcp --dport 10080 -j DNAT --to-destination 172.17.0.2:80

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值