如何做公司企业网站,石景山手机网站建设,wordpress用户中心代码,网站建设类公司排名一、docker是什么
Docker本质是一个进程,宿主机通过namespace隔离机制提供进程需要运行基础环境#xff0c;并且通过Cgroup限制进程调用资源。Docker的隔离机制包括 network隔离#xff0c;此次主要探讨网络隔离mount隔离hostname隔离user隔离pid隔离进程通信隔离
二、doc…一、docker是什么
Docker本质是一个进程,宿主机通过namespace隔离机制提供进程需要运行基础环境并且通过Cgroup限制进程调用资源。Docker的隔离机制包括 network隔离此次主要探讨网络隔离mount隔离hostname隔离user隔离pid隔离进程通信隔离
二、docker 网络模式
host: 主机模式 不会创建网络隔离机制直接宿主机的网络。 bridge 默认桥接, 新建虚拟桥接网卡用于 docker 容器之间的通信。 桥接网卡通过iptables对分组进行转发到主网卡通常使用主机外网IP与外部网络通信。桥接网卡会关联多张 interface 网络接口。 实现内网通信。interface 主要是通过 veth pair 虚拟设备对一端用于容器一端用于绑定网桥。 macvlan : 为容器穿件一张虚拟网卡,该网卡用于独立的MAC地址和相同的网卡操作逻辑。 相比bridge 和 hosts 模式。 即满足了网络隔离需求也满足了和宿主机网络相同地位。 ipvlan 需要要求内核版本 4.2, 暂不复现。 可以通过 ip link vlan 相关命令了解用法overlay: 未复现主要用于swarm 集群none: 容器不具备网络通信能力更多作为类似于脚本任务。
三、docker 网络通信
docker主要通过iptables规则进行报文转和过滤。 目标: 尝试理解docker创建的iptables行为。
1. 清空iptables规则, 重启docker并启动nginx容器
# 清空iptables规则重启docker后,docker-proxy会自动更新iptables策略
[rootmking /]# iptables -F iptables -t nat -F systemctl restart docker# 启动docker容器并暴露网卡
[rootmking /]# docker network create demo# 查看网卡信息demo创建桥接的网卡名为: br-a397efbb3fb4
[rootmking /]# docker network ls
NETWORK ID NAME DRIVER SCOPE
be4c6d689139 bridge bridge local
a397efbb3fb4 demo bridge local
d843459f25fd host host local
7a3b4a1a7c00 none null local# 启动docker容器
[rootmking /]# docker run -itd --rm --name nginx --network demo -p 80:80 nginxdemo创建桥接的网卡名为br-a397efbb3fb4, 后续对该网卡规则进行理解。
2. 查看nat转发表信息
nat主要修改报文目标IP目标端口和源P地址源端口
[rootmking /]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 4 packets, 600 bytes)pkts bytes target prot opt in out source destination 0 0 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCALChain INPUT (policy ACCEPT 4 packets, 600 bytes)pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)pkts bytes target prot opt in out source destination 0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCALChain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)pkts bytes target prot opt in out source destination 0 0 MASQUERADE all -- * !docker0 10.0.254.0/24 0.0.0.0/0 0 0 MASQUERADE all -- * !br-a397efbb3fb4 10.2.254.0/24 0.0.0.0/0 0 0 MASQUERADE tcp -- * * 10.2.254.2 10.2.254.2 tcp dpt:80Chain DOCKER (2 references)pkts bytes target prot opt in out source destination 0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0 0 0 RETURN all -- br-a397efbb3fb4 * 0.0.0.0/0 0.0.0.0/0 0 0 DNAT tcp -- !br-a397efbb3fb4 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:10.2.254.2:80网桥 br-a397efbb3fb4 在nat 中处理逻辑。
PREROUTING: 外部流量到达主机时处理该链路主要动作是修改报文目的IP地址通过DNAT动作实现请求转发 链路展示所有报文会通过DOCKER CHAIN链, 该链也恰好有处理DNAT动作 OUTPUT: 流量出去的时候也会经过 DOCKER CHAIN。DOCKER 关于网桥 br-a397efbb3fb4 有两处处理。 RETURN处: 流量从网卡 br-a397efbb3fb4 进入的, 就不再继续向下匹配也就不修改目标IPDNAT: 流量从其他网卡进入且访问80端口的通过修改了目的地址指向nginx容器的IP: 10.2.254.2。 POSTROUTING: 内部流量从网卡出去时候处理, 该链路主要用于修改源IP地址用于响应回源。 br-a397efbb3fb4有2处处理 第二行 命令: iptables -t nat -A POSTROUTING ! -o br-a397efbb3fb4 -s 10.2.254.0/24 -j MASQUERADE理解: 来自源IP网段10.2.254.0/24 且流量不经过网卡 br-a397efbb3fb4 出去的报文修改动态源IP地址。 MASQUERADE 动态获取IP地址通常是网卡的IP地址。该规则也用于第一行的docker0。 说明这是docker创建网卡时的标准规则。 第三行: 命令: iptables -t nat -A POSTROUTING -p tcp --dport 80 -s 10.2.254.2 -d 10.2.254.2 -j MASQUERADE理解 对源IP和目标IP都是10.2.254.2且端口是80的TCP发出的报文动态修改源IP地址。 场景1: DNAT转换后报文是如何到达nginx的
假设外部通过eth0访问80端口先通过iptable规则进行报文分析处理 报文的入口网卡是eth0 在PREROUTING进行了目的端口转发那么报文就要发送到10.2.254.2 见docker链的DNAT规则 要求不是入口网卡 br-a397efbb3fb4 的报文进行DNAT转换网桥br-a397efbb3fb4 作为一个网关角色是保持内部通信的基础所以其IP不能进行改动 通过路由寻址。route -n 可以看到目标网段在10.2.254.0是通过br-a397efbb3fb4出去。 此时报文的入口是eth0, 报文的出口br-a397efbb3fb4br-a397efbb3fb4 和容器IP10.2.254.2 在同一个网段下且满足通信。 场景2: 容器是如何通过SNAT实现对外通信的 假设容器请求其他主机: 192.168.35.253删除a397efbb3fb4的SNAT规则后。进行ping测试 通过简单的分析拿到容器在主机的设备对网卡是vetha276645 在容器查看命令ip link show可以看容器网卡的ID外部的网卡ID。eth0if125外部查看ip link show查到125网卡vetha276645 ping 请求通过vetha276645到达主机后通过路由会从网卡eth0发出查看eth0抓包信息。可以看到是有报文出去
抓包容器网卡vetha276645向192.168.35.253发起请求
[rootmking net]# tcpdump -vvn -i vetha276645 icmp
tcpdump: listening on vetha276645, link-type EN10MB (Ethernet), capture size 262144 bytes
11:15:39.983214 IP (tos 0x0, ttl 64, id 19344, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 782, length 64
11:15:40.983457 IP (tos 0x0, ttl 64, id 19815, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 783, length 64
11:15:41.983658 IP (tos 0x0, ttl 64, id 20419, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 784, length 64
11:15:42.983858 IP (tos 0x0, ttl 64, id 21070, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 785, length 64抓包192.168.33.253 出口网卡也发出去请求
[rootmking ~]# tcpdump -i enp3s0 -p icmp -vvnn
tcpdump: listening on enp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:04:49.856208 IP (tos 0x0, ttl 63, id 10747, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 132, length 64
11:04:50.856421 IP (tos 0x0, ttl 63, id 11569, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 133, length 64
11:04:51.856633 IP (tos 0x0, ttl 63, id 11661, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 134, length 64
11:04:52.856829 IP (tos 0x0, ttl 63, id 12190, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 135, length 64
11:04:53.857026 IP (tos 0x0, ttl 63, id 12795, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 136, length 64抓包192.168.35.253 的确收到来自10.2.254.3的请求也尝试直接回复10.2.254.3它的请求但失败。
[roothost-253 ~]# tcpdump -i ens192 icmp -vvnn
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
11:05:53.852475 IP (tos 0x0, ttl 62, id 43080, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 196, length 64
11:05:53.852530 IP (tos 0x0, ttl 64, id 13542, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 10.2.254.3: ICMP echo reply, id 32, seq 196, length 64
11:05:54.852667 IP (tos 0x0, ttl 62, id 43886, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 197, length 64
11:05:54.852719 IP (tos 0x0, ttl 64, id 13570, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 10.2.254.3: ICMP echo reply, id 32, seq 197, length 64
11:05:55.312720 IP (tos 0x0, ttl 64, id 39942, offset 0, flags [DF], proto ICMP (1), length 60)192.168.35.253 125.64.129.223: ICMP echo request, id 3328, seq 5836, length 40
11:05:55.319196 IP (tos 0x0, ttl 56, id 39942, offset 0, flags [DF], proto ICMP (1), length 60)125.64.129.223 192.168.35.253: ICMP echo reply, id 3328, seq 5836, length 40
11:05:55.852795 IP (tos 0x0, ttl 62, id 44326, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 198, length 64
11:05:55.852817 IP (tos 0x0, ttl 64, id 13723, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 10.2.254.3: ICMP echo reply, id 32, seq 198, length 64
11:05:56.853000 IP (tos 0x0, ttl 62, id 45059, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 199, length 64
11:05:56.853028 IP (tos 0x0, ttl 64, id 13921, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 10.2.254.3: ICMP echo reply, id 32, seq 199, length 64
11:05:57.853198 IP (tos 0x0, ttl 62, id 45512, offset 0, flags [DF], proto ICMP (1), length 84)10.2.254.3 192.168.35.253: ICMP echo request, id 32, seq 200, length 64通过抓包可以简单分 容器10.2.254.3向192.168.35.253 发起了ICMP请求。主机192.168.33.253通过路由指定网卡进行外部通信目标192.168.35.253也收到来自IP10.2.254.3的请求目标192.168.35.253向10.2.254.3进行回应目标192.168.35.253找不到10.2.254.3, 因为他们本身不具备直接通信的条件。容器10.2.254.3 不能收到 192.168.35.253 响应。 导致网络不能互通 通过SNAT修改源IP地址让192.168.35.253可以和主机通信 对10.2.254.3修改源IP所以docker取网段范围-s 10.2.254.0/24满足更多容器其中br-a397efbb3fb4是一个网桥是内部通信的基础。所以不需要修改其源IP。假设修改了那么会造成主机内网不能互通的情况综合规则: iptables -t nat -A POSTROUTING ! -o br-a397efbb3fb4 -s 10.2.254.0/24 -j MASQUERADE
主机抓包后可以看到icmp的报文原始IP地址变更主机网卡IP地址
[rootmking ~]# tcpdump -i enp3s0 -p icmp -vvnn
tcpdump: listening on enp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
11:23:42.355262 IP (tos 0x0, ttl 63, id 62150, offset 0, flags [DF], proto ICMP (1), length 84)192.168.33.233 192.168.35.253: ICMP echo request, id 33, seq 9, length 64
11:23:42.355422 IP (tos 0x0, ttl 63, id 16529, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 192.168.33.233: ICMP echo reply, id 33, seq 9, length 64
11:23:43.355476 IP (tos 0x0, ttl 63, id 62489, offset 0, flags [DF], proto ICMP (1), length 84)192.168.33.233 192.168.35.253: ICMP echo request, id 33, seq 10, length 64
11:23:43.355662 IP (tos 0x0, ttl 63, id 16562, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 192.168.33.233: ICMP echo reply, id 33, seq 10, length 64目标主机抓包信息的请求源地址也是满足可以通信的主机IP地址。并且能正常响应回复
[rootrunner253 ~]# tcpdump -i ens192 icmp -vvnn
tcpdump: listening on ens192, link-type EN10MB (Ethernet), capture size 262144 bytes
11:26:11.368853 IP (tos 0x0, ttl 62, id 12798, offset 0, flags [DF], proto ICMP (1), length 84)192.168.33.233 192.168.35.253: ICMP echo request, id 33, seq 158, length 64
11:26:11.368893 IP (tos 0x0, ttl 64, id 26732, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 192.168.33.233: ICMP echo reply, id 33, seq 158, length 64
11:26:12.369095 IP (tos 0x0, ttl 62, id 13330, offset 0, flags [DF], proto ICMP (1), length 84)192.168.33.233 192.168.35.253: ICMP echo request, id 33, seq 159, length 64
11:26:12.369136 IP (tos 0x0, ttl 64, id 27102, offset 0, flags [none], proto ICMP (1), length 84)192.168.35.253 192.168.33.233: ICMP echo reply, id 33, seq 159, length 64目前docker主机可以收到来自目标主机的回复响应主机又如何把回复响应转交给docker容器 根据网上查询自己没有验证。 当创建SNAT后iptables也会自动在nat创建DNAT规则用于回源到最原始的IP 简单总结nat规则目的
外部对内请求会在PREROUTING链DNAT转发请求到容器端口。外部对内过程没有修改源IP地址。所以容器是可以拿到客户端IP地址。内部对外访问会在POSTROUTING链SNAT转发请求到外部网络。内部对外修改了源IP地址。所以目的端收到的IP服务器出网的网卡IP。
3. 查看filter 过滤表信息
filter主要对流量进行拦截 查看主机规则。 很多都是docker创建, 还是以br-a397efbb3fb4为例。
[rootmking /]# iptables -t filter -nvL
Chain INPUT (policy ACCEPT 9502 packets, 752K bytes)pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)pkts bytes target prot opt in out source destination 34 5744 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0 34 5744 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0 16 2984 ACCEPT all -- * br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED2 120 DOCKER all -- * br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 16 2640 ACCEPT all -- br-a397efbb3fb4 !br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT all -- br-a397efbb3fb4 br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 Chain DOCKER (2 references)pkts bytes target prot opt in out source destination 2 120 ACCEPT tcp -- !br-a397efbb3fb4 br-a397efbb3fb4 0.0.0.0/0 10.2.254.2 tcp dpt:80Chain DOCKER-ISOLATION-STAGE-1 (1 references)pkts bytes target prot opt in out source destination 0 0 DOCKER-ISOLATION-STAGE-2 all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 16 2640 DOCKER-ISOLATION-STAGE-2 all -- br-a397efbb3fb4 !br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 34 5744 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 Chain DOCKER-ISOLATION-STAGE-2 (2 references)pkts bytes target prot opt in out source destination 0 0 DROP all -- * docker0 0.0.0.0/0 0.0.0.0/0 0 0 DROP all -- * br-a397efbb3fb4 0.0.0.0/0 0.0.0.0/0 16 2640 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0 Chain DOCKER-USER (1 references)pkts bytes target prot opt in out source destination 34 5744 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
通过链路分析关于网桥 br-a397efbb3fb4 处理拦截。 PREROUTING 链路 进入主机后规则匹配成功修改目标IP地址。 INPUT 链: 对所有目的IP存在本机的流量进行处理 因为容器对网络环境进行了隔离所以当前主机 ( ip address和ifconfig ) 没有容器IP地址。 FORWARD 链:对所有目的IP不在本机的流量进行处理 容器IP不在主机网络的会经过当前链进行拦截处理。网桥 br-a397efbb3fb4 处理动作有3个 第三行规则 命令: iptables -I FOREWARD -o br-a397efbb3fb4 -m stat RELATED,ESTABLISHED -j ACCEPT理解: 经过br-a397efbb3fb4出去的网络允许回应报文通过。 第四行规则 命令: iptables -I FOREWARD -o br-a397efbb3fb4 -j DOCKER理解: 经过br-a397efbb3fb4出去的网络由Docker进一步筛选控制。 第五行规则: iptables -I FOREWARD -i br-a397efbb3fb4 ! -o br-a397efbb3fb4 -j ACCEPT 规则翻译: 允许经过br-a397efbb3fb4进的网络, 从其他网卡出去。本质是允许容器内网与外网通信。 第六行规则: iptables -I FOREWARD -i br-a397efbb3fb4 -o br-a397efbb3fb4 -j ACCEPT 规则翻译: 允许经过br-a397efbb3fb4进的网络并从该网卡出去 OUTPUT 链: 通过网卡出去的网络进行拦截。 此处不涉及 Docker 链: 对于br-a397efbb3fb4有一项处理 第一行规则: 命令: iptables -I DOCKER -p tcp --dport 80 -d 10.2.254.2 ! -i br-a397efbb3fb4 -o br-a397efbb3fb4 -j ACCEPT理解: 允许非br-a397efbb3fb4网络到br-a397efbb3fb4网络对目标IP 10.2.254.2 进行80端口访问 DOCKER-ISOLATION-STAGE-1规则上最终交给DOCKER-ISOLATION-STAGE-2: 有一个丢包机制 第二行规则: 命令:iptables -I DOCKER-ISOLATION-STAGE-2 -o br-a397efbb3fb4 -j DROP理解: 拒绝从网桥br-a397efbb3fb4出去的流量 场景1: 外部请求容器服务需要经历哪些关卡
从192.168.35.253访问 容器HTTP 服务请求经过eth0进入主机。在PREROUTING链路修改目的IP地址通过目的端口转向到10.2.254.2路由选择: 匹配到10.2.254.2需要经过过br-a397efbb3fb4出去 报文入口网卡是eth0分组出口网卡是br-a397efbb3fb4 目标IP不在主机网络经过FORWARD链处理,这里主要有2个处理 尝试建立链接: 允许 TCP 3次握手所以满足RELATED,ESTABLISHED进行放行。 行三规则已经建立链接: 允许通过来自外部对10.2.254.2的80端口访问。 行四规则 场景2: 容器对外请求/响应需要经历哪些关卡
容器 回复 192.168.35.253的响应报文经过br-a397efbb3fb4到达主机在POSTROUTING链路修改了源IP地址。路由选择: 匹配到192.168.35.253需要经过eth0出去 流量入口网卡是br-a397efbb3fb4。流量出口网卡是eth0 目标IP不在主机网络经过FORWARD链处理。 允许从其他网卡出去。行五规则 场景3: 不同网络的容器是如何隔离的
10.1.254.2 尝试建立 10.2.254.2请求10.1.254.2 从docker0进入主机路由选择: 匹配到10.2.254.2需要经过过br-a397efbb3fb4出去 流量入口网卡是docker0流量出口网卡是br-a397efbb3fb4 目标IP不在主机网络经过FORWARD, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2 链处理。 拒绝从br-a397efbb3fb4出去的网卡 第二行规则拒绝之后到达RETURN规则不再进行匹配。验证取消容器网络之间的隔离: iptables -F DOCKER-ISOLATION-STAGE-2
四、 模拟docker网络通信
1. 通过shell命令实现网络隔离, 并实现内部通信和外网通信
1. 准备工作
会用到centos网络设备管理命令
ip help # 支持子命令。 所有的命令: 增(add)删(delete/rm)改(set/put)查(show)
ip link # 查看网络连接, 网卡支持虚拟技术的。硬件虚拟vmware就是硬件虚拟机。
ip link type bridge 虚拟网卡 / veth: 一对虚拟网卡(常见用于docker命名空间隔离)
ip address # 查看IP地址
ip netns # 网络命名空间简单理解虚拟了一个环境与外部独立。
ip route # 查看路由。 看IP怎么走的网桥: 网络连接的一种形式主要连接多个局域网(lan) 进行流量接收存储和转发。 虚拟以太网设备对(veth-pair): 网络连接的另一种形式, 会产生一对网卡。常用于网络隔离通信。
2. 设备对通信
创建一个网络隔离的namespace: demo
[rootmking /]# ip netns add demo
# 查看网络NS信息
[rootmking /]# ip netns ls
demo创建一组网卡设备对: veth pair。
设备对网卡可以通过关键字快速辨别。 51,51 表示网卡的编号ID , peer1和peer2表示网卡别名
[rootmking /]# ip link add name peer0 type veth peer name peer1
[rootmking /]# ip link show
51: peer1peer0: BROADCAST,MULTICAST,M-DOWN mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 6a:a0:1b:3a:58:e5 brd ff:ff:ff:ff:ff:ff
52: peer0peer1: BROADCAST,MULTICAST,M-DOWN mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000link/ether 6e:90:2d:40:59:1e brd ff:ff:ff:ff:ff:ff把peer0的网卡对设置到另一个命名空间 demo
[rootmking /]# ip link set peer0 netns demo查不到编号52:peer0peer1 的网卡同时编号51网卡显示: peer1if52, 说明编号52网卡存在但已被设置到其他的ns, 当前的ns查看不了
[rootmking /]# ip link show
1: lo: LOOPBACK,UP,LOWER_UP mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp3s0: BROADCAST,MULTICAST,UP,LOWER_UP mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000link/ether d4:5d:64:7f:92:66 brd ff:ff:ff:ff:ff:ff
51: peer1if52: BROADCAST,MULTICAST,UP,LOWER_UP mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000link/ether 6a:a0:1b:3a:58:e5 brd ff:ff:ff:ff:ff:ff link-netnsid 分别为两张网卡设置IP实现通信。 veth pari创建的设备对默认链路是通的。
# 操作宿主机默认的NS。 操作中需要满足IP在一个网段内。
[rootmking /]# ip address add 10.100.0.15/16 dev peer1
[rootmking /]# ip link set dev peer1 up# 操作隔离的NS: 设置IP地址并启动
[rootmking /]# ip netns exec demo ip address add 10.100.15.34/16 dev peer0
[rootmking /]# ip netns exec demo ip link set dev peer0 up相互ping测
[rootmking /]# ip netns exec demo ping 10.100.0.15
PING 10.100.0.15 (10.100.0.15) 56(84) bytes of data.
64 bytes from 10.100.0.15: icmp_seq1 ttl64 time0.081 ms
64 bytes from 10.100.0.15: icmp_seq2 ttl64 time0.047 ms
64 bytes from 10.100.0.15: icmp_seq3 ttl64 time0.046 ms# 从宿主机进行探测ping通10.100.15.34
[rootmking /]# ping 10.100.15.34
PING 10.100.15.34 (10.100.15.34) 56(84) bytes of data.
64 bytes from 10.100.15.34: icmp_seq1 ttl64 time0.066 ms
64 bytes from 10.100.15.34: icmp_seq2 ttl64 time0.046 ms
64 bytes from 10.100.15.34: icmp_seq3 ttl64 time0.046 ms宿主机创建隔离网络空间demo实现通信 主要步骤如下
创建一个ns独立的网络空间创建一组虚拟设备对 veth pair 产生两张网络接口满足通信链路条件其中一张网卡设置在ns两张网卡IP在同一个网段启动两张网卡
3.多个隔离网络之间的通信
我们实现了一个ns与主机的通信现在模拟docker多个容器之间的通信: 即可实现多个ns内部相互通信。
IP段规划
设备命名空间IP广播地址备注br0default10.105.0.110.105.255.255拟gatewayvir10default10.105.1.11010.105.255.255veth-peer中的一个网卡vir11ns110.105.3.5010.105.255.255veth-peer中的一个网卡vir20default10.105.2.11010.105.255.255veth-peer中的一个网卡vir21ns210.105.8.11010.105.255.255veth-peer中的一个网卡
IP二进制换算: 128 64 32 16 8 4 2 1 10.105.0.1 00001010.01101001.00000000.00000001 子网换算 10.105.0.1/24 00001010.01101001.00000000.xxxxxxxx 10.105.0.0-10.105.0.25510.105.0.1/20 00001010.01101001.0000xxxx.xxxxxxxx 10.105.0.0-10.105.31.25510.105.0.1/16 00001010.01101001.xxxxxxxx.xxxxxxxx 10.105.0.0-10.105.255.255 需求 创建桥接网卡模拟gateway的功能实现arpns1网卡满足通过gateway找到ns2的网卡实现通信 要求 隔离在ns1的网卡需要访问到gateway隔离在ns2的网卡也需要访问到gateway 已知 ns1的vir11可以与vir10进行通信vir10可以与gateway直接通信ns2的vir21可以与vir20进行通信vir11可以与gateway直接通信 可得 vir11可以通过vir10把数据请求到gateway进行通信vir21可以通过vir20把数据请求到gateway进行通信
创建两个ns, 模拟两个docker网络环境
[rootmking /]# ip netns add ns1
[rootmking /]# ip netns add ns2同上两组网卡设备对vir10(主机)/vir11(ns1)和vir20(主机)/vir21(ns2)。 同一主机内的vir10和vir20是相互独立的, 需要创建一张网卡作为其网关,将流量转发到网关, 用于arp IP寻址 此处设置默认网关地址10.105.0.1/16, 广播地址得出 10.105.255.255。
# 安装相关命令
[rootmking /]# yum install bridge-utils -y# 创建一张桥接网卡
[rootmking /]# brctl addbr gateway1# 为gateway1设置网卡IP并启动
[rootmking /]# ip address add 10.105.0.1/16 broadcast 10.105.255.255 dev gateway1
[rootmking /]# ip link set dev gateway1 up同上两组网卡设备对veth pair分别用于ns1和ns2。 并对两组ns设置IP要求在同一个网段内不需要设置vir10和vir20网卡
# 创建vir1x和vir2x的veth peer网卡
[rootmking /]# ip link add name vir10 type veth peer name vir11
[rootmking /]# ip link add name vir20 type veth peer name vir21# 把vir11和vir21网卡分别放在ns1和ns2中
[rootmking /]# ip link set vir11 netns ns1
[rootmking /]# ip link set vir21 netns ns2# 分别为vri11和vir21设置IP并启动环路lo网卡
[rootmking /]# ip netns exec ns1 ip address add 10.105.3.50/16 broadcast 10.105.255.255 dev vir11
[rootmking /]# ip netns exec ns1 ip link set dev vir11 up
[rootmking /]# ip netns exec ns1 ip link set dev lo up[rootmking /]# ip netns exec ns2 ip address add 10.105.8.110/16 broadcast 10.105.255.255 dev vir21
[rootmking /]# ip netns exec ns2 ip link set dev vir21 up
[rootmking /]# ip netns exec ns2 ip link set dev lo up设置同主机内的 vir10和vir20 , 我们将网卡指向到gateway1
# 处理vir10和vir20, 把vir10和vir20 指向到gateway1
[rootmking /]# brctl addif gateway1 vir10
[rootmking /]# brctl addif gateway1 vir20# 启动同一主机下的网卡
[rootmking /]# ip link set dev vir10
[rootmking /]# ip link set dev vir20# 查看网桥信息
[rootmking /]# brctl show
bridge name bridge id STP enabled interfaces
gateway1 8000.7e6c5709cc5e no vir10vir20至此ns1和ns2可以相互ping通, 理论上不同的网络隔离空间下的设备对网卡指向到gateway1都可以访问
# 从ns1 访问 ns2
[rootmking /]# ip netns exec ns1 ping 10.105.8.110
PING 10.105.8.110 (10.105.8.110) 56(84) bytes of data.
64 bytes from 10.105.8.110: icmp_seq1 ttl64 time0.043 ms
64 bytes from 10.105.8.110: icmp_seq2 ttl64 time0.042 ms
64 bytes from 10.105.8.110: icmp_seq3 ttl64 time0.122 ms# 从ns2 访问 ns1
[rootmking /]# ip netns exec ns2 ping 10.105.3.50
PING 10.105.3.50 (10.105.3.50) 56(84) bytes of data.
64 bytes from 10.105.3.50: icmp_seq1 ttl64 time0.068 ms
64 bytes from 10.105.3.50: icmp_seq2 ttl64 time0.038 ms
64 bytes from 10.105.3.50: icmp_seq3 ttl64 time0.105 ms多个网络空间ns实现通信 主要步骤如下
创建多个ns 和多组 veth pair 虚拟设备对的网卡设备对的一端网卡分别设置在多个ns1宿主机创建一张bridge网卡设备对的另一端网卡添加到bridge网卡。ns里面的网卡和bridge网卡的IP设置在一个网段内
4.多个NS对外通信
模拟了多个docker的网络隔离之间通信现在模拟docker对外的通信。
创建两个ns, 模拟两个docker网络环境。 此处继续使用之间建好的ns1和ns2。
# 从ns1 访问外网寻址失败
[rootmking /]# ip netns exec ns2 ping 61.139.2.69
connect: Network is unreachable# 从ns2 访问外网, 寻址失败
[rootmking /]# ip netns exec ns1 ping 61.139.2.69
connect: Network is unreachable创建默认路由让请求外网的分组请求到gateway1
# 添加默认路由
[rootmking /]# ip netns exec ns1 route add default gw 10.105.0.1
[rootmking /]# ip netns exec ns2 route add default gw 10.105.0.1# 访问外网但无响应。
[rootmking /]# ip netns exec ns1 ping 61.139.2.69
PING 61.139.2.69 (61.139.2.69) 56(84) bytes of data.
2 packets transmitted, 0 received, 100% packet loss, time 1000ms[rootmking /]# ip netns exec ns2 ping 61.139.2.69
PING 61.139.2.69 (61.139.2.69) 56(84) bytes of data.
2 packets transmitted, 0 received, 100% packet loss, time 1001ms# 查看gateway1有分组经过。RX packets 接收流量, TX packets 13 传输流量
[rootmking /]# ifconfig gateway1
gateway1: flags4163UP,BROADCAST,RUNNING,MULTICAST mtu 1500inet 10.105.0.1 netmask 255.255.0.0 broadcast 10.105.255.255inet6 fe80::dcb0:d8ff:fe6b:856f prefixlen 64 scopeid 0x20linkether 22:4e:62:c8:f3:80 txqueuelen 1000 (Ethernet)RX packets 33 bytes 2124 (2.0 KiB)RX errors 0 dropped 0 overruns 0 frame 0TX packets 13 bytes 978 (978.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0此时ns1 和 ns2 可以把流量发送到网卡gateway1。
分析ns1流量走势
iptables处理分组时间轴
timelinetitle iptables时间线PREROUTING : natINPUT : filter: natFORWARD : natOUTPUT : filter: natPOSTROUTING: nat分组从 ns1 的网卡 vir11 经过vir10 到达网卡gateway, 会经过如下判断
PREROUTING 事件: 接收分组时候备注: 对分组进行修改, 此处不修改 FORWARD: 事件: 接收分组后执行动作: 放行触发条件: 目标IP不在主机. 所以进行forward转发 POSTROUTING: 事件: 通过转发后触发执行动作: 修改报文source ip, 本质是将分组交给source ipaddress发出去
# 放行FORWARD, 流入gateway1网卡分组通过。 主要是通过来自ns1,ns2请求流量
[rootmking /]# iptables -t filter -I FORWARD -i gateway1 -j ACCEPT# 放行FORWARD, 出口gateway1网卡分组通过。 主要是通过返回ns1,ns2响应流量
[rootmking /]# iptables -t filter -I FORWARD -o gateway1 -j ACCEPT# 地址转换, 把gateway1网段的分组, 修改Source IP或指定网卡IP。实现外部请求
[rootmking /]# iptables -t nat -A POSTROUTING -s 10.105.0.0/16 -o ens33 -j MASQUERADE自建的ns1 可以访问外部网络。
[rootmking /]# ip netns exec ns2 ping 61.139.2.69
PING 61.139.2.69 (61.139.2.69) 56(84) bytes of data.
64 bytes from 61.139.2.69: icmp_seq1 ttl57 time3.09 ms
64 bytes from 61.139.2.69: icmp_seq2 ttl57 time3.03 ms
64 bytes from 61.139.2.69: icmp_seq3 ttl57 time3.44 ms
--- 61.139.2.69 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms5.外部访问NS网络
实现ns可以访问外网模拟外网如何访问ns内部服务(访问docker服务) 前置条件: 创建一个ns, 并要求ns网络可以对外访问。 此处继续使用之间建好的ns1和ns2。 终端1在ns1开启一个端口
[rootmking /]# ip netns exec ns1 nc -l -p 8000终端2检查ns1端口情况
[rootmking /]# ip netns exec ns1 netstat -anpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 26130/nc
tcp6 0 0 :::8000 :::* LISTEN 26130/nc 通过iptables的DNAT转发对外提供访问
enp3s0 网卡收到外部请求端口: 8000。 可通过iptables如下链路
PREROUTING 事件: 接收分组时候。执行动作: 修改目的IP和端口。备注: 因为当前主机是没有提供端口服务而主机与ns1可以直接通信。 所以在入口时通过修改dst address和dst port转发请求到目的网络 FORWARD: 事件: 接收分组后执行动作: 放行触发条件: 目标IP已改目的不在主机. 所以进行forward转发
# 放行FORWARD, 流入gateway1网卡分组通过。 主要是通过来自ns1,ns2请求流量
[rootmking /]# iptables -t filter -I FORWARD -i gateway1 -j ACCEPT# 放行FORWARD, 出口gateway1网卡分组通过。 主要是通过返回ns1,ns2响应流量
[rootmking /]# iptables -t filter -I FORWARD -o gateway1 -j ACCEPT# 地址转换, 把gateway1网段的分组, 修改Source IP或指定网卡IP。实现外部请求
[rootmking /]# iptables -t nat -I PREROUTING -p tcp --dport 8000 -j DNAT --to-destination 10.105.3.50验证自建的ns1 对外提供端口访问。
# 从其他设备访问8000
[rootothers /]# telnet 192.168.33.253 8000# 检查ns1的网络连接情况
[rootmking /]# ip netns exec ns1 netstat -anpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 10.105.3.50:8000 192.168.35.253:48246 ESTABLISHED 26332/nc 可以看到8000端口有来自192.168.35.253的访问基础目标完成
2. 给docker做适配: 为容器接入自定义ns集群
目标: 把自建隔离的网络放入到docker中
创建好一组虚拟网卡设备对, 规划和gateway1相同的IP段.
# 创建ns3
[rootmking /]# ip netns add ns3# 创建新的虚拟网卡设备对
[rootmking /]# ip link add name vir30 type veth peer name vir31启动一个nginx docker,不暴露端口。
# 启动一个nginx服务并使用自定义网络, 但不暴露端口。
[rootmking /]# docker run --name nginx --network demo -itd --rm nginx 指定网络是docker启动会创建新的隔离网络, 不暴露端口是咱不使用docker-proxy代理。
ns的信息主要存放在路径: /var/run/netns/, 通过创建 /proc/${pid}/ns/net 软连接便可以管理进程的ns。
# 查询docker容器ID
[rootmking /]# docker inspect nginx --format{{ .State.Pid }}
6331# 创建PID下的ns软连接到/var/run/netns/ngx, 便可以ngx去管理docker启动nginx容器网络
[rootmking /]# ln -s /proc/6331/ns/net /var/run/netns/ngx# 可以查看目前ngx有一张网卡
[rootmking net]# ip netns exec ngx ifconfig
eth0: flags4163UP,BROADCAST,RUNNING,MULTICAST mtu 1500inet 10.2.254.2 netmask 255.255.255.0 broadcast 10.2.254.255ether 02:42:0a:02:fe:02 txqueuelen 0 (Ethernet)RX packets 8 bytes 656 (656.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0将vir31网卡设置到ngx内。把vir30网卡添加到gateway1的网桥
# 把vir31网卡设置到ngx内
[rootmking net]# ip link set vir31 netns ngx # 查看目前ngx新加入的eth1
[rootmking net]# ip netns exec ngx ifconfig vir31# 设置IP段
[rootmking /]# ip netns exec ngx ip address add 10.105.1.250/16 broadcast 10.105.255.255 dev vir31# 查看网卡信息
[rootmking net]# ip netns exec ngx ifconfig vir31
vir31: flags4098BROADCAST,MULTICAST mtu 1500inet 10.105.1.250 netmask 255.255.0.0 broadcast 10.105.255.255ether 76:f4:11:39:f9:48 txqueuelen 1000 (Ethernet)RX packets 0 bytes 0 (0.0 B)RX errors 0 dropped 0 overruns 0 frame 0TX packets 0 bytes 0 (0.0 B)TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0# 启动容器网卡
[rootmking net]# ip netns exec ngx ip link set vir31 up
# 启动主机网卡
[rootmking net]# ip link set vir30 up# 把外部的vir30网卡添加到gateway1.
[rootmking net]# brctl addif gateway1 vir30
内部ns访问容器网络
# 在ns1访问ngx的IP。
[rootmking net]# ip netns exec ns1 curl http://10.105.1.250 #查看nginx的日志
[rootmking /]# docker logs -f nginx
10.105.3.50 - - [12/Jul/2024:07:24:36 0000] GET / HTTP/1.1 200 615 - curl/8.5.0 -通过iptables方式暴露对外访问
# 先放行FORWARD以上已做,
[rootmking net]# iptables -I FORWARD -i gateway1 -j ACCEPT
[rootmking net]# iptables -I FORWARD -o gateway1 -j ACCEPT#添加 nat 地址映射。更改目标IP
[rootmking net]# iptables -t nat -I PREROUTING -p tcp --dport 8002 -j DNAT --to-destination 10.105.1.250:80#查看nginx的日志
[rootmking /]# docker logs -f nginx
192.168.35.253 - - [12/Jul/2024:07:55:21 0000] GET / HTTP/1.1 200 615 - curl/7.29.0 -小结
docker利用桥接和虚拟设备对实现网络隔离以及通信。docker网络通过iptables对分组进行拦截过滤和转发。