kubernetes中的资源管理(浅谈Iptables及其在)

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 链,修改包的目的地址,通常是为了让外部访问内网中的服务

状态跟踪机制

(点击图片放大查看)

kubernetes中的资源管理(浅谈Iptables及其在)(1)

(点击图片放大查看)

常见应用场景

简单的 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:

kubernetes中的资源管理(浅谈Iptables及其在)(2)

然后创建一个 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 资源中:

kubernetes中的资源管理(浅谈Iptables及其在)(3)

当上面创建的某个 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 链:

kubernetes中的资源管理(浅谈Iptables及其在)(4)

当目的 IP 是 10.0.14.162(即 service 的 ip),目的端口是 80 时,跳转到 KUBE-SVC-CCXTCUX4BWMIZHKW 链:

kubernetes中的资源管理(浅谈Iptables及其在)(5)

iptables 的 Round Robin 负载均衡,因为这个 service 后端有三个 pod,因此会等概率跳转到下面三条链中的一条:

kubernetes中的资源管理(浅谈Iptables及其在)(6)

DNAT,修改目的 ip 和目的端口为:10.173.32.10:80 或者 10.173.32.11:80 或者 10.173.32.8:80,其中这三个 ip 分别是三个后端 pod 的 ip 地址:

kubernetes中的资源管理(浅谈Iptables及其在)(7)

参考文献:

  • 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年品牌优势与经验在企业邮箱的基础上,为进一步布局企业市场而打造的企业级产品矩阵,致力于提供一站式企业信息化解决方案。湖南领先网络科技是网易企业产品授权经销商,专业为企业提供网易企业邮箱、网易办公套件等一站式企业信息化专业解决方案。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页