《零入门kubernetes网络实战》视频专栏地址
https://www.ixigua.com/7193641905282875942
本篇文章视频地址(稍后上传)
通过DNAT技术可以将brige虚拟网桥管理的内网中的服务暴露出来,以供外网访问。
1、测试环境介绍 |
两台centos虚拟机
# 查看操作系统版本
cat /etc/centos-release
# 内核版本
uname -a
uname -r
# 查看网卡信息
ip a s eth0
2、网络拓扑 |
从Slave节点的用户空间里的curl应用发起请求。
3、操作实战 |
3.1、第1步:在master上执行下面的命令 |
brctl addbr br0
ip link set br0 up
ip addr add 10.244.1.3/24 dev br0
ip netns add ns1
ip link add veth1a type veth peer name veth1b
ip link set veth1a netns ns1
ip netns exec ns1 ip addr add 10.244.1.2/24 dev veth1a
ip netns exec ns1 ip link set veth1a up
ip link set veth1b up
brctl addif br0 veth1b
ip netns exec ns1 route add default gw 10.244.1.3
iptables -t nat -A PREROUTING -d 10.211.55.122 -p tcp --dport 8090 -i eth0 -j DNAT --to 10.244.1.2:9090
echo 1 > /proc/sys/net/ipv4/ip_forward
3.2、第2步:被测试服务 |
3.2.1、被测试服务代码 |
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type Stu struct {
Age int
Msg string
}
const ip = "0.0.0.0"
func sayHello(w http.ResponseWriter, r *http.Request) {
stu := Stu{Age: 12, Msg: "hello world! this is DNAT+bridge+Veth pair Test!"}
stuJson, e := json.Marshal(&stu)
if e != nil {
panic(e)
}
w.Write(stuJson)
fmt.Printf("Reply MSG:%v\tlen(Msg):%d\n", string(stuJson), len(stuJson))
}
func main() {
http.HandleFunc("/", sayHello)
fmt.Printf(fmt.Sprintf("App URL: http://%s:%d\n", ip, 9090))
err := http.ListenAndServe(fmt.Sprintf("%s:%d", ip, 9090), nil)
if err != nil {
fmt.Printf("http server failed, err:%v\n", err)
return
}
}
不用关心测试代码的具体逻辑,主要是关心请求后,是否有正常打印输出即可。
3.2.2、本地编译,上传到Master节点 |
Makefile
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o http-web main.go
scp:
scp http-web root@10.211.55.122:/root
all:
make build && make scp
大家可以根据自己的实际情况进行修改。
直接执行
make all
3.3、第3步:在master节点上,ns1命名空间里启动http-web服务 |
ip netns exec ns1 ./http-web
3.4、第4步:slave节点上发起curl请求 |
curl 10.211.55.122:8090
4、从iptables链的角度,对整个过程进行分析 |
为了分析整个传输过程,我们添加一些日志埋点,来验证我们的猜测。
如果你已经根据前面的文章安装过了rsyslog服务,就不需要重复操作了
4.1、安装 |
4.1.1、安装rsyslog服务 |
yum -y install rsyslog
4.1.2、更新配置文件 |
echo "kern.* /var/log/iptables.log" >> /etc/rsyslog.conf
.*,表示所有等级的消息都添加到iptables.log文件里
信息等级的指定方式
- .XXX,表示 大于XXX级别的信息
- .=XXX,表示等于XXX级别的信息
- 如,kern.=notice /var/log/iptables.log, 将notice以上的信息添加到iptables.log里
- .!XXX, 表示在XXX之外的等级信息
4.1.3、重启rsyslog服务 |
systemctl restart rsyslog
systemctl status rsyslog
4.2、日志埋点 |
4.3、在master节点上,进行日志埋点 |
将当前的日志统计清零
iptables -t nat -Z
iptables -t filter -Z
插入日志埋点前,先查看一下,当前的现状
iptables -t nat -nvL PREROUTING --line-number
iptables -t nat -nvL INPUT --line-number
iptables -t filter -nvL FORWARD --line-number
iptables -t nat -nvL POSTROUTING --line-number
插入日志埋点
iptables -t nat -I PREROUTING -d 10.211.55.0/24 -p tcp --dport 8090 -j LOG --log-prefix "Test-nat-PREROUTING-2-"
iptables -t filter -A FORWARD -d 10.244.1.0/24 -p tcp -j LOG --log-prefix "Test-filter-FORWARD-1-"
iptables -t nat -I POSTROUTING -p tcp -d 10.244.1.0/24 -j LOG --log-prefix "Test-nat-POSTROUTING-2-"
iptables -t filter -A FORWARD -d 10.211.55.0/24 -p tcp --sport 9090 -j LOG --log-prefix "Test-filter-FORWARD-333-"
也可以查看一下,ns1命名空间的iptables规则链情况
ip netns exec ns1 iptables -t nat -nvL
查看日志文件
tail -f /var/log/iptables.log
4.3.1、在slave节点上,进行日志埋点 |
将当前的日志统计清零
iptables -t nat -Z
iptables -t filter -Z
插入日志埋点前,先查看一下,当前的现状
iptables -t nat -nvL OUTPUT --line-number
iptables -t filter -nvL OUTPUT --line-number
iptables -t nat -nvL POSTROUTING --line-number
iptables -t nat -nvL PREROUTING --line-number
iptables -t filter -nvL INPUT --line-number
插入日志埋点
iptables -t nat -I OUTPUT -d 10.211.55.0/24 -p tcp --dport 8090 -j LOG --log-prefix "Test-nat-OUTPUT-1-"
iptables -t filter -I OUTPUT -d 10.211.55.0/24 -p tcp --dport 8090 -j LOG --log-prefix "Test-filter-OUTPUT-1-"
iptables -t nat -I POSTROUTING -d 10.211.55.0/24 -p tcp --dport 8090 -j LOG --log-prefix "Test-nat-POSTROUTING-1-"
iptables -t filter -I INPUT -d 10.211.55.0/24 -p tcp --sport 8090 -j LOG --log-prefix "Test-nat-INPUT-1-"
查看日志文件
tail -f /var/log/iptables.log
4.4、测试 |
4.4.1、在slave节点,发起请求 |
curl 10.211.55.122:8090
4.4.2、查看一下,master上日志 |
tail -f /var/log/iptables.log
4.4.3、查看一下,slave上日志 |
4.5、整个传输过程,数据包经过了哪些iptables链呢? |
下图是 从slave节点通过curl发起请求的路线
这个图,主要是要明白一点,外部数据包进入到eth0网卡后,经过了哪些链才能到达br0
需要经过PRETOUTING链,FORWARD链,POSTROUTING链,才能到达虚拟网桥br0
下图是 master节点上的http-web服务接收到请求后的,反馈路线
备注:
反馈路线,仅供参考。
我个人是有疑问的。
比方说,Master节点上,eth0接收到反馈数据包后,没有走nat表中的PREROUTING链,当然,走了raw,mangle表中的PREROUTING链。
5、传输过程中,数据包是否被修改过? |
5.1、针对master节点上的eth0进行抓包 |
tcpdump -nn -i eth0 -p tcp and dst port 8090
tcpdump -nn -i eth0 -p tcp and dst port 8090 -w icmp-eth0.pcap
5.2、针对master节点上的br0网桥进行抓包 |
tcpdump -nn -i br0 -w icmp-br0.pcap
5.3、传输过程中数据包的报文内容变化 |
即,经过DNAT操作后数据包的变化,如下
6、总结 |
- 通过DNAT操作,可以将内网的服务暴露到外面,以供外网访问。端口映射
- 通过SNAT或者MASQUERADE操作,可以允许内网去访问外网的服务。
- DNAT和SNAT刚好相反,
- 因此,在实际中,要明白到底用哪个?还是一起使用。
- 比方说,kube-proxy里都使用了DNAT、MASQUERADE操作。
- 即,通过DNAT将POD里的服务暴露出来,通过MASQUERADE允许POD内部的服务去访问外网服务。
<<零入门kubernetes网络实战>>技术专栏之文章目录