如何在没有转发规则的情况下将 kubernetes pod 连接到外部世界(google 容器引擎)
how to connect a kubernetes pod to the outside world without a forwarding rule (google container engine)
我正在使用 Google 的 Container Engine 服务,并且有一个 pod 运行ning 一个服务器侦听端口 3000。我设置服务以将端口 80 连接到该 pod 的端口3000. 我能够从节点内使用其本地和 public ip 卷曲服务,但不能从外部。我设置了一个防火墙规则以允许端口 80 并将其发送到节点,但我不断从网络外部收到 'connection refused'。我正在尝试在没有转发规则的情况下执行此操作,因为只有一个 pod,而且看起来转发规则会花钱并进行负载平衡。我认为防火墙规则有效,因为当我将 createExternalLoadBalancer: true
添加到服务规范时,转发规则创建的外部 IP 按预期工作。我需要做其他事情吗?设置路线什么的?
controller.yaml
kind: ReplicationController
apiVersion: v1beta3
metadata:
name: app-frontend
labels:
name: app-frontend
app: app
role: frontend
spec:
replicas: 1
selector:
name: app-frontend
template:
metadata:
labels:
name: app-frontend
app: app
role: frontend
spec:
containers:
- name: node-frontend
image: gcr.io/project_id/app-frontend
ports:
- name: app-frontend-port
containerPort: 3000
targetPort: 3000
protocol: TCP
service.yaml
kind: Service
apiVersion: v1beta3
metadata:
name: app-frontend-service
labels:
name: app-frontend-service
app: app
role: frontend
spec:
ports:
- port: 80
targetPort: app-frontend-port
protocol: TCP
publicIPs:
- 123.45.67.89
selector:
name: app-frontend
编辑(其他详细信息):
创建这个服务添加了这些额外的规则,当我 运行 iptables -L -t nat
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- anywhere 10.247.247.206 /* default/app-frontend-service: */ tcp dpt:http redir ports 56859
REDIRECT tcp -- anywhere 89.67.45.123.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http redir ports 56859
Chain KUBE-PORTALS-HOST (1 references)
target prot opt source destination
DNAT tcp -- anywhere 10.247.247.206 /* default/app-frontend-service: */ tcp dpt:http to:10.241.69.28:56859
DNAT tcp -- anywhere 89.67.45.123.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http to:10.241.69.28:56859
我不是很了解iptables,所以我不确定目标端口如何匹配我的服务。我发现 89.67.45.123.bc.googleusercontent.com
的 DNS 解析为 123.45.67.89
。
kubectl get services 显示我指定的 IP 地址和端口:
NAME IP(S) PORT(S)
app-frontend-service 10.247.243.151 80/TCP
123.45.67.89
/var/log/kube-proxy.log
中未显示来自外部 IP 的最新信息
如果您将节点的外部 IP 地址添加到服务的 publicIPs
字段,您应该能够通过节点的 IP 地址访问它。如果您的集群有多个节点,并且您希望在其中任何一个节点上启用对 pod 的访问,则可以将多个节点的 IP 地址放入字段中。
在即将发布的版本中,将有一个更简单的内置选项,用于在没有负载平衡器的情况下设置外部服务。如果您对此感到好奇或在将来某个时候阅读此内容,请查看 this doc 的更新 "External Services" 部分,了解如何使用 NodePort
来完成同样的事情更容易。
TL;DR:使用节点的内部 IP 作为服务定义中的 public IP。
如果您在 kube-proxy 上启用详细日志记录,您会看到它似乎正在创建适当的 IP 表规则:
I0602 04:07:32.046823 24360 roundrobin.go:98] LoadBalancerRR service "default/app-frontend-service:" did not exist, created
I0602 04:07:32.047153 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 10.119.244.130/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.048446 24360 proxier.go:606] Opened iptables from-host portal for service "default/app-frontend-service:" on TCP 10.119.244.130:80
I0602 04:07:32.049525 24360 iptables.go:186] running iptables -C [KUBE-PORTALS-CONTAINER -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j REDIRECT --to-ports 36970]
I0602 04:07:32.050872 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-CONTAINER -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j REDIRECT --to-ports 36970]
I0602 04:07:32.052247 24360 proxier.go:595] Opened iptables from-containers portal for service "default/app-frontend-service:" on TCP 23.251.156.36:80
I0602 04:07:32.053222 24360 iptables.go:186] running iptables -C [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.054491 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.055848 24360 proxier.go:606] Opened iptables from-host portal for service "default/app-frontend-service:" on TCP 23.251.156.36:80
使用 -L -t
列出 iptables 条目显示 public IP 已转换为反向 DNS 名称,如您所见:
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- anywhere 10.119.240.2 /* default/kubernetes: */ tcp dpt:https redir ports 50353
REDIRECT tcp -- anywhere 10.119.240.1 /* default/kubernetes-ro: */ tcp dpt:http redir ports 54605
REDIRECT udp -- anywhere 10.119.240.10 /* default/kube-dns:dns */ udp dpt:domain redir ports 37723
REDIRECT tcp -- anywhere 10.119.240.10 /* default/kube-dns:dns-tcp */ tcp dpt:domain redir ports 50126
REDIRECT tcp -- anywhere 10.119.244.130 /* default/app-frontend-service: */ tcp dpt:http redir ports 36970
REDIRECT tcp -- anywhere 36.156.251.23.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http redir ports 36970
但是添加 -n
选项会显示 IP 地址(默认情况下,-L
会对 IP 地址进行反向查找,这就是您看到 DNS 名称的原因):
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 10.119.240.2 /* default/kubernetes: */ tcp dpt:443 redir ports 50353
REDIRECT tcp -- 0.0.0.0/0 10.119.240.1 /* default/kubernetes-ro: */ tcp dpt:80 redir ports 54605
REDIRECT udp -- 0.0.0.0/0 10.119.240.10 /* default/kube-dns:dns */ udp dpt:53 redir ports 37723
REDIRECT tcp -- 0.0.0.0/0 10.119.240.10 /* default/kube-dns:dns-tcp */ tcp dpt:53 redir ports 50126
REDIRECT tcp -- 0.0.0.0/0 10.119.244.130 /* default/app-frontend-service: */ tcp dpt:80 redir ports 36970
REDIRECT tcp -- 0.0.0.0/0 23.251.156.36 /* default/app-frontend-service: */ tcp dpt:80 redir ports 36970
此时,您可以使用内部和外部 IP 从集群内部访问该服务:
$ curl 10.119.244.130:80
app-frontend-5pl5s
$ curl 23.251.156.36:80
app-frontend-5pl5s
在不添加防火墙规则的情况下,尝试远程连接到 public ip 会超时。如果您添加防火墙规则,那么您将可靠地拒绝连接:
$ curl 23.251.156.36
curl: (7) Failed to connect to 23.251.156.36 port 80: Connection refused
如果启用某些 iptables 日志记录:
sudo iptables -t nat -I KUBE-PORTALS-CONTAINER -m tcp -p tcp --dport
80 -j LOG --log-prefix "WTF: "
然后 grep dmesg
的输出 WTF
很明显,数据包到达 10. VM 的 IP 地址,而不是已设置为的临时外部 IP 地址服务上的 public IP。
原来问题出在GCE有两种外部IP:ForwardingRules(转发时DSTIP原封不动)和1-to-1 NAT(实际上是将DSTIP重写为内部IP)。 VM 的外部 IP 是后一种类型,因此当节点接收到 IP 表规则不匹配的数据包时。
修复实际上非常简单(但不直观):使用节点的内部 IP 作为服务定义中的 public IP。在更新您的 service.yaml 文件以将 publicIPs 设置为内部 IP(例如 10.240.121.42
)之后,您将能够从 GCE 网络外部访问您的应用程序。
@Robert Bailey 的回答绝对正确。 publicIPs 已在 kubernetes 1.5.1 中弃用,您可以改用 externalIPs。
- 获取节点内部ip,
kubectl describe node | grep Address
Addresses: 10.119.244.130,101.192.150.200,gke-...
或者你可以运行节点终端里面的ifconfig eth0
获取内部ip
设置ip在service.yaml
spec:
type: NodePort
externalIPs:
- 10.119.244.130
- 可以卷曲并解决测试
curl --resolve 'example.com:443:23.251.156.36' https://example.com -k
我正在使用 Google 的 Container Engine 服务,并且有一个 pod 运行ning 一个服务器侦听端口 3000。我设置服务以将端口 80 连接到该 pod 的端口3000. 我能够从节点内使用其本地和 public ip 卷曲服务,但不能从外部。我设置了一个防火墙规则以允许端口 80 并将其发送到节点,但我不断从网络外部收到 'connection refused'。我正在尝试在没有转发规则的情况下执行此操作,因为只有一个 pod,而且看起来转发规则会花钱并进行负载平衡。我认为防火墙规则有效,因为当我将 createExternalLoadBalancer: true
添加到服务规范时,转发规则创建的外部 IP 按预期工作。我需要做其他事情吗?设置路线什么的?
controller.yaml
kind: ReplicationController
apiVersion: v1beta3
metadata:
name: app-frontend
labels:
name: app-frontend
app: app
role: frontend
spec:
replicas: 1
selector:
name: app-frontend
template:
metadata:
labels:
name: app-frontend
app: app
role: frontend
spec:
containers:
- name: node-frontend
image: gcr.io/project_id/app-frontend
ports:
- name: app-frontend-port
containerPort: 3000
targetPort: 3000
protocol: TCP
service.yaml
kind: Service
apiVersion: v1beta3
metadata:
name: app-frontend-service
labels:
name: app-frontend-service
app: app
role: frontend
spec:
ports:
- port: 80
targetPort: app-frontend-port
protocol: TCP
publicIPs:
- 123.45.67.89
selector:
name: app-frontend
编辑(其他详细信息):
创建这个服务添加了这些额外的规则,当我 运行 iptables -L -t nat
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- anywhere 10.247.247.206 /* default/app-frontend-service: */ tcp dpt:http redir ports 56859
REDIRECT tcp -- anywhere 89.67.45.123.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http redir ports 56859
Chain KUBE-PORTALS-HOST (1 references)
target prot opt source destination
DNAT tcp -- anywhere 10.247.247.206 /* default/app-frontend-service: */ tcp dpt:http to:10.241.69.28:56859
DNAT tcp -- anywhere 89.67.45.123.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http to:10.241.69.28:56859
我不是很了解iptables,所以我不确定目标端口如何匹配我的服务。我发现 89.67.45.123.bc.googleusercontent.com
的 DNS 解析为 123.45.67.89
。
kubectl get services 显示我指定的 IP 地址和端口:
NAME IP(S) PORT(S)
app-frontend-service 10.247.243.151 80/TCP
123.45.67.89
/var/log/kube-proxy.log
中未显示来自外部 IP 的最新信息如果您将节点的外部 IP 地址添加到服务的 publicIPs
字段,您应该能够通过节点的 IP 地址访问它。如果您的集群有多个节点,并且您希望在其中任何一个节点上启用对 pod 的访问,则可以将多个节点的 IP 地址放入字段中。
在即将发布的版本中,将有一个更简单的内置选项,用于在没有负载平衡器的情况下设置外部服务。如果您对此感到好奇或在将来某个时候阅读此内容,请查看 this doc 的更新 "External Services" 部分,了解如何使用 NodePort
来完成同样的事情更容易。
TL;DR:使用节点的内部 IP 作为服务定义中的 public IP。
如果您在 kube-proxy 上启用详细日志记录,您会看到它似乎正在创建适当的 IP 表规则:
I0602 04:07:32.046823 24360 roundrobin.go:98] LoadBalancerRR service "default/app-frontend-service:" did not exist, created
I0602 04:07:32.047153 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 10.119.244.130/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.048446 24360 proxier.go:606] Opened iptables from-host portal for service "default/app-frontend-service:" on TCP 10.119.244.130:80
I0602 04:07:32.049525 24360 iptables.go:186] running iptables -C [KUBE-PORTALS-CONTAINER -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j REDIRECT --to-ports 36970]
I0602 04:07:32.050872 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-CONTAINER -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j REDIRECT --to-ports 36970]
I0602 04:07:32.052247 24360 proxier.go:595] Opened iptables from-containers portal for service "default/app-frontend-service:" on TCP 23.251.156.36:80
I0602 04:07:32.053222 24360 iptables.go:186] running iptables -C [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.054491 24360 iptables.go:186] running iptables -A [KUBE-PORTALS-HOST -t nat -m comment --comment default/app-frontend-service: -p tcp -m tcp -d 23.251.156.36/32 --dport 80 -j DNAT --to-destination 10.240.121.42:36970]
I0602 04:07:32.055848 24360 proxier.go:606] Opened iptables from-host portal for service "default/app-frontend-service:" on TCP 23.251.156.36:80
使用 -L -t
列出 iptables 条目显示 public IP 已转换为反向 DNS 名称,如您所见:
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- anywhere 10.119.240.2 /* default/kubernetes: */ tcp dpt:https redir ports 50353
REDIRECT tcp -- anywhere 10.119.240.1 /* default/kubernetes-ro: */ tcp dpt:http redir ports 54605
REDIRECT udp -- anywhere 10.119.240.10 /* default/kube-dns:dns */ udp dpt:domain redir ports 37723
REDIRECT tcp -- anywhere 10.119.240.10 /* default/kube-dns:dns-tcp */ tcp dpt:domain redir ports 50126
REDIRECT tcp -- anywhere 10.119.244.130 /* default/app-frontend-service: */ tcp dpt:http redir ports 36970
REDIRECT tcp -- anywhere 36.156.251.23.bc.googleusercontent.com /* default/app-frontend-service: */ tcp dpt:http redir ports 36970
但是添加 -n
选项会显示 IP 地址(默认情况下,-L
会对 IP 地址进行反向查找,这就是您看到 DNS 名称的原因):
Chain KUBE-PORTALS-CONTAINER (1 references)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 10.119.240.2 /* default/kubernetes: */ tcp dpt:443 redir ports 50353
REDIRECT tcp -- 0.0.0.0/0 10.119.240.1 /* default/kubernetes-ro: */ tcp dpt:80 redir ports 54605
REDIRECT udp -- 0.0.0.0/0 10.119.240.10 /* default/kube-dns:dns */ udp dpt:53 redir ports 37723
REDIRECT tcp -- 0.0.0.0/0 10.119.240.10 /* default/kube-dns:dns-tcp */ tcp dpt:53 redir ports 50126
REDIRECT tcp -- 0.0.0.0/0 10.119.244.130 /* default/app-frontend-service: */ tcp dpt:80 redir ports 36970
REDIRECT tcp -- 0.0.0.0/0 23.251.156.36 /* default/app-frontend-service: */ tcp dpt:80 redir ports 36970
此时,您可以使用内部和外部 IP 从集群内部访问该服务:
$ curl 10.119.244.130:80
app-frontend-5pl5s
$ curl 23.251.156.36:80
app-frontend-5pl5s
在不添加防火墙规则的情况下,尝试远程连接到 public ip 会超时。如果您添加防火墙规则,那么您将可靠地拒绝连接:
$ curl 23.251.156.36
curl: (7) Failed to connect to 23.251.156.36 port 80: Connection refused
如果启用某些 iptables 日志记录:
sudo iptables -t nat -I KUBE-PORTALS-CONTAINER -m tcp -p tcp --dport
80 -j LOG --log-prefix "WTF: "
然后 grep dmesg
的输出 WTF
很明显,数据包到达 10. VM 的 IP 地址,而不是已设置为的临时外部 IP 地址服务上的 public IP。
原来问题出在GCE有两种外部IP:ForwardingRules(转发时DSTIP原封不动)和1-to-1 NAT(实际上是将DSTIP重写为内部IP)。 VM 的外部 IP 是后一种类型,因此当节点接收到 IP 表规则不匹配的数据包时。
修复实际上非常简单(但不直观):使用节点的内部 IP 作为服务定义中的 public IP。在更新您的 service.yaml 文件以将 publicIPs 设置为内部 IP(例如 10.240.121.42
)之后,您将能够从 GCE 网络外部访问您的应用程序。
@Robert Bailey 的回答绝对正确。 publicIPs 已在 kubernetes 1.5.1 中弃用,您可以改用 externalIPs。
- 获取节点内部ip,
kubectl describe node | grep Address
Addresses: 10.119.244.130,101.192.150.200,gke-...
或者你可以运行节点终端里面的
ifconfig eth0
获取内部ip设置ip在service.yaml
spec: type: NodePort externalIPs: - 10.119.244.130
- 可以卷曲并解决测试
curl --resolve 'example.com:443:23.251.156.36' https://example.com -k