kubernetes集群管理介绍:浅谈Iptables及其在
kubernetes集群管理介绍:浅谈Iptables及其在filter:input、forward、outputnat:prerouting、output、postroutingNAT基本结构三个表
Iptables 是一个运行在用户空间的应用软件,通过控制 Linux 内核 netfilter 模块,来管理网络数据包的流动与转送。
需要用到 ROOT 权限。OSI 模型的二、三、四层。
主要功能
-
防火墙
-
NAT
基本结构
三个表
-
nat:prerouting、output、postrouting
-
filter:input、forward、output
-
mangle:具有五条链,并且表中的链在包的处理流程中处于比较优先的位置
五条链
-
prerouting:路由前经过这条链,设置 mark 以及 DNAT
-
input:主要是 filter 表,设置防火墙规则
-
forward:主要是 filter 表,设置防火墙规则
-
output:主要是 filter 表,设置防火墙规则
-
postrouting:主要是 nat 表,设置 SNAT
术语解释
-
SNAT:在 postrouting 链,修改包的源地址,通常是为了多个内网用户共享一个外网端口来访问外网
-
DNAT:在 prerouting 链,修改包的目的地址,通常是为了让外部访问内网中的服务
状态跟踪机制
(点击图片放大查看)
(点击图片放大查看)
常见应用场景
简单的 nat 路由器
场景描述:内网中有一台机器,有内网 IP 10.1.1.254/24 eth0 和外网 IP 60.1.1.1/24 eth1。如何控制内网中的其他机器(只有内网 IP)通过这台机器访问外网的行为。
分析:
-
首先将其他内网机器的网关设置为 10.1.1.254
-
打开 Linux 转发功能,并且设置默认的转发策略为 DROP:
sysctl net.ipv4.ip_forward=1
iptables -P FORWARD DROP
-
设置 NAT 规则
iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -j SNAT --to 60.1.1.1
-
假如允许 10.1.1.9 访问外网
iptables -A FORWARD -s 10.1.1.9 -j ACCEPT
-
假如只允许访问 3.3.3.3 这个 ip
iptables -A FORWARD -d 3.3.3.3 -j ACCEPT
-
但是设置了上面的规则后,并不能正常工作,流量能正常的出去,但是回不来,还需要设置
iptables -A FORWARD -m state --state ESTABLISHED RELATED -j ACCEPT
这条规则应该放到第一条,以提高效率。
端口转发
场景描述:内网中有一台机器,有内网 IP 10.1.1.254/24 eth0 和外网 IP 60.1.1.1/24 eth1。另一台内网机器上有一个 webserver,地址为 10.1.1.1:80。如何配置规则让外部可以访问到内网的 web 服务器。
分析:
-
打开 Linux 的转发功能
sysctl net.ipv4.ip_forward=1
-
设置默认转发策略
iptables -P FORWARD DROP
-
利用状态跟踪机制,允许 ESTABLISHED RELATED 连接上的包通过
iptables -A FORWARD -m state --state ESTABLISHED RELATED -j ACCEPT
-
设置 DNAT
iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp --dport 80 -j DNAT --to 10.1.1.1:80
-
设置 Forward 规则,允许某类型的包通过
iptables -A FORWARD -d 10.1.1.1 -p tcp --dport 80 -j ACCEPT
-
现在仍然不能正常工作,外部流量可以到达 webserver,但是 webserver 并不知道如何将流量转发出去,有两种方式解决:
-
设置 webserver 的默认网关为 10.1.1.254
-
在转发机器上设置 SNAT
iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp --dport 80 -j SNAT --to 10.1.1.254
如何让外部访问 kubernetes 的 8080 端口
场景描述:为了安全考虑,非安全端口 8080 是 bind 到 localhost 的。那么如何设置 iptables 规则,让外部能访问 8080 端口呢。
分析:
-
设置 DNAT
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:8080
-
允许外部访问 localhost
sysctl -w net.ipv4.conf.all.route_localnet=1
该设置的解释: Redirect to localhost
(https://unix.stackexchange.com/questions/111433/iptables-redirect-outside-requests-to-127-0-0-1/112232#112232)
在 kubernetes 中的应用
为了支持集群的水平扩展、高可用性,kubernetes 抽象出了 Service 的概念。Service 是一组 pod 的抽象,service 和 pod 是通过 label 和 selector 来实现关联的。我们知道 pod 的 ip 地址会随着 pod 的销毁和重建而发生改变,即新 pod 的 ip 地址与旧 pod 的 ip 地址是不同的。而 k8s 在 pod 之上加了一层 service 的概念,service 创建的时候会被分配一个静态的 cluster ip。在 service 的整个生命周期中,service 的 ip 都不会改变。因此,服务发现这个棘手的问题被轻松地解决。
运行在每个 Node 上的 kube-proxy 进程是一个软件负载均衡器,它通过监控 etcd 中的 service 和 endpoint 资源,创建相应的 iptables 规则,根据 iptables 规则将对 service 的访问请求转发到后端的某个 pod 上,实现了服务的负载均衡和会话保持机制。
接下来我们看一个实际的例子:
首先创建一个三副本的 deployment,每个 pod 具有 label "name"= "nginx-79959",并且 nginx 是在 80 端口提供服务:
{
"kind": "Deployment"
"apiVersion": "extensions/v1beta1"
"metadata": {
"name": "nginx-79959"
"namespace": "default"
}
"spec": {
"replicas": 3
"selector": {
"matchLabels": {
"name": "nginx-79959"
}
}
"template": {
"metadata": {
"name": "nginx-79959"
"namespace": "default"
"labels": {
"name": "nginx-79959"
}
}
"spec": {
"containers": [
{
"name": "nginx"
"image": "hub.c.163.com/public/nginx:1.2.1"
}
]
"restartPolicy": "Always"
}
}
}
}
最终会得到三个 running 的 pod:
然后创建一个 service,service 的 selector 上上面 pod 的 label 是相同的,即 "name"= "nginx-79959",service 被分配了一个虚拟的 cluster ip,并且定义了转发规则,当访问 service 的 80 端口时,会转发到对应后端 pod 的 80 端口上去:
{
"kind": "Service"
"apiVersion": "v1"
"metadata": {
"name": "nginx"
"namespace": "default"
}
"spec": {
"ports": [
{
"protocol": "TCP"
"port": 80
"targetPort": 80
}
]
"selector": {
"name": "nginx-79959"
}
"clusterIP": "10.0.14.162"
"type": "ClusterIP"
"sessionAffinity": "None"
}
}
endpoint controller 通过监控 pod 和 service 资源,会创建跟 service 同名的 endpoint 资源,并且通过 service 的 selector 和 pod 的 label,负责将二者关联起来,将关联信息记录到 endpoint 资源中:
当上面创建的某个 pod 挂掉的时候,endpoint controller 会将对应的 pod 信息从上面的 endpoint 资源中删除。同理,当同样具有 "name"= "nginx-79959" lable 的 pod 创建出来并 running 的时候,endpoint 会将这个 pod 的信息更新到 endpoint 资源中去。因此,当访问 service 的时候,请求不会转发到已经 Failed 的后端 pod 上去。
接下来就是 kube-proxy 的工作了,它通过监控 endpoint 资源,创建 iptables DNAT 规则。
DNAT 是在NAT表的 PREROUTING 链上设置的:
iptables -t nat -L
跳转到 KUBE-SERVICES 链:
当目的 IP 是 10.0.14.162(即 service 的 ip),目的端口是 80 时,跳转到 KUBE-SVC-CCXTCUX4BWMIZHKW 链:
iptables 的 Round Robin 负载均衡,因为这个 service 后端有三个 pod,因此会等概率跳转到下面三条链中的一条:
DNAT,修改目的 ip 和目的端口为:10.173.32.10:80 或者 10.173.32.11:80 或者 10.173.32.8:80,其中这三个 ip 分别是三个后端 pod 的 ip 地址:
参考文献:
-
http://xstarcd.github.io/wiki/Linux/iptables_forward_internetshare.html
-
http://blog.csdn.net/zm_21/article/details/8508653
-
http://www.cnblogs.com/bangerlee/archive/2013/02/27/2935422.html
-
https://my.oschina.net/u/156249/blog/32238
-
http://blog.chinaunix.net/uid-13423994-id-3212414.html
-
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security_Guide/sect-Security_Guide-Firewalls-IPTables_and_Connection_Tracking.html
-
http://brokestream.com/iptables.html
-
http://bbs.chinaunix.net/thread-1926255-1-1.html
-
http://andys.org.uk/bits/2010/01/27/iptables-fun-with-mark/
-
http://lesca.me/archives/iptables-examples.html
以上由网易企业信息化服务提供商,湖南领先网络科技整理发布。
网易企业服务,是网易凭借其20年品牌优势与经验在企业邮箱的基础上,为进一步布局企业市场而打造的企业级产品矩阵,致力于提供一站式企业信息化解决方案。湖南领先网络科技是网易企业产品授权经销商,专业为企业提供网易企业邮箱、网易办公套件等一站式企业信息化专业解决方案。