Kubernetes: 使用 iptables 代替用户空间进行代理

创建于 2015-01-23  ·  187评论  ·  资料来源: kubernetes/kubernetes

昨天我在玩 iptables,我原型化(好吧,从谷歌命中复制并变异)一组 iptables 规则,这些规则基本上在没有用户空间帮助的情况下为我们完成所有代理。 这并不紧急,但我想在我丢失笔记之前将它们归档。

这具有额外的不错的副作用(据我所知),即保留源 IP 并进行大的网络简化。 现在 kube-proxy 只需要同步服务 -> iptables。 这具有与旧的 iptables 和内核不兼容的缺点。 我们之前遇到过这个问题 - 在某个时候我们需要决定我们关心的时间有多远。

这可能可以进一步优化,但在基本测试中,我看到粘性会话正在工作,如果我将该部分注释掉,我会看到~每个后端都有相同的概率。 我无法让确定性循环正常工作(使用 --nth 而不是 --probability),但如果我们愿意,我们可以回到那个问题。

这将使用下面列出的后端设置一个服务门户

iptables -t nat -N TESTSVC
iptables -t nat -F TESTSVC
iptables -t nat -N TESTSVC_A
iptables -t nat -F TESTSVC_A
iptables -t nat -N TESTSVC_B
iptables -t nat -F TESTSVC_B
iptables -t nat -N TESTSVC_C
iptables -t nat -F TESTSVC_C
iptables -t nat -A TESTSVC -m recent --name hostA --rcheck --seconds 1 --reap -j TESTSVC_A
iptables -t nat -A TESTSVC -m recent --name hostB --rcheck --seconds 1 --reap -j TESTSVC_B
iptables -t nat -A TESTSVC -m recent --name hostC --rcheck --seconds 1 --reap -j TESTSVC_C
iptables -t nat -A TESTSVC -m statistic --mode random --probability 0.333 -j TESTSVC_A
iptables -t nat -A TESTSVC -m statistic --mode random --probability 0.500 -j TESTSVC_B
iptables -t nat -A TESTSVC -m statistic --mode random --probability 1.000 -j TESTSVC_C

iptables -t nat -A TESTSVC_A -m recent --name hostA --set -j DNAT -p tcp --to-destination 10.244.4.6:9376
iptables -t nat -A TESTSVC_B -m recent --name hostB --set -j DNAT -p tcp --to-destination 10.244.1.15:9376
iptables -t nat -A TESTSVC_C -m recent --name hostC --set -j DNAT -p tcp --to-destination 10.244.4.7:9376

iptables -t nat -F KUBE-PORTALS-HOST
iptables -t nat -A KUBE-PORTALS-HOST -d 10.0.0.93/32 -m state --state NEW -p tcp -m tcp --dport 80 -j TESTSVC
iptables -t nat -F KUBE-PORTALS-CONTAINER
iptables -t nat -A KUBE-PORTALS-CONTAINER -d 10.0.0.93/32 -m state --state NEW -p tcp -m tcp --dport 80 -j TESTSVC
prioritawaiting-more-evidence release-note sinetwork siscalability

所有187条评论

凉爽的! 我认为我们绝对应该将其合并。另外,我看到代理在重负载下占用了大约 30% 的核心,我不得不相信 iptables 会给我们带来比这更好的性能。

我们必须优先考虑这一点——这几乎是对 kube-proxy 和
其所有测试。 它也有向后兼容的问题(不适用于
较旧的内核或较旧的 iptables 二进制文件)。

2015 年 1 月 26 日星期一上午 11:06,Brendan Burns通知@github.com
写道:

凉爽的! 我认为我们绝对应该将其合并。另外,
我看到代理在重负载下吃掉了大约 30% 的核心,我必须
相信iptables会给我们带来比这更好的性能。

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -71517501
.

也许将其作为并行选项实施并缓慢迁移有意义?

2015 年 1 月 26 日星期一下午 12:01,Tim Hockin通知@ github.com
写道:

我们必须优先考虑这一点——这几乎是对 kube-proxy 和
其所有测试。 它也有向后兼容的问题(不适用于
较旧的内核或较旧的 iptables 二进制文件)。

2015 年 1 月 26 日星期一上午 11:06,Brendan Burns通知@github.com
写道:

凉爽的! 我认为我们绝对应该将其合并。另外
笔记,
我看到代理在重负载下吃掉了大约 30% 的核心,我必须
相信iptables会给我们带来比这更好的性能。

直接回复此邮件或在 GitHub 上查看
<
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -71517501

.


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -71527216
.

我试图哄其他不太了解此代码的人学习它
并接受它。 我真的_想_解决它,但如果
其他人学习了这个空间(不是你!:)

也就是说,您还发送了有关大量 P1 列表的(好的)电子邮件 - 而我
不要认为这是在那个名单上。

2015 年 1 月 26 日星期一下午 1:06,Brendan Burns通知@github.com
写道:

也许将其作为并行选项实施并缓慢迁移使
感觉?

2015 年 1 月 26 日星期一下午 12:01,Tim Hockin通知@ github.com
写道:

我们必须优先考虑这一点——这几乎是对 kube-proxy 的完全重写

其所有测试。 它也有向后兼容的问题(不起作用

较旧的内核或较旧的 iptables 二进制文件)。

2015 年 1 月 26 日星期一上午 11:06,Brendan Burns <
通知@github.com>
写道:

凉爽的! 我认为我们绝对应该将其合并。另外
笔记,
我看到代理在重负载下吃掉了大约 30% 的核心,我必须
相信iptables会给我们带来比这更好的性能。

直接回复此邮件或在 GitHub 上查看
<

https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -71517501

.

直接回复此邮件或在 GitHub 上查看
<
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment-71527216>

.

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -71538256
.

这是P2吗? 现在是否值得将其设为 P3?

我希望让它发挥作用,但我们可能还会降级它

2015 年 2 月 11 日星期三下午 2:49,Satnam Singh通知@ github.com
写道:

这是P2吗? 现在是否值得将其设为 P3?

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -73982161
.

难道“希望”不等于我们可以达到的 P3 吗?

来自与@thockin 的讨论:这是支持服务端口范围的要求,1.0 不需要,但我们希望最终支持。

@thockin “这具有与旧的 iptables 和内核不兼容的缺点。” 内核必须有多“新”?

不是太新,但我们有一些用户真的想要从 2012 年到 iptables
工作。

在星期一,2015年2月23日2:44 PM,Sidharta Seethana < [email protected]

写道:

@thockin https://github.com/thockin “这有一个缺点是不被
与旧的 iptables 和内核兼容。”内核如何“新”
不得不?

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -75654187
.

@thockin谢谢。 例如,我们正在使用/测试 RHEL/CentOS 6 - 所以如果我们对最近的 3.x 内核没有严格的依赖,那就太好了。

@pweil-我们前几天讨论过这个
2015 年 2 月 23 日星期一晚上 11:40 Sidharta Seethana [email protected]
写道:

@thockin https://github.com/thockin谢谢。 我们正在使用/测试
例如 RHEL/CentOS 6 - 所以如果我们没有硬
依赖于最近的 3.x 内核。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -75698480
.

好吧,您确实需要 Docker 才能运行,而在某些时候我们必须将其切断。
back-rev iptables 支持不会阻止我(最终)制作
这种变化,它会刺痛一些人。

2015 年 2 月 23 日星期一晚上 8:40,Sidharta Seethana < [email protected]

写道:

@thockin https://github.com/thockin谢谢。 我们正在使用/测试
例如 RHEL/CentOS 6 - 所以如果我们没有硬
依赖于最近的 3.x 内核。

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -75698480
.

@thockin的帮助下,我们对 udp 进行了同样的尝试。

我们创建了一个带有 3 个 sky-dns 复制控制器的 GCE Kubernetes 集群。
在 kubernetes-master 上,我们在 iptables 中设置了以下内容:
dns 服务 ip 为 10.0.0.10,运行 dns 的 pod 端点为 10.244.0.5:53、10.244.3.6:53、10.244.0.6:53

iptables -t nat -N TESTSVC
iptables -t nat -F TESTSVC
iptables -t nat -N TESTSVC_A
iptables -t nat -F TESTSVC_A
iptables -t nat -N TESTSVC_B
iptables -t nat -F TESTSVC_B
iptables -t nat -N TESTSVC_C
iptables -t nat -F TESTSVC_C
iptables -t nat -N KUBE-PORTALS-HOST
iptables -t nat -F KUBE-PORTALS-HOST

iptables -t nat -A TESTSVC -m 最近 --name hostA --rcheck --seconds 1 --reap -j TESTSVC_A
iptables -t nat -A TESTSVC -m 最近 --name hostB --rcheck --seconds 1 --reap -j TESTSVC_B
iptables -t nat -A TESTSVC -m 最近 --name hostC --rcheck --seconds 1 --reap -j TESTSVC_C

iptables -t nat -A TESTSVC -m statistic --mode random --probability 0.333 -j TESTSVC_A
iptables -t nat -A TESTSVC -m statistic --mode random --probability 0.5 -j TESTSVC_B
iptables -t nat -A TESTSVC -m statistic --mode random --probability 1.000 -j TESTSVC_C

iptables -t nat -A TESTSVC_A -m 最近的 --name hostA --set -j DNAT -p udp --to-destination 10.244.0.5:53
iptables -t nat -A TESTSVC_B -m 最近 --name hostB --set -j DNAT -p udp --to-destination 10.244.3.6:53
iptables -t nat -A TESTSVC_C -m 最近的 --name hostC --set -j DNAT -p udp --to-destination 10.244.0.6:53
iptables -t nat -A KUBE-PORTALS-HOST -d 10.0.0.10/32 -p udp -m udp --dport 53 -j TESTSVC
iptables -t nat -A 输出 -j KUBE-PORTALS-HOST


kubernetes-master>nslookup kubernetes.default.kuberenetes.local 10.0.0.10

我们得到了回复!

好东西! 仅供参考(从我们的面对面对话中确认),通常运行多个并发 iptables 命令是不安全的(不同的链听起来可能没问题)。 iptables 是 libiptc 的包装器,请参阅对 iptc_commit 的评论: http ://www.tldp.org/HOWTO/Querying-libiptc-HOWTO/mfunction.html

这显然是在 2013 年修复的,但也许只有当你通过 --wait (?): http://git.netfilter.org/iptables/commit/?id=93587a04d0f2511e108bbc4d87a8b9d28a5c5dd8

造成这种情况的根本原因是 iptables 有效地调用了 iptables-save / iptables-restore(至少每条链); 我见过很多代码因此调用 iptables-save 和 iptables-restore 而不是通过添加和删除来做事。 我什至可能有一些代码要做,如果有帮助,我可以挖掘。

令人难以置信的是,没有办法进行 CAS 或 LL/SC 类型的操作。

我们应该添加对 --wait 的支持,尽管 GCE 的
debian-backports 没有它。

也许我们应该在我们的代码中做我们自己的锁定以至少防止我们
从踩到我们自己。

2015 年 2 月 26 日星期四下午 1:56,贾斯汀圣巴巴拉 <
通知@github.com> 写道:

好东西! 仅供参考(从我们面对面的谈话中确认),
通常运行多个并发 iptables 命令是不安全的
(不同的链听起来可能没问题)。 iptables 是一个包装
libiptc,并查看关于 iptc_commit 的评论:
http://www.tldp.org/HOWTO/Querying-libiptc-HOWTO/mfunction.html

这显然是在 2013 年修复的,但也许只有当你通过 --wait (?)
http://git.netfilter.org/iptables/commit/?id=93587a04d0f2511e108bbc4d87a8b9d28a5c5dd8

造成这种情况的根本原因是 iptables 有效地调用了 iptables-save /
iptables-restore(至少每个链); 我看过很多代码
因此调用 iptables-save & iptables-restore 而不是做事
通过添加和删除。 我什至可能有一些代码可以挖掘
如果有帮助的话。

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -76282629
.

如果在创建一堆规则的过程中失败会发生什么?

公平的问题 - 我们可能应该认真思考这意味着什么
在这中间遇到一个错误

2015 年 2 月 26 日星期四晚上 8:47,Brian Grant通知@github.com
写道:

在创建一堆失败的情况下会发生什么
规则?

直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -76331174
.

@thockin今天来自 irc:

net.ipv4.conf.all.route_localnet允许 127.0.0.1 成为DNAT规则的目标。 从文档

route_localnet - 布尔值

不要将环回地址视为火星源或目标
路由时。 这样就可以将 127/8 用于本地路由目的。
默认错误

我们会将其集成到 kubelet 中,还是将其保存在单独的守护进程中? Kubelet 已经监视服务以填充环境变量。

我想把它作为一个单独的二进制文件。 你是有原因的
可能想在 k8s 之外的其他机器(例如宠物虚拟机)上运行它
集群以获得对 k8s 服务的访问。

--布兰登

2015 年 3 月 13 日星期五上午 11:37,Brian Grant通知@github.com
写道:

我们会将其集成到 kubelet 中,还是将其保存在单独的守护进程中?
Kubelet 已经监视服务以填充环境变量。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79230747
.

赶上。 关于在失败的情况下会发生什么(相信我,会有很多失败),我是反熵方法的忠实粉丝 - 将所需状态存储在某处,并定期调和所需状态和实际状态(通过改变实际状态)。 在这种情况下,也许很简单:

而(真){
实际状态 = iptablesSave()
if actualState != desiredState { iptablesRestore(desiredState))
sleep_a_while()
}

100% 同意这是处理编写 iptables 失败的正确方法
规则。

2015 年 3 月 13 日星期五下午 1:16,Quinton Hoole通知@ github.com
写道:

赶上。 关于在失败的情况下会发生什么(其中
会有很多,相信我),我是反熵方法的忠实粉丝

  • 在某处存储所需的状态,并定期协调所需的和
    实际状态(通过改变实际状态)。 在这种情况下,也许很简单:

而(真){
实际状态 = iptablesSave()
if actualState != desiredState { iptablesRestore(desiredState))
sleep_a_while()
}


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79336296
.

现在或多或少就是这样,不是吗? 对于每个预期规则,
检查它是否存在,如果不存在,则创建它。

2015 年 3 月 13 日星期五下午 2:02,Brendan Burns通知@github.com
写道:

100% 同意这是处理编写 iptables 失败的正确方法
规则。

2015 年 3 月 13 日星期五下午 1:16,Quinton Hoole通知@ github.com
写道:

赶上。 关于在失败的情况下会发生什么(其中
会有很多,相信我),我是反熵的忠实粉丝
方法

  • 在某处存储所需的状态,并定期协调所需的和
    实际状态(通过改变实际状态)。 在这种情况下,也许就这么简单
    作为:

而(真){
实际状态 = iptablesSave()
if actualState != desiredState { iptablesRestore(desiredState))
sleep_a_while()
}


直接回复此邮件或在 GitHub 上查看
<
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79336296

.


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79392626
.

我同意在一个单独的二进制文件中有实用程序,但也许我们将它链接到
kubelet(与 cAdvisor 相同的方式)并使其成为独立的
同时。

2015 年 3 月 13 日星期五下午 12:03,Brendan Burns通知@github.com
写道:

我想把它作为一个单独的二进制文件。 你是有原因的
可能想在 k8s 之外的其他机器(例如宠物虚拟机)上运行它
集群以获得对 k8s 服务的访问。

--布兰登

2015 年 3 月 13 日星期五上午 11:37,Brian Grant通知@github.com
写道:

我们会将其集成到 kubelet 中,还是将其保存在单独的守护进程中?
Kubelet 已经监视服务以填充环境变量。


直接回复此邮件或在 GitHub 上查看
<
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79230747

.


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -79257059
.

我很想知道 Kubernetes-Mesos 的人对节点组件是否应该更加集成或模块化有什么看法。 @jdef?

[[编辑]] 我真的很喜欢 k8s 组件的模块化,例如运行一个独立于 kubelet 进程的代理进程。 如果代理因任何原因失败,它不会关闭 kubelet。 这非常棒,因为 Mesos 执行器现在没有非常优雅的故障转移模型——而 kubernetes-mesos 框架的执行器是 kubelet/执行器混合体。 该模型还允许我在 mesos 主节点上运行代理服务,并将其用作外部客户端的循环平衡器(如我们提交的入门指南中所示)。

在打包/发送二进制文件方面,我认为将功能打包在一起非常有用,就像在 hyperkube 中一样。 我还考虑过如何将 kubernetes-mesos 框架组件打包到最小的Docker 容器中。 iptables 具有外部库依赖项,这使事情变得复杂。 因此,一个不错的折衷方案可能是将 k8sm 框架作为包含单个 hyperkube 映像的 Docker 提供 - 但是当该框架执行并开始在整个集群中分发 kubelet 执行器时,它基本上会提供一个可以变形为 kubelet 的 hyperkube 映像 - executor 或 proxy - 每个进程都可以直接在主机上运行。 这基本上解决了 iptables-{binaries,libraries}-in-Docker 依赖问题。

+1 用于模块化功能,+1 用于单个二进制图像

@thockin 回复:反熵:是的。 我看到 proxier.SyncLoop() 这样做。 在哪种情况下, @bgrant0607在 2 月 26 日提出的问题的答案不是可以忽略错误并将在 SyncLoop() 的下一次迭代中修复(当前为 1 分钟)? 或者也许我错过了什么?

@thockin

  1. 我们是担心网络流量的黑洞还是服务/pod 作者需要处理的事情?

使用用户空间代理
假设虚拟 IP 10.0.0.11 有 3 个端点,例如 10.240.1.1、10.240.1.2、10.240.1.3
对于用户空间代理,如果一个端点说 10.240.1.1 不起作用,代理将意识到未与 10.240.1.1 建立 tcp 连接,并且它可以回退到其他 2 个端点之一。

使用 iptables
当我们使用 iptables 时,没有回退机制,因为 kubernetes 没有意识到端点是否工作。
如果我们对端点进行某种健康检查,我们可以缓解这种情况,这将删除无响应的端点。

或者,担心无响应的端点不是 kubernetes 系统的责任,而是 pod 作者的责任?

用户可以设置就绪探针,由 Kubelet 执行。 探测失败将导致端点控制器从端点列表中删除端点。 然后服务代理应该从目标集中删除端点。

我一直在为 GSoC 研究这个,我想知道:

那么理想情况下,我们会检测 iptables 是否足够新以使用,否则继续使用 kube-proxy?

https://github.com/GoogleCloudPlatform/kubernetes/issues/5419听起来这将是理想的方法; kubelet 决定是使用 ip-tables 还是启动 kube-proxy。

我也有点迟到 GSoC(在春假....),所以我也想知道我是否仍然可以在明天/今天晚些时候提交 GSoC 提案(当然除了第 27 个截止日期,是这仍然开放)?

@BenTheElder是的,您必须在周五之前提交提案。 还有一个人可能对这个话题感兴趣,但目前还没有具体的建议。

我并不担心 2012 年之前的内核,就像我担心完全没有 iptables 的操作系统一样,尽管它们已经在某种程度上被破坏了。

@bgrant0607谢谢!
我想我可以选择这个问题。 看起来很有趣。

就绪探针对于应用程序启动很有效,但我不确定就绪是否适合减轻应用程序故障。 在 pod 失败时,信号必须从应用程序 -> kubelet -> apiserver -> endpoints_controller -> apiserver -> kube-proxy 传递。 我有兴趣了解应用程序故障和从 kube-proxy 轮换中删除端点之间的延迟。 在此期间,请求将被代理到无响应的端点。

连接失败时重试是一种常见的策略,也是许多流行负载均衡器(例如 haproxy、AWS ELB)的相当有用的特性,由当前的 kube-proxy 实现处理。 这个职责是否应该迁移到外部LB? 集群内流量呢?

另一个想法是,对于 iptables,我们可能会遇到重新配置与实际 LB 时优雅地连接耗尽的问题。

迈克提出了很好的观点。

2015 年 3 月 23 日星期一晚上 11:00,Mike Danese通知@github.com
写道:

另一个想法,我们可能会遇到优雅连接的问题
在重新配置与实际 LB 时消耗。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -85354865
.

我一直在阅读 kube-proxy 和 proxy pkg 的源代码; 当前版本中是否尚未使用 iptables?

在这方面究竟需要做什么? 从当前的主源来看,iptables 似乎已经在代理中广泛使用。

@mikedanese @thockin Readiness 对计划中断最有用。 计划外中断总是会导致一些可观察到的错误。 相对于更新延迟,轮询间隔通常应该较长,但如果通过 apiserver 和 etcd 的延迟太长和/或路径不够可靠。

@BenTheElder现有规则通过代理路由流量。 这里的想法是使用规则绕过代理。

@bgrant0607谢谢,现在完全有道理了。 又通读了源代码和设计文档,我几乎完成了提案草案的编写。

GSoC 提案草案: https ://gist.github.com/BenTheElder/ac61900595a7ea9ea9b5

我特别感谢对日程安排部分的反馈。 我不太确定。
我应该早点完成我很想解决其他一些(较小的?)未采取的 GSoC 问题,例如:
https://github.com/GoogleCloudPlatform/kubernetes/issues/1651。

再次感谢,Kubernetes 为最友好的团队分担了蛋糕。

我只想说,我很高兴地说我的提议已被接受,我将在整个夏天进行这项工作。 :笑脸:

我很兴奋。 不幸的是,我现在正处于决赛阶段,但从本周末的某个时候开始,我应该做更多的工作并努力,最有可能从获取https://github.com/GoogleCloudPlatform/kubernetes/pull/7032开始完成的。

@thockin @brendanburns任何人都可以权衡我们是否要与用户空间代理并行执行此操作,或者迁移到重新实现将如何工作?

看起来我们已经更喜欢 iptables >= 1.4.11(2011 年 5 月 26 日发布)。

// Executes the rule check without using the "-C" flag, instead parsing iptables-save.
// Present for compatibility with <1.4.11 versions of iptables.  This is full
// of hack and half-measures.  We should nix this ASAP.
func (runner *runner) checkRuleWithoutCheck(table Table, chain Chain, args ...string) (bool, error) {

来源: https :

我们真的看到比这更老的主机吗?

一种方法显然是在运行时检测我们正在运行的 iptables 版本,并做我们可以给出版本的“最好的事情”,例如:

如果(旧版本){
加载用户空间代理模块
}
别的 {
加载 iptables 代理模块
}

我警告不要在上面的 if 语句中有太多的分支(最好只有 2 个),并尽可能避免在代码中的多个地方使用这种 if 语句。

我没有详细筛选代码以弄清楚上述方法的可行性。

此外,是否所有节点都需要实施相同的策略(用户空间与 iptables 代理),还是每个节点都可以独立决定?

如果每个节点独立决定,我们可能会增加与上述if语句中分支数量的平方成正比的测试表面积(即source_mode x dest_mode),但如果我们可以将模式数量保持为2,我认为就可以了.

哦,不幸的是,您对我们是否看到旧节点的问题的答案是“是”。

在一个单独的问题中有很多关于上面的讨论。,我会尽力为你挖掘出来。

@quinton-hoole 谢谢!

此外,我相当确定我们可以在一个节点上运行用户空间,而在另一个节点上运行 iptables。

除了当我们没有 -C 但具有 -C 的节点应该能够运行纯 iptables 版本(我认为)时的 hack 之外,模式的数量应该只是 2。

是的,#7528 讨论内核版本等。

谢谢。
我在查找 kubernetes 的要求时没有看到这一点。 我发现的唯一要求是在讨论我们如何假设唯一 ip 的网络文档中。

一旦我们更好地了解它们是什么,我们可能应该为需求编写一些文档。

我已经开始在这里进行黑客攻击: https :

具体来说,我已将用户空间实现移到此处的接口后面:
https://github.com/BenTheElder/kubernetes/commit/4e5d24bb74aca43b0dd37cf5cfee8a34f8eff2bf

我现在不确定实现选择是否应该在 cmd/kube-proxy 或 pkg/proxy 中,所以我可以删除它并让 kube-proxy 选择实现。

编辑:回想起来,我认为从 kube-proxy 中选择实现可能更有意义。

@BenTheElder我用 Calico 测试了 Tim 的规则,它们运行良好。 我们在过滤器表中完成所有工作,因此此处的 DNAT 规则已经设置了适当的 src IP。

更一般地说,如果 Kubernetes 也将在那里插入规则,那么最好进行讨论以定义网络插件如何安全地更改 iptables。 不想践踏(或被践踏)Kubernetes 规则,如果他们改变了道路。

@对称是的。 我还不确定插件部分,但这似乎非常重要。

这个周末我可能会有点忙,但周一我应该开始全职工作,为 GSoC 实现第一次迭代。
我想在这样做时牢记这一点,但在查看网络插件 api 后,我不确定最干净的处理方法是什么。

你知道你希望它看起来像什么/它应该如何工作吗?

FWIW,我做了一些对我们有用的事情,因为 kube-proxy 几乎没有响应。 它在这里: https :

我之前没有看到这个线程,但我最终得到了一些接近的东西,除了我在随机统计匹配权重方面犯了一个错误:-)

我还想分享一下,我们很快就达到了 nf_conntrack_max。 应该会增加吧。

# cat /etc/sysctl.d/nf_conntrack.conf 
net.netfilter.nf_conntrack_max = 1000000
net.nf_conntrack_max           = 1000000

我可能不明白iptables所有需要,但为什么不使用IPVS呢?
与 iptables 相比,它似乎与代理更相关...
这是一个简单的 go 实现: https :
为了完成#561,还有ktcpvs项目。

IPVS 似乎也是对 netfilter(如 iptables)的抽象。 我们可以通过使用 iptables 与现有代码共享一些功能; 和 iptables 似乎是管理 netfilter 的更灵活/通用的解决方案。

至于#561 和 ktcpvs:自 2004 年以来 ktcpvs 似乎没有任何发展,并且似乎没有用户想要的功能,例如 URL 重写。 无论如何,#561 正在寻找可与可插拔平衡器一起使用的通用解决方案。

旁注:那个 go 项目似乎没有许可证。

iptables 将“有一天”被弃用,取而代之的是 nftables( nft cli)。
同样使用 iptables CLI 创建规则似乎不是很健壮......

快速搜索找到另一个 MIT 项目: https :
但是创建一个简单的工作似乎真的很容易,因为所有复杂性都已经在内核代码中防弹了。

我怀疑 iptables 很快就会从任何主要发行版中删除,而 iptables CLI 专门用于创建和管理 netfilter 的规则......?

像链接的一个不完整的 cgo 包装器似乎比炮击iptablesiptables-restore安全得多,而且我们已经需要 iptables 用于其他规则(例如 nodeports)和iptables-restore我们可以通过一些原子性进行批量更新。

IPVS 似乎进一步设计为用于与“真实”服务器分开的负载平衡主机。
表明这是唯一受支持的用法:

2.2. 问题:您需要一个外部客户端(director 和 realservers 无法访问虚拟服务)

要设置和测试/运行 LVS,您至少需要 3 台机器:client、director、realserver(s)。

从外部看,LVS 就像一台机器。 客户端不能是 LVS 中的一台机器(director 或 realserver)。 你需要一个外部客户。 如果您尝试从 LVS 中的任何机器访问 LVS 控制的服务(例如 http、smtp、telnet); 来自 Director 的访问将挂起,来自 realserver 的访问将连接到本地服务,绕过 LVS。

看起来IPVS/LVS 也增加了一些额外的要求,比如心跳守护程序和额外的监控进程。 我们已经在 kubernetes 中处理端点信息和 Pod 健康监控等。

+1 为 iptables 方法。 我们在 Calico 中广泛使用 iptables,它们已被证明是健壮的,并且它们的性能和扩展性都很好(假设您设计的规则很好)。 @BenTheElder ,如果您在任何 iptables 工作方面需要任何帮助,请告诉我们,因为我们很乐意提供帮助。

+1 用于 iptables 和 iptables-restore,这是一种不那么笨拙的方法
比 IPVS/LVS 要求更少的系统要求(心跳守护进程,
等等。)

2015 年 6 月 13 日星期六上午 11:27,Alex Pollitt通知@ github.com
写道:

+1 为 iptables 方法。 我们在 Calico 中广泛使用 iptables 和
它们已被证明是强大的,并且它们的性能和扩展性都很好(假设您
设计好你的规则)。 @BenTheElder https://github.com/BenTheElder
如果您需要任何有关 iptables 工作的帮助,请让
我们知道,因为我们很乐意参与。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -111719474
.

谢谢亚历克斯,我会告诉你的。

如果有人有时间,我可以对当前的实现 (https://github.com/GoogleCloudPlatform/kubernetes/pull/9210) 使用一些反馈/输入。

它大部分是完整的,目前已与上游主服务器保持同步,我需要完成编写将生成的规则与iptables-save并恢复计数器等的代码,但规则已生成并且(大部分)工作,几乎遵循此处 OP 中概述的规则,最大的变化只是链名称,这是自动生成 iptables 将接受的名称所必需的。

这里报告了一个边缘情况: https :

我与@MikaelCluseau@Symmetric有一些很好的反馈和讨论,特别是关于重新设计来处理这个和其他事情(再次感谢!); 但我们可以在规则设计上使用更多的输入。 如果其他人有时间看一看,那将不胜感激,因为我不确定最好的路线是什么,我想避免在没有更多输入的情况下进行任何重大更改。

PR 本身很大,但相关的规则生成都在pkg/proxy/proxieriptables.go syncProxyRules()中: https :

可以看到现有的讨论(当然是这里)以及 PR 评论和https://github.com/BenTheElder/kubernetes/issues/3以及更多信息,访问

另一个需要输入的问题:

在当前代码中,仍然包含 kube-proxy,以仅处理 nodePort 情况。 我认为在这种情况下我们也可以取消 kube-proxy,并在Ben 的 PR上提出了一些简单的 iptables 规则来这样做。

但是这些规则仍然掩盖了任何外部 LB 的源 IP,因此它们并不理想。 问题是,如果我们只是在 LB 到达节点时从 LB 传输 DNAT 流量,那么响应数据包可能来自不同的节点,因此我认为 LB 无法将响应与原始 TCP 会话相关联. 这种担忧有效吗? 如果我们不必担心这个,实现会更简单。

我怀疑我们可以做一些神奇的事情来让 HTTP 代理满意,但我看不出有什么方法可以在 L4 上做到这一点。

我正在尝试从你的 PR 中使用黑魔法,但它没有为我生成任何东西,似乎规则开始通过调用 iptables 来生成,然后生成一个 iptables-restore 文件。

生成的文件的标题部分有一个未命中,通常是那些已填充 iptables 调用的文件,日志中有相关部分:

I0807 11:41:24.560063 8369 iptables.go:327] 运行 iptables -N [KUBE-PORTALS-CONTAINER -t nat]
I0807 11:41:24.562361 8369 iptables.go:327] 运行 iptables -C [PREROUTING -t nat -m comment --comment handle ClusterIPs; 注意:这必须在 NodePort 规则之前 -j KUBE-PORTALS-CONTAINER]
I0807 11:41:24.563469 8369 iptables.go:327] 运行 iptables -N [KUBE-PORTALS-HOST -t nat]
I0807 11:41:24.565452 8369 iptables.go:327] 运行 iptables -C [OUTPUT -t nat -m comment --comment handle ClusterIPs; 注意:这必须在 NodePort 规则之前 -j KUBE-PORTALS-HOST]
I0807 11:41:24.566552 8369 iptables.go:327] 运行 iptables -N [KUBE-NODEPORT-CONTAINER -t nat]
I0807 11:41:24.568363 8369 iptables.go:327] 运行 iptables -C [PREROUTING -t nat -m addrtype --dst-type LOCAL -m comment --comment 处理服务 NodePorts; 注意:这必须是链中的最后一条规则 -j KUBE-NODEPORT-CONTAINER]
I0807 11:41:24.569564 8369 iptables.go:327] 运行 iptables -N [KUBE-NODEPORT-HOST -t nat]
I0807 11:41:24.571458 8369 iptables.go:327] 运行 iptables -C [OUTPUT -t nat -m addrtype --dst-type LOCAL -m comment --comment 处理服务 NodePorts; 注意:这必须是链中的最后一条规则 -j KUBE-NODEPORT-HOST]
I0807 11:41:24.573392 8369 iptables.go:327] 运行 iptables -C [POSTROUTING -t nat -m comment --comment 处理连接到 self -s 10.240.240.78/32 -d 10.240.240.78/32 -d 10.2478SQUES 340 的 Pod ]
I0807 11:41:24.574447 8369 proxier.go:349] 同步 iptables 规则。
I0807 11:41:24.575592 8369 proxier.go:399] 链:PREROUTING,规则::PREROUTING ACCEPT [0:0]
I0807 11:41:24.575615 8369 proxier.go:401] 规则:-A PREROUTING -m comment --comment “处理 ClusterIP;注意:这必须在 NodePort 规则之前” -j KUBE-PORTALS-CONTAINER
I0807 11:41:24.575625 8369 proxier.go:401] 规则:-A PREROUTING -m addrtype --dst-type LOCAL -m comment --comment “处理服务节点端口;注意:这必须是链中的最后一条规则” -j KUBE-节点端口-容器
I0807 11:41:24.575633 8369 proxier.go:399] 链:输入,规则::输入接受 [0:0]
I0807 11:41:24.575646 8369 proxier.go:399] 链:输出,规则::输出接受 [0:0]
I0807 11:41:24.575658 8369 proxier.go:401] 规则:-A OUTPUT -m 评论 --comment “处理 ClusterIP;注意:这必须在 NodePort 规则之前” -j KUBE-PORTALS-HOST
I0807 11:41:24.575670 8369 proxier.go:401] 规则:-A OUTPUT -m addrtype --dst-type LOCAL -m comment --comment “处理服务 NodePorts;注意:这必须是链中的最后一条规则” -j KUBE-节点端口-主机
I0807 11:41:24.575683 8369 proxier.go:399] 链:POSTROUTING,规则::POSTROUTING ACCEPT [0:0]
I0807 11:41:24.575691 8369 proxier.go:401] 规则:-A POSTROUTING ! -d 10.0.0.0/8 -o eth0 -j 伪装
I0807 11:41:24.575699 8369 proxier.go:401] 规则:-A POSTROUTING -s 10.240.240.78/32 -d 10.240.240.78/32 -m comment --comment “处理连接到 selfADE 的 pod
I0807 11:41:24.575709 8369 proxier.go:399] 链:KUBE-NODEPORT-CONTAINER,规则::KUBE-NODEPORT-CONTAINER - [0:0]
I0807 11:41:24.575720 8369 proxier.go:399] 链:KUBE-NODEPORT-HOST,规则::KUBE-NODEPORT-HOST - [0:0]
I0807 11:41:24.575729 8369 proxier.go:399] 链:KUBE-PORTALS-CONTAINER,规则::KUBE-PORTALS-CONTAINER - [0:0]
I0807 11:41:24.575740 8369 proxier.go:399] 链:KUBE-PORTALS-HOST,规则::KUBE-PORTALS-HOST - [0:0]
I0807 11:41:24.581897 8369 proxier.go:603] 同步规则::KUBE-PORTALS-HOST - [0:0]
:KUBE-PORTALS-容器 - [0:0]
:KUBE-节点端口-主机 - [0:0]
:KUBE-节点端口-容器 - [0:0]
:KUBE-SVC-VO8JL93ZeRSf8cnsLpl - [0:0]
:KUBE-SVC-L26cB3JYuxdW5TF84ct - [0:0]
:KUBE-SVC-j2SF8q3nUajS8vOx2qL - [0:0]
:KUBE-SVC-shln2urO8W1aBiB2bWJ - [0:0]
:KUBE-SVC-8jQ3IvijvhJ4ppFj3Ui - [0:0]
[...截图...]

将 iptable-save 与详细模式下产生的结果合并可以导入并做一些好事。

@bnprss感谢您的报告,最近有一些未经测试的更改,包括在审查过程的一些重写期间使用临时文件和使用iptables-restore的“-T 表”标志。 一旦我知道是什么导致了回归,我就会进行修复。

@bnprss就像你说的表头丢失(“*nat”应该是第一行),它被错误地删除了,把它放回去之后似乎又正常工作了,似乎没有其他错误(不包括:https:/ /github.com/BenTheElder/kubernetes/issues/3)。 再次感谢,抱歉。 我已经推动了修复。

干得好,规则正在加载,似乎从内部工作,但外部负载均衡器没有运气,外部没有通信给出答案。

呵呵。 你能转到 PR 并提供更多细节吗? 迄今为止
它运行良好,但我不会在本地测试之外部署自己,我
不要认为其他任何测试人员都在使用外部负载平衡器。
2015 年 8 月 7 日下午 1:29,“bnprss”通知@github.com 写道:

干得好,规则正在加载,似乎从内部起作用,但没有运气
与 externalloadbalancer 没有来自外部的通信给出答案。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -128772763
.

是的,对于细节,我将进行进一步的查询,并会在 PR 上生成一些日志或线索,但不会在明天之前,我希望在可能破坏某些东西之前运行一些好的备份工作。

你能计算没有分隔符“-_”的规则的标记吗?

@bnprss ,太好了。
为服务生成的规则链是服务端口/端点的哈希,然后是 base64 url​​ 编码和截断。 KUBE-SVC-. 代码在这里: https :
我们选择这种方式来生成满足 iptables 中字符限制的有效链名称,同时仍然具有确定性。
所以应该可以在外部复制。
如果您的意思是,我们可以停止使用分隔符吗,我们可能可以,但是“_”来自一些编码的散列,而“-”都只是遵循现有用户空间代理的规则名称中的模式。
如果有必要,我们可能可以使用其他东西而不会太麻烦。

我没问题,这真的是化妆品! :)
但这与我之前看到的不同:
gce lb 规则:a07f76b3b2ec311e59e2642010af0479
gce固件规则:k8s-fw-a7ecad94f3ba511e59e2642010af0479
gce 路由规则:default-route-6973e029b504a0e8
gce 到节点的路由:obfuscated_cluster_node-43506797-2eb2-11e5-9e26-42010af04793

这个不错:
KUBE-SVC-6ADi2TVfn7mFPvBjC56
那些很有趣:
KUBE-SVC-zU6ParcQ-UfW_LdRDUc
KUBE-SVC-y--z1xTUpHPT6sgAUCC

是的,我也不完全是他们的粉丝,我们也许可以更改哈希
编码。

2015 年 8 月 7 日星期五下午 2:16,bnprss [email protected]写道:

我没问题,这真的是化妆品! :)
但这与我之前看到的不同:
gce lb 规则:a07f76b3b2ec311e59e2642010af0479
gce固件规则:k8s-fw-a7ecad94f3ba511e59e2642010af0479
gce 路由规则:default-route-6973e029b504a0e8
gce 路由到节点:
obfuscated_cluster_node-43506797-2eb2-11e5-9e26-42010af04793

这个不错:
KUBE-SVC-6ADi2TVfn7mFPvBjC56
那些很有趣:
KUBE-SVC-zU6ParcQ-UfW_LdRDUc
KUBE-SVC-y--z1xTUpHPT6sgAUCC


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -128785914
.

是的,可以只使用 SHA 的截断部分,git 可以,docker 也可以,并且似乎是对 kube 实体的其他引用的方式。 如果生成的哈希 base64 发生冲突,将无济于事。 ;)
我想@thockin可以

我更关心 iptables 中的有效字符,我很难找到一个好的参考。 我很快就会进一步研究这个问题。

2015 年 8 月 7 日星期五下午 2:29,bnprss [email protected]写道:

是的,可以只使用 SHA 的截断部分,git 可以
那个,docker 也是,似乎是另一个引用 kube 的方式
实体被制作。 如果生成的哈希 base64 发生冲突,则不会
帮助。 ;)
我想@thockin https://github.com/thockin可以就此提出建议。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -128788454
.

@bnprss仅供参考,PR 非常不稳定并且正在重做,根据 thockin,我们现在正在修剪 NodePort 等,并专注于获得一个更简单、更干净的支持门户的版本,然后恢复到完全相同的状态。

我_不_尝试立即运行它,但希望它很快就会恢复。 将 PR 分解为一些较小的相关内容,然后立即使用 iptables-proxy 内容推送一个干净的 PR。

对于那些在家里玩的人,我相信我们可以全力以赴
平价,但分阶段审查会容易得多:)

2015 年 8 月 7 日星期五晚上 9:35,Benjamin Elder通知@github.com
写道:

我对上述评论的回复,也很快被压扁了:

在 IRC 中讨论:

  • 仍然需要处理计数器,但想要继续解析
    util/iptables 包中的状态。
  • 仍然需要散列或类似的方法来处理链长度限制

否则似乎是一个非常干净的简化,将在之后实施
还有一些讨论。


直接回复此邮件或在 GitHub 上查看
https://github.com/GoogleCloudPlatform/kubernetes/issues/3760#issuecomment -128912169
.

状态:“主”逻辑被签入并被标记门控。

我现在正在研究节点端口。 有很多奇怪的情况需要特殊处理。 到目前为止我的笔记:

# Basic node ports:
iptables -t nat -N KUBE-NODEPORTS
iptables -t nat -A PREROUTING -j KUBE-NODEPORTS
iptables -t nat -A OUTPUT -j KUBE-NODEPORTS
iptables -t nat -A KUBE-NODEPORTS -p tcp -m comment --comment "TEST: default/nodeport:p" -m tcp --dport 30241 -j KUBE-SVC-EQKU6GMUKRXBR6NWW53

# To get traffic from node to localhost:nodeport to the service:
echo 1 > /proc/sys/net/ipv4/conf/all/route_localnet
# Mark packets that are destined for services from localhost, then masquerade those
iptables -t nat -I KUBE-SVC-EQKU6GMUKRXBR6NWW53 -s 127.0.0.0/16 -j MARK --set-mark 0x4b000001;
iptables -t nat -A POSTROUTING -m mark --mark 0x4b000001 -j MASQUERADE

# To get traffic from a pod to itself via a service:
for intf in $(ip link list | grep veth | cut -f2 -d:); do brctl hairpin cbr0 $intf on; done
# Mark packets that are destined for each endpoint from the same endpoint, then masquerade those.
# This is hacky, but I don't really know which pods are "local" and I don't really want to right now. (but I will eventually)
iptables -t nat -I KUBE-SEP-HHNEQBOLY57T5MQCFIY -s 10.244.1.6 -j MARK --set-mark 0x4b000001

一直致力于测试的贡献工具。
到目前为止,我想我会在一个节点上启动一个服务器,时间延迟为
向它发出请求,请参阅获取 kube-proxy 资源负载并转储
将数据转换为 CSV 以进行绘图等。
希望在周五之前完成,现在对 kubectl 更加熟悉。

2015 年 8 月 12 日星期三晚上 8:48,Tim Hockin通知@ github.com
写道:

状态:“主”逻辑被签入并被标记门控。

我现在正在研究节点端口。 有很多怪人案例需要
特殊处理。 到目前为止我的笔记:

基本节点端口:

iptables -t nat -N KUBE-NODEPORTS
iptables -t nat -A PREROUTING -j KUBE-NODEPORTS
iptables -t nat -A OUTPUT -j KUBE-NODEPORTS
iptables -t nat -A KUBE-NODEPORTS -p tcp -m comment --comment "TEST: default/ nodeport:p " -m tcp --dport 30241 -j KUBE-SVC-EQKU6GMUKRXBR6NWW53

获取从节点到localhost:nodeport到服务的流量:

回声 1 > /proc/sys/net/ipv4/conf/all/route_localnet

标记发往本地主机服务的数据包,然后伪装这些数据包

iptables -t nat -I KUBE-SVC-EQKU6GMUKRXBR6NWW53 -s 127.0.0.0/16 -j MARK --set-mark 0x4b000001;
iptables -t nat -A POSTROUTING -m mark --mark 0x4b000001 -j MASQUERADE

要通过服务从 Pod 获取流量到其自身:

对于 $(ip 链接列表 | grep veth | cut -f2 -d:) 中的 intf; 做 brctl 发夹 cbr0 $intf on; 完毕

标记发往同一端点的每个端点的数据包,然后伪装这些数据包。

这是 hacky,但我真的不知道哪些 Pod 是“本地的”,我现在也不想知道。 (但我最终会)

iptables -t nat -I KUBE-SEP-HHNEQBOLY57T5MQCFIY -s 10.244.1.6 -j MARK --set-mark 0x4b000001


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130492394
.

@BenTheElder我刚刚在 GCE 上做了一些相当详细的网络性能测量——我建议看看 netperf (qperf 也提供了延迟测量)。

netperf 是一个客户端/服务器性能工具,我已经将客户端和服务器都打包在 docker 容器 paultilady/ netserver:ubuntu.2 中。 netperf 上有很多选项,但类似于启动两个 netserver pod 并运行

kubectl exec  -t $netserver-pod-1 -- netperf –l 30 -i 10 -I 99,1 -c -j -H $netserver-pod-2-ip -t OMNI --  -T tcp -D -O THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,MIN_LATENCY,MAX_LATENCY,P50_LATENCY,P90_LATENCY,P99_LATENCY,STDDEV_LATENCY,LOCAL_CPU_UTIL

应该给你一个不错的统计数据,包括延迟和吞吐量。 您也可以使用docker run --net=host运行 netserver 容器来进行 node->pod 测试。

这个容器的 dockerfile 非常简单,如果你想把它扩展成更精简的东西(例如一个基于 alpinelinux 的容器,以便更快地拉动),我可以将它启动。

谢谢我会研究一下。

这个评论来看,虽然我认为我们想要做某种服务请求延迟。 现在我正在尝试使用标准的 nginx 容器作为节点 X 并致力于让测试 pod 时间重复命中它,以便我们可以在节点 Y 上构建图表。

不过,我会看看 netperf/qperf,我们总是可以进行多个测试。
尽管根据之前与@thockin 的讨论,我想先完成该图表

2015 年 8 月 13 日星期四上午 12:02,Paul Tiplady通知@github.com
写道:

@BenTheElder https://github.com/BenTheElder我只是做了一些合理的
GCE 上的详细网络性能测量——我建议看一看
netperf(qperf 还提供延迟测量)。

netperf 是一个客户端/服务器性能工具,我已经打包了客户端和
docker 容器 paultilady/ netserver:ubuntu.2 中的服务器。 那里
netperf 上有很多选择,但有点像旋转两个
netserver pods 和运行

kubectl exec -t $netserver-pod-1 -- netperf –l 30 -i 10 -I 99,1 -c -j -H $netserver-pod-2-ip -t OMNI -- -T tcp -D -O THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,MIN_LATENCY,MAX_LATENCY,P50_LATENCY,P90_LATENCY,P99_LATENCY,STDDEV_LATENCY,LOCAL_CPU_UTIL

应该给你一个不错的统计数据,包括延迟和吞吐量。
您可以使用 docker run --net=host 运行 netserver 容器来执行
node->pod 测试也是如此。

这个容器的 dockerfile 非常简单,如果
你想把它扩展成更精简的东西(例如一个基于 alpinelinux 的
容器以便更快地拉动)。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130524576
.

关于节点端口:在#9210 @Symmetric带来了这个案例:

如果交通流量:
LB -> node1:nodePort
并且服务 pod 在 node2 上,那么完整的流程将是:
LB -> node1:nodePort -> node2 -> pod:svcPort
srcIP 仍将是 LB,因此响应将继续
pod -> node2 -> LB
由于node2可以直接路由到LB。

现在我们失去了 un-DNAT 为返回数据包恢复正确源 IP 的机会(这只能发生在 node1 上)。

我已经重现了这个问题。 确认这是一个真正的问题。 tcpdump 显示数据包被 DNAT 传输到(机器外)pod IP:port,src 完好无损,但目标机器上的 tcpdump 没有显示任何内容。 即使数据包确实到达那里,我也不确定我会期望发生什么。

我认为唯一的解决方案是 SNAT。 影响最小的解决方案是 _only_ 来自 LB 的 SNAT 数据包,这些数据包发往节点外,但是 a) 我在 kube-proxy 中没有该信息(可以以代码为代价获得它)和 b) 因为任何无论如何,策略都必须考虑 SNAT 情况,我可以通过始终对外部 LB 数据包进行 SNAT 来简化。 这对政策引擎有多糟糕?

最终 LB 将足够聪明,只针对带有 Pod 的主机,并且流量将保持在本地,然后这将没有实际意义。

虽然它变得更加复杂。 我们有 deprecatedPublicIPs 字段,我们可能会通过对行为进行一些调整来取消弃用。 我想我们需要为那些做同样的事情。 但它变得更加复杂——我实际上并不知道所有的公共 IP(例如,VM 有一个 1 对 1 的 NAT 外部 IP)。 简单回答 - 总是 SNAT 节点端口数据包。 什么想法?

我明天会测试更多。

@BenTheElder您可以使 netserver pod 成为一项服务,以便来自 perf <-> 的流量
服务器正在通过服务 VIP。 这样你就不必做
自己进行采样/延迟计算...

2015 年 8 月 12 日星期三晚上 9:20,Benjamin Elder通知@github.com
写道:

谢谢我会研究一下。

这个评论
虽然我认为我们想做某种服务请求延迟。 对
现在我尝试使用标准的 nginx 容器作为节点 X 并继续工作
有一个测试吊舱时间反复点击它,所以我们可以建立一个图表
节点 Y。

不过,我会看看 netperf/qperf,我们总是可以进行多个测试。
尽管根据之前的讨论,我想先完成该图表
@thockin

2015 年 8 月 13 日星期四上午 12:02,Paul Tiplady通知@github.com
写道:

@BenTheElder https://github.com/BenTheElder我只是做了一些合理的
GCE 上的详细网络性能测量——我建议看一看
netperf(qperf 还提供延迟测量)。

netperf 是一个客户端/服务器性能工具,我已经打包了客户端和
docker 容器 paultilady/ netserver:ubuntu.2 中的服务器。 那里
netperf 上有很多选择,但有点像旋转两个
netserver pods 和运行

kubectl exec -t $netserver-pod-1 -- netperf –l 30 -i 10 -I 99,1 -c -j -H
$netserver-pod-2-ip -t OMNI -- -T tcp -D -O
THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,MIN_LATENCY,MAX_LATENCY,P50_LATENCY,P90_LATENCY,P99_LATENCY,STDDEV_LATENCY,LOCAL_CPU_UTIL

应该给你一个不错的统计数据,包括延迟和
吞吐量。
您可以使用 docker run --net=host 运行 netserver 容器来执行
node->pod 测试也是如此。

这个容器的 dockerfile 非常简单,如果
你想把它扩展成更精简的东西(例如一个基于 alpinelinux 的
容器以便更快地拉动)。


直接回复此邮件或在 GitHub 上查看
<
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130524576

.


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130527558
.

真的。 我认为@thockin提到最终想要一个 e2e 延迟测试作为
好。 如果时间允许,将会有许多不同的测试,我们将
可能必须考虑 gce 与 AWS 等。
2015 年 8 月 13 日下午 1:47,“Paul Tiplady”通知@github.com 写道:

您可以使 netserver pod 成为一项服务,以便来自 perf <-> 的流量
服务器正在通过服务 VIP。 这样你就不必做
自己进行采样/延迟计算...

2015 年 8 月 12 日星期三晚上 9:20,Benjamin Elder通知@github.com
写道:

谢谢我会研究一下。

来自[此评论](

https://github.com/kubernetes/kubernetes/pull/9210#issuecomment-130154261)
虽然我认为我们想做某种服务请求延迟。 对
现在我尝试使用标准的 nginx 容器作为节点 X 并正常工作

有一个测试吊舱时间反复点击它,所以我们可以建立一个图表
节点 Y。

不过,我会看看 netperf/qperf,我们总是可以进行多个测试。
尽管根据之前的讨论,我想先完成该图表
@thockin

在星期四,2015年8月13日在12:02,保罗·蒂普莱迪< [email protected]

写道:

@BenTheElder https://github.com/BenTheElder我只是做了一些
合理的
GCE 上的详细网络性能测量——我建议看一看

netperf(qperf 还提供延迟测量)。

netperf 是一个客户端/服务器性能工具,我已经打包了两个客户端

docker 容器 paultilady/ netserver:ubuntu.2 中的服务器。
那里
netperf 上有很多选择,但有点像旋转两个
netserver pods 和运行

kubectl exec -t $netserver-pod-1 -- netperf –l 30 -i 10 -I 99,1 -c -j
-H
$netserver-pod-2-ip -t OMNI -- -T tcp -D -O

THROUGHPUT,THROUGHPUT_UNITS,MEAN_LATENCY,MIN_LATENCY,MAX_LATENCY,P50_LATENCY,P90_LATENCY,P99_LATENCY,STDDEV_LATENCY,LOCAL_CPU_UTIL

应该给你一个不错的统计数据,包括延迟和
吞吐量。
您可以使用 docker run --net=host 运行 netserver 容器来执行
node->pod 测试也是如此。

这个容器的 dockerfile 非常简单,我可以将其触发
如果
你想把它扩展成更精简的东西(例如一个基于 alpinelinux 的
容器以便更快地拉动)。


直接回复此邮件或在 GitHub 上查看
<

https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130524576

.


直接回复此邮件或在 GitHub 上查看
<
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130527558

.


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130776866
.

@Symmetric netperf 测试运行良好。 谢谢你的建议:-)

我想稍后重新测试像 Web 服务这样的“真实”负载,但是在获得正确的 args 之后,到目前为止它提供了非常好的数据。 当我完成清理工作后,我会稍后发布结果。

很高兴听到这对你有用——有很多令人眼花缭乱的
该工具上的选项,但事实证明它对我的分析工作非常有用。
绝对比iperf好...

2015 年 8 月 13 日星期四下午 2:32,Benjamin Elder通知@github.com
写道:

@Symmetric https://github.com/Symmetric netperf 测试正在运行
很好。 谢谢你的建议:-)

我想稍后重新测试像网络服务这样的“真实”负载
可能,但是在获得正确的参数之后,它提供了非常好的数据,所以
远的。 当我完成清理工作后,我会稍后发布结果。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -130850398
.

@thockin我认为我们可以使用 SNAT 来处理 LB 流量。 我目前的想法是,您需要将 pod 的访问策略指定为以下之一:

  • 默认为 'allow from [my namespace]',在这种情况下,LB 数据包将被丢弃
  • 'allow from [list of namespaces]' 或 'allow from [all namespaces in the cluster]',同样总是丢弃 LB 数据包
  • 'allow from all',在这种情况下,我们不关心它是来自 LB、其他节点还是其他任何地方

因此,仅丢失 LB 的源 IP 实际上并不会花费我们太多。

如果我们能保证 LB 命中服务 Pod 的正确节点,那就太好了——在这种情况下,我们不需要 SNAT,我们可以通过将 LB IP 列入白名单来运行更严格的船,当它们在一个服务,否则丢弃流量。

关于 publicIP,我认为它们与 nodePort 具有相同的考虑因素,因此我们需要对它们进行 SNAT,直到 LB 可以命中正确的主机。 以上每个都很好,除非我错过了某种比nodePort更邪恶的方式......

作为安全措施,实际上包含一个标志来代理 MASQUERADE 可能非常有用(非常接近用户空间代理)。 我认为这并不难,而且是一种很好的诊断方法,甚至在出现问题时进行回退(我正在考虑 vxlan 情况)。

-------- 消息来源 --------
德:保罗·蒂普莱迪[email protected]
日期 : 14/08/2015 12:50 (GMT+11:00)
À : kubernetes/kubernetes [email protected]
抄送:Mikaël Cluseau [email protected]
Objet : Re: [kubernetes] 使用 iptables 代替用户空间进行代理
(#3760)

@thockin我认为我们可以使用 SNAT 来处理 LB 流量。 我目前的想法是,您需要将 pod 的访问策略指定为以下之一:

默认为 'allow from [my namespace]',在这种情况下,LB 数据包将被丢弃
'allow from [list of namespaces]' 或 'allow from [all namespaces in the cluster]',同样总是丢弃 LB 数据包
'allow from all',在这种情况下,我们不关心它是来自 LB、其他节点还是其他任何地方

因此,仅丢失 LB 的源 IP 实际上并不会花费我们太多。

如果我们能保证 LB 命中服务 Pod 的正确节点,那就太好了——在这种情况下,我们不需要 SNAT,我们可以通过将 LB IP 列入白名单来运行更严格的船,当它们在一个服务,否则丢弃流量。

关于 publicIP,我认为它们与 nodePort 具有相同的考虑因素,因此我们需要对它们进行 SNAT,直到 LB 可以命中正确的主机。 以上每个都很好,除非我错过了某种比nodePort更邪恶的方式......


直接回复此邮件或在 GitHub 上查看。

@MikaelCluseau这不是一个坏主意 - 你能不能专门就此开一个新问题,这样我就不会忘记它?

仍然TODO:修复发夹,e2e,默认启用

嗨蒂姆,很抱歉没有回到你身边,但我们在这里处理了一些混乱......我想下周六我会选择修复发夹。

这是给我自己的笔记——你打算解决其中的一些问题吗? :)

是的,当然,正如我在谈论 e2e 测试时所说的那样。 我去帮忙,Kubernetes对我帮助很大,所以我最好尽可能地掌握它,还有什么比bug更好的呢? :-) 随意提出更高优先级的任何建议,但我认为发夹式的开始非常好。 它应该发生在 kubelet 中并有一个启用标志(默认情况下首先禁用)。 我会尽量每周工作 0.5 到 1 天。

AFAIK 剩下要做的唯一部分是将其设为默认值,这在 v1.1 之后的某个时间可能会发生(假设没有爆炸),并且这有一些英里。

哇!

2015 年 9 月 24 日星期四上午 11:21,Tim Hockin通知@ github.com
写道:

AFAIK 剩下要做的唯一部分是将其设为默认值
在 v1.1 之后的一段时间发生(假设没有爆炸),这有一些里程
在上面。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -142960614
.

v1.1 之后的一段时间,这有一些里程。

哎哟。 我们真的指望它 1.1....
https://github.com/kubernetes/kubernetes/blob/master/docs/roadmap.md

@bgrieder您仍然可以通过参数启用它。

它是 IN 但默认情况下不启用。 您可以选择使用单个注释
节点(和 kube-proxy 重启)

2015 年 9 月 24 日星期四上午 8:27,Bruno G. [email protected]写道:

v1.1 之后的一段时间,这有一些里程。

哎哟。 我们真的指望它 1.1....
https://github.com/kubernetes/kubernetes/blob/master/docs/roadmap.md


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -142962932
.

@thockin @bnprss好的,但我们希望 1.1 版在发布后能在 Google Container Engine 上运行。 我想知道我们将有什么样的灵活性来“选择每个节点使用单个注释”。 您能否向我们提供一些有关该过程的详细信息或向我们指出一些文档?

升级到 1.1 后:

$ for node in $(kubectl get nodes -o name); do kubectl annotate $node net.beta.kubernetes.io/proxy-mode=iptables; done

然后通过 SSH 连接到每个节点并重新启动 kube-proxy(或重新启动每个节点)。

如果你想更谨慎,做一两个节点,然后尝试一下:)

我已将此问题标记为“发行说明”,以便我们不会忘记在 1.1 文档中包含该魔术循环。

@RichieEscarez

(只是想顺便说一下我们已经使用 iptables 代理一个星期了,看起来一切正常!)

@thockin应该将其关闭还是从 1.1 里程碑中删除?

我会将其移至 1.2 仅用于默认启用。

为一个潜在的愚蠢问题道歉,但关于保留客户端 IP:

@thockin我在 9 月 2 日的另一个问题中看到“只有集群内流量保留客户端 IP”——这对于 1.2 alpha 来说仍然如此吗?

我们启动了一个新的 1.2 集群,应用了节点注释,重新启动,并且仍然看到 10.244.0.1 作为对运行 HAProxy 的 pod 发出的所有请求的源地址。

在这一点上,我只是想弄清楚我们是否错过了一个设置,或者我正在尝试实现一些尚不可能的东西——即查看发出请求的实际客户端的公共 IP 地址集群外。

默认仍然使用用户空间模式。 您必须在上设置注释
节点(net.beta.kubernetes.io/proxy-mode=iptables)并重启
代理。 但这不会暴露外部客户端 IP,只会暴露在集群内
知识产权。
2015 年 10 月 23 日下午 5:09,“Ben Hundley”通知@ github.com 写道:

为一个潜在的愚蠢问题道歉,但关于保存
客户端 IP:

@thockin https://github.com/thockin我在 9 月 2 日的另一个问题中看到
“只有集群内流量保留客户端 IP”——这仍然是
1.2 alpha 是真的吗?

我们启动了一个全新的 1.2 集群,应用节点注释,重新启动,
并且仍然看到 10.244.0.1 作为所有对一个请求的源地址
运行 HAProxy 的 pod。

在这一点上,我只是想弄清楚我们是否错过了
设置或者我正在尝试实现一些尚不可能的东西——那个
正在查看发出请求的实际客户端的公共 IP 地址
从集群外部。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150725513
.

我可以通过 DNAT 的外部流量 + kube-proxy 路由来保留外部客户端 IP。 例如,如果您的服务网络是 10.42.0.0/16,并且您在 IP 10.10.1.1 上有一个高可用的 kube-proxy,那么您可以拥有以下 iptable 规则:

-A PREROUTING -i public -p tcp -m tcp --dport 25 -j DNAT --to-destination 10.42.12.34

以及以下路线:

10.42.0.0/16 via 10.10.1.1 dev edge 

后面的 pod 就会看到真实的 IP:

Oct 24 02:41:39 email-0yr7n mail.info postfix/smtpd[469]: connect from zed.yyy.ru.[94.102.51.96]

当然,您必须拥有正确的数据包返回路径。

是的,如果这个 DNATs 到一个机外后端,你就会形成一个没有
SNAT。 这是根本问题。

2015 年 10 月 23 日星期五晚上 8:12,Mikaël Cluseau通知@github.com
写道:

我可以通过 DNAT 的外部流量保持外部客户端 IP +
通过 kube-proxy 路由。 例如,如果您的服务网络是
10.42.0.0/16 并且您在 IP 上有一个高度可用的 kube-proxy
10.10.1.1,你可以有如下iptable规则:

-A PREROUTING -i public -p tcp -m tcp --dport 25 -j DNAT --to-destination 10.42.12.34

以及以下路线:

10.42.0.0/16 通过 10.10.1.1 开发边缘

后面的 pod 就会看到真实的 IP:

10 月 24 日 02:41:39 email-0yr7n mail.info postfix/smtpd[469]:从 zed.yyy.ru.[94.102.51.96] 连接

当然,您必须拥有正确的数据包返回路径。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150747217
.

听起来很有趣,有链接吗? :-) 我试图找到一种方法来确保数据包将通过正确的 conntrack 规则。 我正在考虑通过集群复制 conntrack 状态。

我对你想要实现的目标有点迷茫。

当前 iptables 代理应该工作的方式是一个数据包
到达一个节点,我们检测到它不是本地生成的,将其标记为
SNAT,选择一个后端,用SNAT转发给后端,后端响应
对我们来说,我们 un-SNAT,un-DNAT,并响应外部用户。

2015 年 10 月 23 日星期五晚上 9:32,Mikaël Cluseau通知@github.com
写道:

听起来很有趣,有链接吗? :-) 我试图找到一种方法来确保
数据包将通过正确的 conntrack 规则。 我在想
通过集群复制 conntrack 状态。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150753147
.

哦,对不起,如果我不清楚。 我说的是无 SNAT 的情况。 如果每个 kube-proxy 都有相同的 conntrack 列表,那么当容器回复客户时,它们中的任何一个都应该能够正确地取消 DNAT。

我看不到没有复制不涉及 HA 来保持这样的线形结构:

[client] ----- [proxy in HA] ------ [node1]
                           `------- [node2]

但如果一个三角形的东西能起作用,它应该会打开更多的可能性。

[client] ----- [proxy1] ------ [node1]
       `------ [proxy2] ------ [node2]

那会很可爱,但看起来很复杂

2015 年 10 月 25 日星期日晚上 11:20,Mikaël Cluseau通知@github.com
写道:

哦,对不起,如果我不清楚。 我说的是无 SNAT 的情况。 如果
每个 kube-proxy 都有相同的 conntrack 列表,它们中的任何一个都应该能够
当容器回复客户时正确 un-DNAT。

我看不到没有复制的不涉及 HA 来保持
像这样的线形结构:

[客户端] ----- [HA 中的代理] ------ [node1]
`------- [节点2]

但如果一个三角形的东西能起作用,它应该会打开更多的可能性。

[客户端] ----- [代理1] ------ [节点1]
`------ [proxy2] ------ [node2]


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -151037663
.

我必须探索的方式(我没有也不喜欢在适当的研究之前询问,但是因为 subjet 现在是开放的......)是“非对称多路径路由”,你可以在这里看到:http:// conntrack-tools.netfilter.org/manual.html#sync-aa 。 是的,那真的很好:-)

可能工作的最简单的事情......

  1. proxy1 通过 iptables 钩子接收新连接(我想我在某处看到过),并且它的 LB 将它分配给 proxy2 的节点。
  2. proxy1 发送类似“为 {src-ip}:{src-port} -> {pod-ip}:{pod-port} 设置 conntrack 条目”的请求
  3. proxy2 接收请求,设置 conntrack 条目,并将其 ACK 给 proxy1
  4. proxy1 让数据包通过 DNAT 规则(它也在 proxy1 中放置了一个 conntrack 条目)。
  5. 当 pod 回复时,proxy2 的主机会相应地取消 DNAT。
  6. 当客户端通过 proxy1 在此流上发送另一个数据包时,conntrack 条目也会执行正确的 DNAT。

这样,每个新连接的开销是 2 个数据包,并通过避免 un-SNAT + 额外路由(否则数据包必须通过 proxy1 返回)迅速得到回报。

我不是网络专家,所以我可能假设太多,但这似乎是合理的。

就我而言,我的目标是为每个 NodePort 服务建立防火墙规则。

看起来我可以在 INPUT 链中添加简单的 ALLOW IP / DROP 其他所有规则,如下所示:

iptables -A INPUT -s $WHITELISTED_IP -p tcp --dport $CONTAINER_PORT -j ACCEPT
iptables -A INPUT -p tcp --dport $CONTAINER_PORT -j DROP

为了应用这些规则,我的设想是在 NodePort 服务上使用注释。 注释将包含列入白名单的 IP。

由于我可以等待这些规则的应用,因此我想象了对每个通过的 minion 的精细 cron 任务,并从所有 Service 注释更新 minion 的 INPUT 链。

这里有什么可能导致问题的吗? 我疯了吗?

@thockin的视野比我好,但我不会为此使用注释。 我认为安全性是正交的,应该放在系统旁边,或者可能是网络/代理插件。 如果你有 Kubernetes,你就有 etcd,所以你可以简单地将规则集存储在一个键中并使用 etcdctl watch/exec 进行更新:

# while true; do etcdctl watch "/iptables/$(hostname)" && etcdctl get /iptables/$(hostname) |iptables-restore --noflush; done &
# iptables -F my-filter
# iptables -nvL my-filter
Chain my-filter (0 references)
 pkts bytes target     prot opt in     out     source               destination      
# ~nwrk/go/bin/etcdctl set /iptables/$(hostname) >/dev/null <<EOF
*filter
:my-filter -
-A my-filter -j ACCEPT -s 1.2.3.4 -p tcp --dport 80
-A my-filter -j DROP -p tcp --dport 80
COMMIT
EOF
# iptables -nvL my-filter
Chain my-filter (0 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 ACCEPT     tcp  --  *      *       1.2.3.4              0.0.0.0/0            tcp dpt:80
    0     0 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80

我想你想要#14505

2015 年 10 月 26 日星期一上午 8:53,Ben Hundley通知@github.com
写道:

就我而言,我的目标是为每个 NodePort 服务建立防火墙规则。

看起来我可以添加简单的 ALLOW IP / DROP 其他所有规则
INPUT 链,如下所示:

iptables -A INPUT -s $WHITELISTED_IP -p tcp --dport $CONTAINER_PORT -j ACCEPT
iptables -A 输入 -p tcp --dport $CONTAINER_PORT -j DROP

为了应用这些规则,我的设想是在
节点端口服务。 注释将包含列入白名单的 IP。

因为我可以等一下这些规则的应用,所以我想了一下
每个minion上的cron任务通过并更新minion的INPUT
来自所有服务注释的链。

这里有什么可能导致问题的吗? 我疯了吗?


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -151181267
.

这是最初的方法,将安全组附加到负载均衡器。 我刚刚在 AWS 上非常快地达到了每个网络接口的侦听器限制,并遇到了一些麻烦的逻辑,试图将防火墙规则分散到单个 kube 集群的多个 SG 和多个 ELB。

幸运的是,我们正在寻找一个更好的解决方案,它不涉及使用 iptables。

如果你刚加入,请允许我总结一下。 有关无法获取客户端 IP 的所有问题都已合并到此问题中,但是提出(和实施)的解决方案并没有解决它。 您目前无法访问客户端的 ip。 哈。

@shaylevi2目前没有什么好方法可以在通过云 LB 跳转到 nodePort 的同时获取客户端 IP。 一旦云LB赶上,我就直接跳过去。 但这确实会保留集群内的客户端 IP

但这确实会保留集群内的客户端 IP

这完全取决于集群网络的设置方式; 例如,它目前在 OpenShift 中无法正常工作,因为 iptables 规则不会在 OVS 内部流量上运行。 因此,数据包通过 DNAT 进入服务端点,但由于源 IP 是集群内部的,因此响应将保留在 OVS 内,因此它不会再次访问 iptables,因此 DNAT 不会被逆转,所以客户端 pod 无法识别数据包。 目前,最简单的解决方法是完全伪装进入端点的数据包,迫使它们在出路时再次从 OVS 反弹。 (我正在努力想办法解决这个问题。)

OVS 内部是否有 VIP 概念? 你可以摆脱
kube-proxy(参见 opencontrail)

2015 年 11 月 20 日星期五上午 7:09,Dan Winship通知@ github.com
写道:

但这确实会保留集群内的客户端 IP

这完全取决于集群网络的设置方式; 例如,它没有
目前在 OpenShift 中正常工作,因为 iptables 规则不会运行
在 OVS 内部流量上。 所以数据包得到 DNAT 进入服务
端点,但由于源 IP 是集群内部的,响应将
留在 OVS 中,因此它不会再次访问 iptables,因此 DNAT 不会
被反转,因此客户端 pod 无法识别数据包。 在
此刻,最简单的解决方法是完全伪装数据包
进入端点,迫使他们再次从 OVS 中弹开
出路。 (我正在努力想办法解决这个问题。)


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -158426296
.

我们已经讨论过完全在 OVS 内部完成与纯 iptables 代理的基本等效,但这需要 OVS conntrack 支持,这需要一个非常新的内核,我们还不想依赖它。 不过,这可能是长期计划。

(目前看来,我们可以通过为源 IP+端口与来自容器接口的已知服务端点匹配的数据包从 OVS 中添加一个无偿的额外跃点来使其工作;然后节点可能会取消 DNAT ,然后将其弹回到 OVS 中,在那里它可以正确地传送回客户端 Pod。)

我希望写一个关于服务 VIP 抽象的文档并使它
清楚它是一个可以被替换的抽象(并且应该在某些
案例)。

2015 年 11 月 23 日星期一上午 6:54,Dan Winship通知@ github.com
写道:

我们已经讨论过做本质上等同于
pure-iptables-proxying 完全在 OVS 内部,但这需要 OVS conntrack
支持,这需要一个我们不想依赖的最新内核
还在。 不过,这可能是长期计划。

(现在看起来我们可以通过添加一个无偿的额外
对于源 IP+端口与已知服务匹配的数据包,跳出 OVS
来自容器接口的端点; 然后节点将
可能会取消 DNAT,然后将其弹回到 OVS 中,在那里它可以得到
正确传送回客户端 pod。)


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -158959014
.

尽管 iptables/nftables 可以解决 TCP 和 UDP 负载均衡用例,但我个人认为 IPVS https://github.com/kubernetes/kubernetes/issues/17470会更合适,因为它是专门为负载均衡而构建的(阅读:k8s 团队正在进行的更改/维护较少),提供了一组更丰富的负载平衡算法,已证明在接近线速的速度下具有稳定性,amd 还拥有准备操作规则的 golang 库。

@thockin ,其他人,根据https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150743158,我做了注释,但正如正确提到的,位于容器中的应用程序仍然看不到外部客户端 IP .

如何实现这一点,即获取外部客户端 IP? 在我的设置中,没有外部 LB,服务作为 nodeport 公开,客户端正在与我的容器化应用程序建立纯 TCP(不是 http/Websocket)连接。

@ashishvyas您正在运行什么版本的 kube-proxy?

我正在运行 v1.1.3

按照https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -143280584 和https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150743158 中的说明操作,但不要使用名为net.beta.kubernetes.io/proxy-mode ,使用名为net.experimental.kubernetes.io/proxy-mode的注解。

for node in $(kubectl get nodes -o name); do
  kubectl annotate $node net.experimental.kubernetes.io/proxy-mode=iptables;
done

您应该在 kube-proxy 启动的开头看到日志语句,例如“找到实验注释”和“注释允许 iptables 代理”

https://github.com/kubernetes/kubernetes/commit/da9a9a94d804c5bfdf3cc86ee76a2bc1a2742d16的第一个版本是 1.1.4,所以net.beta.kubernetes.io/proxy-mode对很多人都不起作用。 你不是第一个遇到这种情况的人。

由于代理的工作方式,当它通过时我们会丢失客户端 IP
一个节点端口。 我知道这不是很好。 我非常关心如何
正确解决这个问题,但这主要归结为
负载平衡器(或流量到达节点的其他方式,例如
作为 DNS-RR)

2016 年 1 月 13 日星期三上午 10:25,Mike Danese通知@github.com
写道:

按照#3760(评论)中的说明进行操作
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -143280584
和#3760(评论)
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -150743158
但不是使用名为的注释
net.beta.kubernetes.io/proxy-mode,使用名为的注解
net.experimental.kubernetes.io/proxy-mode。

对于 $(kubectl get nodes -o name) 中的节点; 做
kubectl annotate $node net.experimental.kubernetes.io/proxy-mode=iptables;
完毕

您应该在 kube-proxy 启动的开头看到日志语句
像“发现实验注释”和“注释允许 iptables 代理”

da9a9a9 的第一个版本
https://github.com/kubernetes/kubernetes/commit/da9a9a94d804c5bfdf3cc86ee76a2bc1a2742d16
把它变成了 1.1.4。 你不是第一个遇到这种情况的人。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -171387997
.

@thockin ,现在有可能临时解决这个问题的解决方法吗? 如果是,我会建议为我提供详细的步骤,此线程上的其他人会有所帮助。

不,目前没有真正的解决方法。 问题归结为
事实上,每个 kube-proxy 可能会选择不同节点上的后端。
使用原始客户端 IP 转发流量将使另一个节点
直接回应这显然是行不通的。

“修复”是_仅_将服务 S 的流量发送到具有
至少 1 个后端让 S _and_ 发送与多少成正比的流量
每个节点都有的后端。 Kube-proxy 然后可以选择本地后端
只。

考虑 2 个节点和 3 个后端。 一个节点必然以 2 结束
后端。 无论路由流量必须向一个节点发送 2 倍的流量
到另一个节点。 我们只是还没有解决这个问题 - 没有
云负载平衡器支持这一点,所以它有点推测性和
因此开始工作非常危险。

2016 年 1 月 13 日星期三下午 12:17,Ashish Vyas通知@ github.com
写道:

@thockin https://github.com/thockin ,任何临时解决方法
现在可以解决这个问题吗? 如果是,我建议提供
我和其他人在这个线程上的详细步骤会有所帮助。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -171420567
.

@mikedanese ,我似乎无法在 gcr.io 上找到 1.1.4:

$ sudo docker pull gcr.io/google_containers/
拉取存储库 gcr.io/google_containers/hyperkube
在存储库 gcr.io/google_containers/hyperkube 中找不到标签 v1.1.4
$ sudo docker pull gcr.io/google_containers/
v1.1.3:从 google_containers/hyperkube 拉取
摘要:sha256:004dde049951a4004d99e12846e1fc7274fdc5855752d50288e3be4748778ca2
状态:图像是最新的 gcr.io/google_containers/ hyperkube:v1.1.3

@thockin为冗长的回复道歉,我想介绍我们试图解决这个问题的两种方法,以便其他人能够理解我们在这两种方法中面临的挑战。

作为一点背景,我们的主要应用程序是一个非常高性能的智能 DNS 平台(即它需要 UDP 并且每个 pod 需要至少做 100k+ 请求/秒),以及它在 SNI 代理中的支持应用程序,需要看到客户端真实IP 地址(这对我们来说是个障碍)。 我们不想为不同的应用程序使用不同的网络方法,所以我们决定为所有人标准化一个单一的网络方法,出于我上面提到的原因(性能/稳定性/灵活性/目的构建 SLB),我们选择使用 IPVS ,但是您也可以仅使用 iptables 沿着这些相同的路线一起破解某些东西。 我们使用 vxlan(快速、简单、在站点之间工作),但这两种方法也应该与 OVS 的 GRE/VXLAN 或标准的第 2 层主机网络一起使用(假设您的主机都在同一个 L2 网络上)。

我们使用任播和 DNS 的混合分配传入的最终用户流量,这取决于故障转移速度要求或最适合特定类型服务的任何方法,因此我们可以相当均匀地分配进入我们节点的最终用户流量,但是正如您所指出的,问题是在 pod 之间获得均匀的流量分布,而不管 pod 位置如何。 另一个问题是确保与其他服务通信的服务有效地进行负载平衡。

我们尝试了两种模型来解决这个问题:

我们尝试的第一种方法是 2 层 VIP。 外部 VIP(每个服务 1 个),在节点之间分配流量(基于节点上该服务的 pod 数量),然后是内部 VIP(在带有 pod 的节点上运行),在节点内分配负载(通常是均匀分布在豆荚中)。 这种模型的局限性在于,运行外部 VIP 的节点需要运行两个不同的网络命名空间,或者运行自己的物理节点。 在 DSR 模式(直接服务器返回)模式下使用 IPVS 的好处是它不需要看到返回流量,流量如下:

Consumer >> (over L3) >> External VIP node >> (1) >> Internal VIP node >> (2) >> Container >> (any which way you want) >> Consumer

(1) 带有外部 VIP 的主机上的 IPVS(在 DSR 模式下)选择一个 _node_ 将流量发送到(IPVS 术语中的“真实服务器”),并且只更改数据包的 DST MAC 地址(即 IP 数据包到达时保持不变) k8s 节点)。 它根据在节点上运行该服务的 pod 数量跨节点进行负载平衡。
(2) k8s 节点上的 IPVS(也在 DSR 模式下)负载均衡跨 Pod 的流量(通过 veths 到节点)。 来自容器(TCP 和 UDP)的回复直接返回给服务的消费者。

这个模型的好处是,上手真的很简单,规则集也很容易管理。 这种模型的缺点是它通过运行外部 VIP 的多个节点集中了我们所有的服务请求(但不是回复)。 我们喜欢“无共享”,因此,输入版本 2:

现在有趣的第二个模型是具有更智能 IPVS 和 iptables 配置的单层 VIP。

Consumer >> Any node/local node >> (1) >> Container >> (any which way you want) >> Consumer
或者,它可能会转到另一个节点:
Consumer >> Any node/local node >> (1) >> Remote Node >> (2) >> Container >> (any which way you want) >> Consumer

(1) 流量到达 Primary VIP,流量在集群中的所有 pod 之间进行负载均衡。
(2) 流量到达 Secondary VIP,流量仅在所有本地 pod 之间进行负载平衡。 此辅助 VIP 仅用于来自网络上其他主机的流量(其 FWMARK VIP)。 我们用 FWMARK=1234 标记来自任何外部接口的流量,这会强制流量进入不同的规则集,从而防止节点之间的循环。

主 VIP 有一个本地 pod 和带有 pod 的远程主机列表(每个本地 pod 的权重为 100,远程节点的权重为 100 * pod 数)。 因此,例如,如果 3 个 Pod 在 nodeA 上本地运行,并且有两个 Pod 在 nodeB 上运行,则 nodeA 上的规则集将如下所示:

Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP service.ip.address:0 rr persistent 360
-> pod1.on.nodeA.ip:80 Route 100 0 0
-> pod2.on.nodeA.ip:80 Route 100 0 0
-> pod2.on.nodeA.ip:80 Route 100 0 0
-> interfaceip.of.nodeB:80 Route 200 0 0
FWM 1234 rr
-> pod1.on.nodeA.ip:80 Route 100 0 0
-> pod2.on.nodeA.ip:80 Route 100 0 0
-> pod3.on.nodeA.ip:80 Route 100 0 0

但是在 nodeB 上,IPVS 配置看起来有点不同,因为它只有两个本地 pod,而 nodeA 上只有三个远程 pod:

Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP service.ip.address:0 rr persistent 360
-> pod1.on.nodeB.ip:80 Route 100 0 0
-> pod2.on.nodeB.ip:80 Route 100 0 0
-> interfaceip.of.nodeA:80 Route 300 0 0
FWM 1234 rr
-> pod1.on.nodeB.ip:80 Route 100 0 0
-> pod2.on.nodeB.ip:80 Route 100 0 0

另一种方法是切换 FWMARK,并使用 iptables 对 veth+ 接口(通配符匹配)中的任何内容进行 FWMARK,并使 FWMARK 匹配仅用于本地负载平衡。

因为这里不涉及 NAT,所以在启动每个 pod 时,您需要将环境中的 SVC_XXX_YYY IP 添加到环回或虚拟接口,但您可能也可以更改 IPVS VIP 来执行 DNAT,我看不到为什么那行不通。

最终结果是最直接的网络,无需集中请求处理/路由,因此可扩展性更好。 缺点是创建 IPVS 规则时需要一些额外的智能。 我们使用一个小(golang)守护进程来完成所有这些,但如果我有时间并且有足够的兴趣,我会考虑为此编写一个 k8s 模块。

我很晚才研究这个问题,可能还没有足够详细地阅读完整的线索,但以防万一它有帮助:如果我已经理解@qoke上面的帖子,那么他们想要使用 VIP,而不是节点端口. 线程中早些时候提出的问题之一是使用 iptables kubeproxy 时没有维护源 IP。 但是,如果您使用的是服务 VIP 而不是我相信的节点端口功能,它会得到维护。 (无论如何,正如我所说,我还没有真正阅读完整的线索,所以如果这些评论很明显或没有帮助,那么请忽略!下周我回来时,我会尽量抽时间深入阅读从假期开始。)

@lxpollitt正确,使用 IPVS 时会维护源 IP,但是请记住,使用这种方法,我们几乎必须自己完成所有网络连接,因为 kube-proxy 不支持 IPVS 的配置。 您也可以使用 iptables 保留源 IP,但是您需要两层 IPtables DNAT,以便您可以在返回的途中“取消”流量

在我这边,通过 flannel(在 vxlan 模式下)管理我的容器网络,我在我的路由节点上的命名空间中使用了 kube-proxy(在 iptables 模式下而不是伪装)+ flannel。 外部请求经过 DNAT 处理以服务 IP,然后使用 kube-proxy 通过命名空间转发。 我没有做过主动/主动路由器集群测试,但是这个设置让我可以保留外部 IP。 我提到它 FWIW,但我明白它不是“最直接的网络”。

我知道如果 kube-proxy 可以管理它会很好,但是考虑到您的特定需求,尤其是负载平衡已经在 kube-proxy 之外的事实,编写客户 iptables-rules 管理器是否有意义观察 kubernetes 集群状态并将规则设置为 DNAT VIP 仅适用于正在运行的主机的 pod? 不过,这也可能是 kube-proxy 的一种模式,比如……嗯……我不擅长命名……--proxy-mode=iptables-to-node-pods-only。

谢谢你写的详细。 你的解决方案很有趣,我花了
今天有很多时间考虑它。 不幸的是你
跨越到非常特定的领域,在一般意义上不起作用。
像 GCE 这样的云无法使用 IPVS 网关模式,因为路由
网络。 即使网关有效,它也不支持端口重新映射,
Kubernetes 这样做,因此它仅适用于服务端口 == 目标
港口。

kubernetes 核心的挑战是找到处理您的问题的方法
一般情况下,或者让你摆脱困境并赋予你权力
自己设置。 也许我们可以用 ipvs encap 模式做点什么,
但我不知道它对性能的影响。

2016 年 1 月 14 日星期四凌晨 3:37,qoke [email protected]写道:

@thockin https://github.com/thockin抱歉这么长的回复,我
想要涵盖我们试图解决这个问题的两种方法,以便其他人可以
了解我们面临的挑战。

作为一点背景,我们的主要应用程序是一个非常高性能的
智能DNS平台(即需要UDP,需要做至少100k+
每个 Pod 的请求数/秒),及其在 SNI 代理中的支持应用程序
这需要查看客户端的真实 IP 地址(这是一个显示塞子
我们)。 我们不想为不同的网络使用不同的网络方法
应用程序,所以我们决定标准化一个单一的网络方法
全部,出于我上面提到的原因,我们选择使用 IPVS
(性能/稳定性/灵活性/目的构建 SLB),但你可以
可能只使用 iptables 沿着这些相同的路线一起破解一些东西
也。 我们使用 vxlan(快速、简单、在站点之间工作)但是这两个
方法也应该与 GRE/VXLAN 和 OVS 或标准第 2 层一起使用
主机网络也是如此(假设您的主机都在同一个 L2 网络上)。

我们使用任播和
DNS,取决于故障转移速度要求或最适合的
特定类型的服务,所以我们有相当均匀的分布
最终用户流量进入我们的节点,但问题正如你所指出的,
然后在 pod 之间获得均匀的流量分布,无论
豆荚位置。 另一个问题是确保服务与其他
服务负载均衡。

我们尝试了两种模型来解决这个问题:

我们尝试的第一种方法是 2 层 VIP。 外部 VIP(每人 1 个)
服务),它在节点之间分配流量(基于 pod 计数)
节点上的服务),然后是内部 VIP(在节点上运行)
与 Pod 一起分配负载(通常均匀分布在节点内)
跨豆荚)。 该模型的局限性在于运行外部的节点
VIP 需要运行两个不同的网络命名空间,或者运行自己的
物理节点。 在 DSR 模式下使用 IPVS 的好处(直接服务器返回)
模式是它不需要看到返回的流量,流量去:

消费者 >>(在 L3 上)>> 外部 VIP 节点 >> (1) >> 内部 VIP 节点 >>
(2) >> Container >> (任何你想要的方式) >> Consumer

(1) 带有外部VIP的主机上的IPVS(在DSR模式下)选择一个_node_来
将流量发送到(IPVS 术语中的“真实服务器”),并且仅更改 DST MAC
数据包的地址(即IP数据包到达k8s节点不变)。 它加载
根据运行该服务的 Pod 数量跨节点进行平衡
节点。
(2) k8s 节点上的 IPVS(也在 DSR 模式下)负载均衡跨
pods(通过veths到节点)。 来自容器(TCP 和 UDP)的回复
直接返回给服务的消费者。

这个模型的好处是,上手真的很简单,而且
规则集很容易管理。 这个模型的缺点是
通过一个集中我们所有的服务请求(但不是回复)
运行外部 VIP 的节点数。 我们喜欢“无共享”,所以,
进入版本2:

现在娱乐性的第二种模式是单层 VIP
更智能的 IPVS 和 iptables 配置。

消费者 >> 任何节点/本地节点 >> (1) >> Container >> (任何方式你
想要) >> 消费者
或者,它可能会转到另一个节点:
消费者 >> 任何节点/本地节点 >> (1) >> 远程节点 >> (2) >> 容器

(任何你想要的方式)>>消费者

(1) 流量到达 Primary VIP,流量在所有 Pod 之间进行负载均衡
集群。
(2) 流量命中Secondary VIP,流量只在所有负载均衡
本地豆荚。 此辅助 VIP 仅用于来自
网络上的其他主机(它是 FWMARK VIP)。 我们标记流量进来
任何 FWMARK=1234 的外部接口,并强制流量去
到不同的规则集,以防止节点之间的循环。

主要 VIP 有一个本地 pod 和带有 pod 的远程主机列表(带有
每个本地 pod 的权重为 100,100 * pod 数量为
远程节点)。 例如,如果 3 个 Pod 在 nodeA 上本地运行,并且
nodeB 上有两个 Pod 运行,nodeA 上的规则集看起来像
这个:

Prot LocalAddress:端口调度程序标志
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP service.ip.address:0 rr 持久化 360
-> pod1.on.nodeA.ip:80 路由 100 0 0
-> pod2.on.nodeA.ip:80 路由 100 0 0
-> pod2.on.nodeA.ip:80 路由 100 0 0
-> interfaceip.of.nodeB:80 路由 200 0 0
FWM 1234 rr
-> pod1.on.nodeA.ip:80 路由 100 0 0
-> pod2.on.nodeA.ip:80 路由 100 0 0
-> pod3.on.nodeA.ip:80 路由 100 0 0

但是在 nodeB 上,IPVS 配置看起来有点不同,因为它
在 nodeA 上只有两个本地 Pod 和三个远程 Pod:

Prot LocalAddress:端口调度程序标志
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP service.ip.address:0 rr 持久化 360
-> pod1.on.nodeB.ip:80 路由 100 0 0
-> pod2.on.nodeB.ip:80 路由 100 0 0
-> interfaceip.of.nodeA:80 路由 300 0 0
FWM 1234 rr
-> pod1.on.nodeB.ip:80 路由 100 0 0
-> pod2.on.nodeB.ip:80 路由 100 0 0

另一种方法是切换 FWMARKs,并使用 iptables
FWMARK veth+ 接口中的任何内容(通配符匹配)并具有 FWMARK
match 仅用于本地负载均衡。

最终结果是最直接的联网,无需集中
请求处理/路由,以便更好地扩展。 缺点是一些
创建 IPVS 规则时的额外智能。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -171619663
.

我认为尝试iptables-to-node-pods-only模式会很有趣,
但它有很多涟漪。 不平衡的可能性是非常真实的
至少服务控制器需要知道如何编程
外部负载平衡器。

2016 年 1 月 14 日星期四下午 3:59,Mikaël Cluseau通知@github.com
写道:

在我这边,通过法兰绒(在 vxlan 模式下)管理我的容器网络,我
使用 kube-proxy(在 iptables 模式下而不是伪装)+ flannel
我的路由节点上的命名空间。 外部请求被 DNATed 服务
IP,然后使用 kube-proxy 通过命名空间转发。 我没有
完成主动/主动路由器集群测试,但此设置允许我保持
外部 IP。 我提到它 FWIW,但我明白它不是“最
直接联网”。

我知道如果 kube-proxy 可以管理它会很好,但是
考虑到您的特定需求,尤其是负载平衡
已经在 kube-proxy 之外,对客户进行编码是否有意义
iptables-rules manager 监视 kubernetes 集群状态并设置
DNAT VIP 的规则仅适用于正在运行的主机的 Pod? 这可以
也是 kube-proxy 的一种模式,不过,比如……嗯……我不擅长
名称... --proxy-mode=iptables-to-node-pods-only。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -171821603
.

@thockin你的意思是如果 2 个副本在同一个节点上? 我认为我们可以将“对外部负载均衡器进行编程”的案例放在 kube-proxy 的范围之外,因为它有多个实例,并且外部 LB 程序员可能应该处于“单主”模式。 因此,允许 kube-proxy 模式“iptables-to-node-pods-only”只是两步过程中的第一步。

我想我明天可以尝试实现类似的东西:kube-proxy 中的“iptables-to-node-pods-only”模式,加上一个 contrib/ip-route-elb,它将维护一个 Linux 路由表,每个服务一个路由,根据节点对给定服务的端点数量,为每个节点设置正确的权重。

@thockin 例如,您的意思是 2 个副本在同一个节点上? 我想我们可以把案例“编程
kube-proxy 范围之外的外部负载均衡器,因为它有多个实例和一个外部负载均衡器
程序员可能应该处于“单主”模式。 因此,允许 kube-proxy 模式“iptables-to-node-
pods-only”只是两步过程中的第一步。

“仅代理到本地 Pod”必须是该过程的第 2 步。 第1步
必须更改服务控制器以仅发送负载平衡器
对给定服务具有 1 个或多个后端的节点。 那一步
单独可能是合理的,但需要大量测试才能
确保我们做对了。 我想我们最终想要做到这一点,
反正。

完成后,我们可以讨论使节点端口更喜欢本地
如果可能的话,后端,但这一步需要更加小心
想..这是否意味着_总是_(即永远不要选择远程
后端(如果本地可用)或概率? 我们应该做
通过同一个节点端口(不同的节点会得到非常
不同的行为)或者我们是否分配了一个不同的端口
当且仅当此节点具有 1 个或多个后端? 我们如何处理
不平衡问题?

我想我可以尝试在明天实现类似的东西:kube-proxy 中的“iptables-to-node-pods-only”模式,
加上一个 contrib/ip-route-elb,它将维护一个 Linux 路由表,每个服务一个路由,权重合适
对于每个节点,基于节点对给定服务的端点数量。

如果 ELB 支持权重,那么它在某些方面会比
GCE,没有。 没关系,我只是认为它不支持
重量。 我不认为它可以贡献,虽然 - 这是一个漂亮的
系统的基本部分。

在 01/16/2016 05:19 AM,蒂姆·霍金写道:

“仅代理到本地 Pod”必须是该过程的第 2 步。 第1步
必须更改服务控制器以仅发送负载平衡器
对给定服务具有 1 个或多个后端的节点。 那一步
单独可能是合理的,但需要大量测试才能
确保我们做对了。 我想我们最终想要做到这一点,
反正。

那讲得通。

一旦完成,[...]

所以让我们看看一旦完成:-)

如果 ELB 支持权重,那么它在某些方面会比
GCE,没有。 没关系,我只是认为它不支持
重量。

因为它来自手册,你可能有超过我的 10 倍
在这种网络经验中,我必须完全忽略一个问题。
man ip-route 是这样说的:

           nexthop NEXTHOP
                  the nexthop of a multipath route.  NEXTHOP is a 

复杂值,其自身的语法类似于顶级参数列表:

                          via [ FAMILY ] ADDRESS - is the nexthop 

路由器。

                          dev NAME - is the output device.

                          weight NUMBER - is a weight for this 

反映其相对带宽或质量的多径路由元素。

我不认为它可以贡献,虽然 - 这是一个漂亮的
系统的基本部分。

由于“E”代表“外部”,我觉得它可以从那里开始,
至少得到一些代码来支持想法。

2016 年 1 月 15 日星期五下午 2:55,Mikaël Cluseau
通知@github.com写道:

在 01/16/2016 05:19 AM,蒂姆·霍金写道:

“仅代理到本地 Pod”必须是该过程的第 2 步。 第1步
必须更改服务控制器以仅发送负载平衡器
对给定服务具有 1 个或多个后端的节点。 那一步
单独可能是合理的,但需要大量测试才能
确保我们做对了。 我想我们最终想要做到这一点,
反正。

那讲得通。

我今天想了很多,我认为这不会很困难。
只是中等难度。

一旦完成,[...]

所以让我们看看一旦完成:-)

很公平,我只是想知道一组更改的去向:)

如果 ELB 支持权重,那么它在某些方面会比
GCE,没有。 没关系,我只是认为它不支持
重量。

因为它来自手册,你可能有超过我的 10 倍
在这种网络经验中,我必须完全忽略一个问题。
man ip-route 是这样说的:

下一跳 NEXTHOP
多路径路由的下一跳。 NEXTHOP 是一个
复杂值,其自身的语法类似于顶级参数列表:

通过 [ 家庭 ] 地址 - 是下一跳
路由器。

dev NAME - 是输出设备。

weight NUMBER - 是这个的权重
反映其相对带宽或质量的多径路由元素。

不过,我们并没有真正使用 linux 的 IP 路由概念。 没有任何一个
无论如何,我知道使用它的 LB 实现。 GCE 使用 Google 的云
平衡器,它没有重量。 我不知道是亚马逊 ELB
做。

我不认为它可以贡献,虽然 - 这是一个漂亮的
系统的基本部分。

由于“E”代表“外部”,我觉得它可以从那里开始,
至少得到一些代码来支持想法。

当然,我们可以在 contrib 中开始 :)

另外,如果你想追求这个,你应该打开 2 个错误,比如:

1) 服务的负载均衡器应该只针对实际的节点
有一个该服务的后端

2) 为了跨负载均衡器保留客户端 IP,kube-proxy 应该
如果存在,总是更喜欢本地后端(外部参照 #1)

然后说明意图和方向

2016 年 1 月 15 日星期五下午 5:11,Tim Hockin [email protected]写道:

2016 年 1 月 15 日星期五下午 2:55,Mikaël Cluseau
通知@github.com写道:

在 01/16/2016 05:19 AM,蒂姆·霍金写道:

“仅代理到本地 Pod”必须是该过程的第 2 步。 第1步
必须更改服务控制器以仅发送负载平衡器
对给定服务具有 1 个或多个后端的节点。 那一步
单独可能是合理的,但需要大量测试才能
确保我们做对了。 我想我们最终想要做到这一点,
反正。

那讲得通。

我今天想了很多,我认为这不会很困难。
只是中等难度。

一旦完成,[...]

所以让我们看看一旦完成:-)

很公平,我只是想知道一组更改的去向:)

如果 ELB 支持权重,那么它在某些方面会比
GCE,没有。 没关系,我只是认为它不支持
重量。

因为它来自手册,你可能有超过我的 10 倍
在这种网络经验中,我必须完全忽略一个问题。
man ip-route 是这样说的:

下一跳 NEXTHOP
多路径路由的下一跳。 NEXTHOP 是一个
复杂值,其自身的语法类似于顶级参数列表:

通过 [ 家庭 ] 地址 - 是下一跳
路由器。

dev NAME - 是输出设备。

weight NUMBER - 是这个的权重
反映其相对带宽或质量的多径路由元素。

不过,我们并没有真正使用 linux 的 IP 路由概念。 没有任何一个
无论如何,我知道使用它的 LB 实现。 GCE 使用 Google 的云
平衡器,它没有重量。 我不知道是亚马逊 ELB
做。

我不认为它可以贡献,虽然 - 这是一个漂亮的
系统的基本部分。

由于“E”代表“外部”,我觉得它可以从那里开始,
至少得到一些代码来支持想法。

当然,我们可以在 contrib 中开始 :)

没有文档的 PR 的风险在于它的方向是错误的。 这是
将某事作为提案进行审查要容易得多。 我会看看你的
PR 当我有机会时,我希望很快。
2016 年 1 月 15 日下午 7:02,“Mikaël Cluseau”通知@github.com 写道:

可以直接使用此名称和一些名称打开 (1) 的拉取请求吗?
解释?


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172149777
.

不幸的是,您已经进入了在一般意义上不起作用的非常具体的领域。
由于路由网络,像 GCE 这样的云无法使用 IPVS 网关模式。 即使网关有效,它也不支持端口重新映射,而 Kubernetes 支持,因此它仅适用于服务端口 == 目标端口。

在网关方面,这在第 3 层网络上运行良好(我们使用覆盖),即使我们可以在没有覆盖网络的情况下逃脱,我们还是以这种方式构建它,因为我们希望我们使用的方法具有便携性和工作性在第 3 方云(如 GCE)中。

纠正 DSR 模式的限制是服务端口 == 目标端口,但这不是真正的问题,除非您有两个应用程序_在同一个容器中_需要在同一个端口上运行(我们花了很多时间思考这一点,并假设“每个容器 1 个应用程序”准则,我们找不到用于此的单个用例)。 我们有许多容器都运行在相同的节点上,其中的服务都在相同的端口上,并且所有负载平衡都很好。 如果你_真的_需要重新映射端口(我想了解背后的真正原因),你可以使用 IPVS NAT 模式而不是“ROUTE”模式。

kubernetes 核心的挑战是找到方法来处理您的一般情况,或者让您摆脱困境并授权您自己进行设置。 也许我们可以用 ipvs encap 模式做点什么,但我不知道它对性能的影响。

我们所做的是尽可能通用(在这里工作,在亚马逊工作,我确信当我们需要扩展时它会在 GCE 中工作),DSR 的唯一限制是应用程序在 pod/container 中运行需要在与服务相同的端口上运行,经过大量内部讨论,没有人能够从 E2E 应用程序堆栈的角度找到限制的场景。

话虽如此,如果您从等式中删除 DSR(IPVS 路由模式),而使用 IPVS 的“NAT 模式”,则可以重新映射端口,并且您仍然可以获得获得 IPVS 功能/性能/等的好处。 唯一的缺点是 NAT 增加了一些性能负担,但 (a) 它支持 UDP,(b) 与用户空间解决方案相比,它仍然闪电般快速。

@brendandburns @thockin在线程的早些时候,您询问了一些性能数据。 我不会称之为最全面的测试集,但我希望 HTTP 是容器中更常见的工作负载之一,所以这里有一些 apache-bench 数字作为起点:

https://docs.google.com/presentation/d/1vv5Zszt4HDGbuyVlvOe76unHskxPuZQseQnarNbhQVc

在 IPVS 上启用 DNAT 是为了与其他两种解决方案进行公平比较(这也意味着服务端口可能与目标服务端口不同)。 我们的工作负载对某些人来说可能看起来有点不寻常,但我们的性能目标可能与其他人没有什么不同(即尽可能地挤压硬件)。

谢谢!

我不确定 kube-proxy 不执行 UDP 的想法来自哪里 - 它
绝对可以,虽然可能不完美(没有连接它来
直到超时)。

还值得澄清 iptables(新)kube-proxy 与用户空间
(传统)模式。

在星期六,2016年1月16日晚上9:45,qoke [email protected]写道:

@thockin https://github.com/thockin在您要求的线程的早些时候
一些性能数据。 我不会称之为最全面的一套
测试,但我希望 HTTP 是更常见的工作负载之一
容器,所以这里有一些 apache-bench 数字作为起点:

https://docs.google.com/presentation/d/1vv5Zszt4HDGbuyVlvOe76unHskxPuZQseQnarNbhQVc

在 IPVS 上启用 DNAT 以便与其他两种解决方案进行公平比较
(这也意味着服务端口可以与目标服务端口不同)。 我们的
工作负载对某些人来说可能有点不寻常,但我们的性能目标
可能不会与其他人不同(即为所有人挤压硬件
你可以得到)。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172293881
.

对新模式与传统模式的良好呼吁 - 注意到并更新。

同样在 UDP 方面,感谢您的澄清; 直到现在,我才知道 kube-proxy 完全支持 UDP。 当我们第一次尝试使用 UDP 的 kube-proxy 时,我们遇到了很多问题。 不知道为什么,但我们确实增加了超时并且仍然有问题。 我们必须快速找到解决方案,因此我们最终使用 IPVS 解决了它,而不是调试它。 当时它只适用于非常低的每秒数据包工作负载(低于 1k pps),但我们最近没有重新测试。

iptables 和任何高速 UDP 服务的主要问题是 netfilter conntrack 表被填满。 即使您将 conntrack 大小增加到 100 万,一些受恶意软件感染的最终用户 DDoS 也会攻击您或试图利用您进行 DNS 放大攻击,然后您的 conntrack 表只会再次填满。 一般来说,DNS 服务器(或任何高速 UDP 服务)的最佳实践是禁用 conntrack(在原始表中使用 -j NOTRACK),如果禁用 conntrack,iptables NAT 和有状态的东西(-m state)就会中断。

除了 GIT 存储库,在尝试创建“k8s.io/kubernetes/pkg/proxy/ipvs”模块/包之前,哪里是最佳查看位置? 还是最好留给更了解代码库的人?

另外,如果您希望运行任何特定的基准测试,请告诉我,我会看看我能做些什么。

在 01/17/2016 08:50 PM,qoke 写道:

除了GIT repo,哪里是最好看的地方
试图创建一个“k8s.io/kubernetes/pkg/proxy/ipvs”模块/包?

我相信你也可以从 contrib 开始。

FWIW...我用list watch和undelta store做了一个独立的
binay 对集群的状态做出反应
https://github.com/kubernetes/kubernetes/pull/19755。 如果信息

https://github.com/kubernetes/kubernetes/pull/19755/files#diff -0becc97ac222c3f2838fbfe8446d5375R26
就足够了,您只需要更改下面几行的调用即可
(https://github.com/kubernetes/kubernetes/pull/19755/files#diff-0becc97ac222c3f2838fbfe8446d5375R44)。

请注意,我在此 PoC 中仅支持 clusterIP 服务。

不幸的是,您已经进入了在一般意义上不起作用的非常具体的领域。
由于路由网络,像 GCE 这样的云无法使用 IPVS 网关模式。 即使网关工作,它也不会
支持端口重映射,Kubernetes 就是这么做的,所以它只适用于服务端口 == 目标端口。

在网关方面,这在第 3 层网络上运行良好(我们使用覆盖),即使我们本可以逃脱
没有覆盖网络,我们以这种方式构建它,因为我们希望我们使用的方法是可移植的并且可以在 3rd 方工作
云(如 GCE)。

我不确定它是如何工作的。 机器级静态路由不起作用
在 GCE 中。 也许我错过了您应用的一些技术。 一世
坦率地承认我不是这方面的专家:)

纠正限制是服务端口 == 目标端口,但这不是真正的问题,除非您有两个应用程序
需要在同一个端口上运行的同一个容器(我们花了很多时间考虑这个,并假设“1个应用程序
每个容器”指南,我们找不到一个单独的用例。我们有许多容器都运行在相同的节点上
它们内部的服务都在相同的端口上,并且所有负载平衡都很好。 简而言之,我们使用的方法不会阻止您
在同一个节点的同一个端口上运行多个服务。

如果您有正在更改版本的后端(例如
在 etcd1 和 etcd2 之间转换)或任何其他情况
后端端口只需要不同。 问题是
Kubernetes 允许它被表达,所以我们需要确保人们
可以实际使用它(或者弃用它和 EOL 的功能
似乎不太可能)。

kubernetes 核心的挑战是找到方法来处理您的一般情况或避开您的方式
并授权您自行设置。 也许我们可以用 ipvs encap 模式做点什么,但我不知道性能
它的含义。

我们所做的是尽可能通用的(在这里工作,在亚马逊工作,我确定它会在
GCE 当我们需要扩展时),唯一的限制是运行在 pod/container 中的应用程序需要 > 运行在与服务相同的端口上,经过大量内部讨论,没有人能够找到一个场景
从 E2E 应用程序堆栈的角度来看,这将是一种限制。

我真的很想了解如何。 你有更多的步骤吗?

同样在 UDP 方面,感谢您的澄清; 直到现在,我才知道 kube-proxy 完全支持 UDP。
当我们第一次尝试使用 UDP 的 kube-proxy 时,我们遇到了很多问题。 不知道为什么,但我们确实增加了超时时间和
仍然有问题。 我们必须快速找到解决方案,因此我们最终使用 IPVS 解决了它,而不是调试它。 在
时间它只适用于非常低的每秒数据包工作负载(低于 1k pps),但我们最近没有重新测试。

iptables 和任何高速 UDP 服务的主要问题是 netfilter conntrack 表被填满。 即使你增加
conntrack 大小为 100 万,然后某些受恶意软件感染的最终用户 DDoS 会攻击您或试图利用您进行 DNS 放大
攻击,然后您的 conntrack 表再次填满。 一般来说,DNS 服务器(或任何高速率
UDP 服务)是禁用 conntrack(在原始表中使用 -j NOTRACK),如果禁用 conntrack,iptables NAT 和
有状态的东西(-m 状态)中断。

是的,UDP 的 NAT 真的很不幸。 寻找一个非conntrack
解决方案会很棒,但它必须适用于所有
环境或由平台参数化(这本身就很难
道路)。

除了 GIT 存储库之外,在尝试创建一个
“k8s.io/kubernetes/pkg/proxy/ipvs”模块/包? 还是最好留给更了解代码库的人?

我打开了一个关于 IPVS 的 github 问题,但我使用的是伪装(NAT)
模式,因为我无法在没有(并且由于
端口重映射功能)。 如果端口重新映射触发了不太理想的
平衡模式,我可能会接受并记录它
像这样。

我们应该把这个车队搬到那里——它会在这里迷路。

在 2016 年 1 月 18 日下午 12:34,Tim Hockin 写道:

是的,UDP 的 NAT 真的很不幸。 寻找一个非conntrack
解决方案会很棒,但它必须适用于所有
环境或由平台参数化(这本身就很难
道路)。

无状态 NAT 可以用于 (pod, port) 对在
大多数一项服务(多项服务对一项服务)?

这看起来像这样:

{from: clientIP:clientPort, to: externalIP:externalPort} ---[代理选择一个随机的pod]---> {from: clientIP:clientPort, to: podIP:targetPort} ---> [通过正确的主机路由...]

在回来的路上,防火墙会有一个规则说一个数据包{来自:
podIP:targetPort , to: any} 应该被 SNAT 转换为 {from:
e xternalIP:externalPort , to: 不变}。

用 iptables 方言来说明:

iptables -t nat -N stateless-svc-in

iptables -t nat -N stateless-svc-out

iptables -t nat -A stateless-svc-in  -j DNAT -s 1.2.3.4  -p udp --dport 53 --to-destination 10.1.0.1 -m statistic --mode random --probability 0.3333

iptables -t nat -A stateless-svc-in  -j DNAT -s 1.2.3.4  -p udp --dport 53 --to-destination 10.2.0.1 -m statistic --mode random --probability 0.5

iptables -t nat -A stateless-svc-in  -j DNAT -s 1.2.3.4  -p udp --dport 53 --to-destination 10.2.0.2 -m statistic --mode random --probability 1

iptables -t nat -A stateless-svc-out -j SNAT -s 10.1.0.1 -p udp --sport 53 --to-source 1.2.3.4

iptables -t nat -A stateless-svc-out -j SNAT -s 10.2.0.1 -p udp --sport 53 --to-source 1.2.3.4

iptables -t nat -A stateless-svc-out -j SNAT -s 10.2.0.2 -p udp --sport 53 --to-source 1.2.3.4

当数据包来自外部时,我看不出这在哪里不起作用
集群。

服务在 Kubernetes 中的表达方式允许单个 pod
前面有任意数量的服务,所以这会崩溃 - 我们不知道是什么
到 SNAT 到。

2016 年 1 月 17 日星期日下午 6:13,Mikaël Cluseau通知@github.com
写道:

在 2016 年 1 月 18 日下午 12:34,Tim Hockin 写道:

是的,UDP 的 NAT 真的很不幸。 寻找一个非conntrack
解决方案会很棒,但它必须适用于所有
环境或由平台参数化(这本身就很难
道路)。

无状态 NAT 可以用于 (pod, port) 对在
大多数一项服务(多项服务对一项服务)?

这看起来像这样:

{from: clientIP:clientPort, to: externalIP:externalPort} ---[代理选择
一个随机的 pod]---> {from: clientIP:clientPort, to: podIP:targetPort} --->
[通过正确的主机路由...]

在回来的路上,防火墙会有一个规则说一个数据包{来自:
podIP:targetPort , to: any} 应该被 SNAT 转换为 {from:
e xternalIP:externalPort , to: 不变}。

用 iptables 方言来说明:

iptables -t nat -N stateless-svc-in

iptables -t nat -N stateless-svc-out

iptables -t nat -A stateless-svc-in -j DNAT -s 1.2.3.4 -p udp --dport 53
--to-destination 10.1.0.1 -m statistic --mode random --probability 0.3333

iptables -t nat -A stateless-svc-in -j DNAT -s 1.2.3.4 -p udp --dport 53
--to-destination 10.2.0.1 -m statistic --mode random --probability 0.5

iptables -t nat -A stateless-svc-in -j DNAT -s 1.2.3.4 -p udp --dport 53
--to-destination 10.2.0.2 -m statistic --mode random --probability 1

iptables -t nat -A stateless-svc-out -j SNAT -s 10.1.0.1 -p udp --sport 53
--to-source 1.2.3.4

iptables -t nat -A stateless-svc-out -j SNAT -s 10.2.0.1 -p udp --sport 53
--to-source 1.2.3.4

iptables -t nat -A stateless-svc-out -j SNAT -s 10.2.0.2 -p udp --sport 53
--to-source 1.2.3.4

当数据包来自外部时,我看不出这在哪里不起作用
集群。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172408290
.

在 2016 年 1 月 18 日下午 03:31,蒂姆·霍金写道:

服务在 Kubernetes 中的表达方式允许单个 pod
成为
前面有任意数量的服务,所以这会崩溃 - 我们不知道
什么
到 SNAT 到。

这就是为什么我将案例限制为多对一(我的第一句话:-))。
我只是想在可以做什么或不能做什么周围划一条线。

当然,我只是有一个不幸的工作来指出为什么它不是一个
一般足够的解决方案:(

2016 年 1 月 17 日星期日晚上 8:34,Mikaël Cluseau通知@github.com
写道:

在 2016 年 1 月 18 日下午 03:31,蒂姆·霍金写道:

服务在 Kubernetes 中的表达方式允许单个 pod
成为
前面有任意数量的服务,所以这会崩溃 - 我们不知道
什么
到 SNAT 到。

这就是为什么我将案例限制为多对一(我的第一句话:-))。
我只是想在可以做什么或不能做什么周围划一条线。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172421828
.

在 01/18/2016 下午 03:46,Tim Hockin 写道:

当然,我只是有一个不幸的工作来指出为什么它不是一个
一般足够的解决方案:(

是的...但它是一个常见问题解答。 我们也可以在某处放置“if len(services)
== 1 { 实现无状态} else { 实现有状态}”。但这可能
对新手来说看起来一团糟。 我也可以成为一个贡献者/elbs/东西...

这甚至不是我们目前跟踪的东西(服务的数量
在给定的吊舱前面)。 我们可以,我想。 我不反对它(即使它
似乎利基)。 这听起来像是一个实质性的改变
许多警告。 我仍然想考虑更好的答案。

2016 年 1 月 17 日星期日晚上 8:51,Mikaël Cluseau通知@github.com
写道:

在 01/18/2016 下午 03:46,Tim Hockin 写道:

当然,我只是有一个不幸的工作来指出为什么它不是一个
一般足够的解决方案:(

是的...但它是一个常见问题解答。 我们也可以在某处放置“if len(services)
== 1 { 实现无状态} else { 实现有状态}”。但这可能
对新手来说看起来一团糟。 我也可以是一个
贡献/elbs/东西...


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172425404
.

在 01/18/2016 下午 04:07,蒂姆·霍金写道:

这甚至不是我们目前跟踪的东西(服务的数量
在给定的吊舱前面)。 我们可以,我想。 我不反对它(即使它
似乎利基)。 这听起来像是一个实质性的改变
许多警告。 我仍然想考虑更好的答案。

我同意,但现在没有更好的主意:-(

即使是专门构建的 SDN 也需要跟踪我想的东西。 也许
基于标签的解决方案,如 MPLS ..?

在 01/18/2016 下午 04:18,Mikaël Cluseau 写道:

即使是专门构建的 SDN 也需要跟踪我想的东西。
也许基于标签的解决方案,如 MPLS ..?

在标记事物的想法中……如果我们为每个服务分配一个 IP + 一个
每个端点的 IP(服务 + pod 对),并将这些端点 IP 添加到
pods,它应该完全无状态地工作:

``````

  • 外部到主机:{from: clientIP:clientPort, to: externalIP:servicePort} -----[ELB
    选择一个端点]--------> {from: clientIP:clientPort, to:
    endpointServiceIP:podPort} --> 路由到主机
  • 主机到 pod:{from: clientIP:clientPort, to: endpointServiceIP:podPort} --[标准
    路由到容器]--> {from: clientIP:clientPort , to:
    端点服务IP:podPort }

  • Pod 到主机:{from: endpointServiceIP:podPort, to: clientIP:clientPort}
    --------[到路由器的标准路由]-----> {来自:
    endpointServiceIP:podPort, to: clientIP:clientPort} - Host to external:{from: endpointServiceIP:podPort, to: clientIP:clientPort} --------[ELB
    SNATs back]-----------------> {from: clientIP:clientPort , to:
    e外部IP:servicePort } ```

它认为我们也可以为 clusterIP 进行这项工作。
``````

我无法在 GCE 上完成这项工作,而且我不确定 AWS - 有一个
可用的静态路由数量有限。

我想知道我是否可以通过将 2 个 IP 范围放在一个单一的范围内来做到这一点
路线。 要花费很多 IP,但我想它只对 UDP 重要。
我得试试看。

编辑:我试过了,但不能让它工作,但我错过了一些东西。
我们必须在容器中添加/删除 IP 以响应即将到来的服务
并且继续,但我无法在容器中制作“额外”IP(它可以
ping 但不是 TCP 或 UDP,不知道为什么)。

有时间我得再试一次。

2016 年 1 月 17 日星期日晚上 10:22,Mikaël Cluseau通知@github.com
写道:

在 01/18/2016 下午 04:18,Mikaël Cluseau 写道:

即使是专门构建的 SDN 也需要跟踪我想的东西。
也许基于标签的解决方案,如 MPLS ..?

在标记事物的想法中……如果我们为每个服务分配一个 IP + 一个
每个端点的 IP(服务 + pod 对),并将这些端点 IP 添加到
pods,它应该完全无状态地工作:

``````

  • 外部到主机:{from: clientIP:clientPort, to: externalIP:servicePort}
    -----[ELB
    选择一个端点]--------> {from: clientIP:clientPort, to:
    endpointServiceIP:podPort} --> 路由到主机
  • 主机到 pod:{from: clientIP:clientPort, to: endpointServiceIP:podPort}
    - [标准
    路由到容器]--> {from: clientIP:clientPort , to:
    端点服务IP:podPort }

  • Pod 到主机:{from: endpointServiceIP:podPort, to: clientIP:clientPort}
    --------[到路由器的标准路由]-----> {来自:
    endpointServiceIP:podPort, to: clientIP:clientPort} - 主机到
    外部:{来自:endpointServiceIP:podPort,至:clientIP:clientPort}
    --------[ELB
    SNATs back]-----------------> {from: clientIP:clientPort , to:
    e外部IP:servicePort } ```

它认为我们也可以为 clusterIP 进行这项工作。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment-172438133
.

``````

我正在尝试在我这边得到一些东西(在我的本地主机上使用纯 netns
目前)。

我正在尝试一种方法来影响主机的服务 IP 范围
减少路由条目的数量:

cli——elb——h1——c1

| `--- c2

`--- h2 -- c2

h1_ep_ip_ranges=( 10.1.1.0/24 10.1.2.0/24 )
h2_ep_ip_ranges=( 10.1.3.0/24 )

没有 ping ATM(数据包不通过 PREROUTING 链......),以及
需要睡觉。 明天再谈;)

在 2016 年 1 月 18 日下午 06:28,Tim Hockin 写道:

我无法在 GCE 上完成这项工作,而且我不确定 AWS - 有一个
可用的静态路由数量有限。

我想知道我是否可以通过将 2 个 IP 范围放在一个单一的范围内来做到这一点
路线。 要花费很多 IP,但我想它只对 UDP 重要。
我得试试看。

编辑:我试过了,但不能让它工作,但我错过了一些东西。
我们必须在容器中添加/删除 IP 以响应即将到来的服务
并且继续,但我无法在容器中制作“额外”IP(它可以
ping 但不是 TCP 或 UDP,不知道为什么)。

有时间我得再试一次。

我走得更远了,但我应该预料到的事情发生了。

我设置了一个以 10.244.2.8/25 作为主界面和 10.244.2.250/25 的 pod
作为其“in-a-service”接口。 我希望我可以将 UDP 发送到
.250 并检测响应,对它们进行 SNAT。 但是当然,如​​果客户是
不在同一个/25(不可能是)默认路由开始,这
来自 .8 地址。 tcpdump 确认响应来自 .8
使用 UDP 时。

我又到了一个我不知道如何让它发挥作用的地方。 会觉得
更多关于它。

2016 年 1 月 18 日星期一上午 2:59,Mikaël Cluseau通知@github.com
写道:

我正在尝试在我这边得到一些东西(在我的本地主机上使用纯 netns
目前)。

我正在尝试一种方法来影响主机的服务 IP 范围
减少路由条目的数量:

cli——elb——h1——c1

| `--- c2

`--- h2 -- c2

h1_ep_ip_ranges=( 10.1.1.0/24 10.1.2.0/24 )
h2_ep_ip_ranges=( 10.1.3.0/24 )

没有 ping ATM(数据包不通过 PREROUTING 链......),以及
需要睡觉。 明天再谈;)

在 2016 年 1 月 18 日下午 06:28,Tim Hockin 写道:

我无法在 GCE 上完成这项工作,而且我不确定 AWS - 有一个
可用的静态路由数量有限。

我想知道我是否可以通过将 2 个 IP 范围一起放在一个
单身的
路线。 要花费很多 IP,但我想它只对 UDP 重要。
我得试试看。

编辑:我试过了,但不能让它工作,但我想念
某物。
我们必须在容器中添加/删除 IP 以响应即将到来的服务
并且继续,但我无法在容器中制作“额外”IP(它可以
ping 但不是 TCP 或 UDP,不知道为什么)。

有时间我得再试一次。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172497456
.

我(通过 Abhishek)突然意识到,即使这行得通,我们仍然必须
轨道在某处流动,所以无论如何它最终都不是无状态的。

2016 年 1 月 18 日星期一晚上 9:50,Tim Hockin [email protected]写道:

我走得更远了,但我应该预料到的事情发生了。

我设置了一个以 10.244.2.8/25 作为主界面的 pod
10.244.2.250/25 作为其“in-a-service”接口。 我希望我
可以将 UDP 发送到 .250 并检测响应,以对它们进行 SNAT。 但是当然,
如果客户端不在同一个 /25(它不能是)默认值
路由开始,它来自 .8 地址。 tcpdump 确认
使用 UDP 时,响应来自 0.8。

我又到了一个我不知道如何让它发挥作用的地方。 会觉得
更多关于它。

2016 年 1 月 18 日星期一上午 2:59,Mikaël Cluseau通知@github.com
写道:

我正在尝试在我这边得到一些东西(在我的本地主机上使用纯 netns
目前)。

我正在尝试一种方法来影响主机的服务 IP 范围
减少路由条目的数量:

cli——elb——h1——c1

| `--- c2

`--- h2 -- c2

h1_ep_ip_ranges=( 10.1.1.0/24 10.1.2.0/24 )
h2_ep_ip_ranges=( 10.1.3.0/24 )

没有 ping ATM(数据包不通过 PREROUTING 链......),以及
需要睡觉。 明天再谈;)

在 2016 年 1 月 18 日下午 06:28,Tim Hockin 写道:

我无法在 GCE 上完成这项工作,而且我不确定 AWS - 有一个
可用的静态路由数量有限。

我想知道我是否可以通过将 2 个 IP 范围一起放在一个
单身的
路线。 要花费很多 IP,但我想它只对 UDP 重要。
我得试试看。

编辑:我试过了,但不能让它工作,但我想念
某物。
我们必须在容器中添加/删除 IP 以响应服务
未来
并且继续,但我无法在容器中制作“额外”IP(它
可以
ping 但不是 TCP 或 UDP,不知道为什么)。

有时间我得再试一次。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -172497456
.

这很不幸:-(顺便说一下,不知道为什么。然后我会用 MPLS 尝试一些东西,无论如何我都想学习它。

如果您有 2 个 Service 后端并且您想要发送多个
数据包,您需要以某种方式跟踪流量,不是吗? 或者你是
假设在不同的后端喷射数据包是安全的?

2016 年 1 月 20 日,星期三,下午 12:24,Mikaël Cluseau通知@github.com
写道:

这很不幸 :-( 顺便说一下不知道为什么。我会尝试一些
那么MPLS,反正我也想学。


直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -173348973
.

我有点假设对于 UDP 工作负载,是的。 即使对于 UDP,也可以选择无状态。 @qoke对此有何评论?

此外,我们可以使用诸如客户端 IP 哈希之类的方法来使流更稳定,同时仍然保持平衡(我不知道我们是否可以称之为“某种跟踪”:-))。

@MikaelCluseau我们使用默认的 IPVS 行为,它做了一些非常轻量级的 UDP“粘性”......

对于调度 UDP 数据报,IPVS 负载均衡器记录 UDP 数据报调度,可配置超时时间,默认 UDP 超时时间为 300 秒。 在 UDP 连接超时之前,来自同一套接字(协议、IP 地址和端口)的所有 UDP 数据报将被定向到同一服务器。

-- 引自http://kb.linuxvirtualserver.org/wiki/IPVS

当然,这只适用于有多个客户端与单个服务通信,或者单个客户端具有不同源端口的情况。 如果您有一个大容量客户端,所有客户端都从同一个源端口发送流量,并且您希望在多个后端上对其进行负载平衡,那么您可能更喜欢使用无状态/喷雾和祈祷方法。

我们对大量 DNS 和 RADIUS 流量进行负载平衡 - DNS 通常属于第一类(大量客户端,或具有大量源端口的客户端),而 RADIUS 通常属于后一类(很少客户端,大量数据包都来自相同的 IP/端口)。 我们没有对 RADIUS 使用无状态散列,而是决定随机化源端口以获得均匀分布。

在阅读了整个线程后,我仍然无法弄清楚为 kube-proxy 激活 iptables 模式是否应该解决隐藏外部 IP 的问题(#10921)。 我们确实按照此处的建议使用 v1.1 启用了 iptables 模式,但我们仍然看到来自集群的 IP,而不是来自用户的真实 IP。

我们的集群在 GCE 中,在上线之前我们只需要一个支持 HTTPS 的负载均衡器。 由于 GCE 不支持 v.1.2 alpha,我们不能使用新的 Ingress(AFAIK 支持 HTTPS 负载均衡器),因此网络负载均衡器是我们唯一的选择。 但显然,如果没有记录用户真实 ip 的能力,我们就无法上线。

对此新用户的一些澄清将不胜感激。 对我们中的许多人来说,支持 HTTPS 是强制性的。 谢谢!

我一直在使用 iptables 代理打开和关闭一段时间,可以确认客户端的外部 IP 仍然是隐藏/显示集群 IP。

到目前为止,我们已经通过运行在主机网络模式下运行的前端 HTTP/HTTPS 代理来解决这个问题,以便它看到源 IP 地址。

@maclof感谢您的反馈。 你能分享更多关于你的解决方法的信息吗? 在主机网络中运行的 HTTP/HTTPS 是什么意思?

@javiercr我们使用如下的 pod 规范: http : //pastie.org/private/zpdelblsob654zif7xus5g

使用主机网络意味着 Pod 运行在主机网络中,而不是被分配一个集群 IP。

这意味着当我们的 nginx 服务器绑定到端口 80/443 时,它将侦听主机 IP 并查看源 IP 地址。

我正在使用 kubernetes 1.1, /opt/bin/kube-proxy ... --proxy-mode=iptables --masquerade-all=false并通过具有 kube-proxy 的主机路由集群 IP 网络。 在此设置中,我的服务正在查看外部 IP。 我使用一个高度可用的网络命名空间,它有一个外部 IP 和一个到主机的路由:

I0221 01:20:32.695440       1 main.go:224] <A6GSXEKN> Connection from 202.22.xxx.yyy:51954 closed.

读了这篇文章,我学到了很多!

作为仅供参考,该文档指出 AWS ELB 对 TCP 连接使用循环,对 http/https 使用最少连接: http :

我同意专注于仅将请求发送到运行 Pod 的节点并尝试为本地 Pod 提供服务是最好的方法。 这样做的好处是集群内的节点到节点流量会更少,我想通过始终为从服务到 pod 的本地请求提供服务来改善延迟(我猜如果您有节点,这会带来更多好处)同一集群中的多个可用区)。

在使用不支持加权的负载均衡器方面,您可以通过复制控制器来解决这个问题,方法是尝试始终在一个节点上保持相同数量的 pod(如果每个节点有 1 个以上),然后在它们之间平均分配它们,即使这意味着在某些情况下必须将 pod 移出节点并且只允许某些副本计数。 例如,对于具有连接到负载均衡器的服务的 4 节点集群,可接受的 pod 副本的唯一数量是 1、2、3、4、6、8、9、12、16、20 等

我们还希望解决仅路由到本地 Pod 的流量问题。 有时,当本地没有服务的 pod 时,nodeport 会在节点上消失。 这样,一个简单的负载均衡器 TCP 健康检查将阻止请求发送到这些节点。 我认为,如果我们至少可以解决 iptables\kube-proxy 部分的问题,那么我们就会发现当 pod 没有跨集群平衡时负载平衡的影响是什么。 我认为有一些方法可以在负载平衡器上解决这个问题,而不必为每个节点设置一个带有 API 调用的权重。

负载均衡器已经使用其他动态方法来处理这个问题。 此外,根据您正在运行的服务在该容器内为每个 api 调用实际执行的操作,当节点上有 2 个 pod 时,它可能无法支持 2 倍的流量,而无论如何。 如果设置了 Kubernetes 限制,并且如果在 podnode 上达到最大使用水平,也可能会影响到这一点,这会增加另一层复杂性,试图在外部负载均衡器上找到正确的权重设置。

我想说的是,远离那种复杂程度,不要尝试从 kubernetes 设置负载均衡器的权重。

@yoshiwaan我可以建议为节点间流量建议开一个新问题吗,因为这个问题现已关闭。 我个人认为一个好的第一步是确保 _if_ 一个 pod 在本地节点上运行,我们路由到本地 pod。 我怀疑这已经足够了,因为您可以扩展您的 RC,以便在每个节点上都有 pod。

@justinsb +1,我们现在也

这可能太天真了,但我想知道用户空间模式和 iptables 之间有什么区别? 我无法从用户 doc 中分辨出来。

用户态模式意味着 kube-proxy 通过接收来自客户端的连接请求并打开一个到服务器的套接字来处理连接本身,这 (1) 消耗更多的 CPU 和内存 (2) 受限于单个可以使用的端口数打开(<65k)。 iptables 模式工作在较低级别的内核中,并使用连接跟踪代替,因此它更轻巧并处理更多连接*。

(edit) (*) 只要您不通过 SNAT 数据包,这反过来又需要进行设置,您可以确保数据包将穿过与其关联的连接跟踪规则。 例如,使用路由访问设计可以避免 SNAT,这意味着服务的端点将看到真实客户端的 IP。

@MikaelCluseau
这意味着 kube-proxy 只负责设置和维护 iptables 规则,我们不再为 iptables 模式下的每个服务获取随机本地端口,对吗?

于 04/19/2016 下午 10:51,Emma He 写道:

意思是 kube-proxy 只负责设置和维护
iptables,我们不再为每个服务获得随机本地端口
iptables 模式,对吧?

是的。

抱歉,我之前完全错过了。

(edit) (*) 只要您不通过 SNAT 数据包,这反过来又需要进行设置,您可以确保数据包将穿过与其关联的连接跟踪规则。 例如,使用路由访问设计可以避免 SNAT,这意味着服务的端点将看到真实客户端的 IP。

@MikaelCluseau我在想 iptables 采用 SNAT 和 DNAT,根据您的说法,情况并非如此。 你能帮我澄清一下吗?

在 04/20/2016 下午 01:59,Emma He 写道:

@MikaelCluseau https://github.com/MikaelCluseau我在想
iptables 采用 SNAT 和 DNAT,你说的不是这种情况。
你能帮我澄清一下吗?

这是棘手的部分。

(1) 使用服务/外部 IP 需要 DNAT。
(2) 如果您确定回复数据包将通过相同的 conntrack
规则(即相同的网络堆栈或复制的 conntrack 表),您
可以跳过 SNAT 部分(即 MASQUERADE 规则)。

(2)的条件在路由接入网设计中通常是可以的
(这是我能想到的最简单的设计)。

例如,给定

  • 客户端 1.0.1.1,
  • 服务 1.0.2.1,
  • 实现服务 1.0.3.1 的 pod。

然后,

  1. 你的路由器/防火墙/负载均衡器/主机/任何接收到数据包的东西
    对于该服务,它会看到一个数据包“1.0.1.1 -> 1.0.2.1”;
  2. 它将 DNAT 传输到端点(pod),因此数据包将是“1.0.1.1 ->
    集群网络中的1.0.3.1";
  3. pod 回复一个数据包“1.0.3.1 -> 1.0.1.1”;
  4. 数据包通过路由器/防火墙/负载均衡器/主机/任何
    有了conntrack规则,conntrack系统重写数据包
    在将其发送回客户端之前将其设置为“1.0.2.1 -> 1.0.1.1”。

如果不能满足(2)的条件,则必须使用 SNAT/MASQUERADING
以确保数据包将通过
路由器/防火墙/负载均衡器/主机/任何连接跟踪。

@MikaelCluseau - 在 google.com 上以我的 github 名称给我发一封电子邮件 - 我有
给你的东西

2016 年 4 月 19 日,星期二,晚上 8:20,Mikaël Cluseau通知@github.com
写道:

在 04/20/2016 下午 01:59,Emma He 写道:

@MikaelCluseau https://github.com/MikaelCluseau我在想
iptables 采用 SNAT 和 DNAT,你说的不是这种情况。
你能帮我澄清一下吗?

这是棘手的部分。

(1) 使用服务/外部 IP 需要 DNAT。
(2) 如果您确定回复数据包将通过相同的 conntrack
规则(即相同的网络堆栈或复制的 conntrack 表),您
可以跳过 SNAT 部分(即 MASQUERADE 规则)。

(2)的条件在路由接入网设计中通常是可以的
(这是我能想到的最简单的设计)。

例如,给定

  • 客户端 1.0.1.1,
  • 服务 1.0.2.1,
  • 实现服务 1.0.3.1 的 pod。

然后,

  1. 你的路由器/防火墙/负载均衡器/主机/任何接收到数据包的东西
    对于该服务,它会看到一个数据包“1.0.1.1 -> 1.0.2.1”;
  2. 它将 DNAT 传输到端点(pod),因此数据包将是“1.0.1.1 ->
    集群网络中的1.0.3.1";
  3. pod 回复一个数据包“1.0.3.1 -> 1.0.1.1”;
  4. 数据包通过路由器/防火墙/负载均衡器/主机/任何
    有了conntrack规则,conntrack系统重写数据包
    在将其发送回客户端之前将其设置为“1.0.2.1 -> 1.0.1.1”。

如果不能满足(2)的条件,则必须使用 SNAT/MASQUERADING
以确保数据包将通过
路由器/防火墙/负载均衡器/主机/任何连接跟踪。


你收到这个是因为你被提到了。
直接回复此邮件或在 GitHub 上查看
https://github.com/kubernetes/kubernetes/issues/3760#issuecomment -212230959

@justinsb @yoshiwaan 有没有人为此创建过问题? 我的搜索功能让我失望,我也有类似的需求。

我可以建议为节点间流量建议打开一个新问题,因为这个问题现已关闭。 我个人认为一个好的第一步是确保如果 Pod 在本地节点上运行,我们将路由到本地 Pod。 我怀疑这已经足够了,因为您可以扩展您的 RC,以便在每个节点上都有 pod。

我不是自己提出来的

啊哈,我想我找到了,这似乎是功能/修复: https :

从 1.5.x 开始似乎是测试版。

此页面是否有帮助?
0 / 5 - 0 等级