如何从外部网络访问

Kubernetes的Pod IP和Cluster IP都只能在集群内部访问,而我们通常需要从外部网络上访问集群中的某些服务,Kubernetes提供了下述几种方式来为集群提供外部流量入口。

NodePort

NodePort在集群中的主机节点上为Service提供一个代理端口,以允许从主机网络上对Service进行访问。Kubernetes官网文档只介绍了NodePort的功能,并未对其实现原理进行解释。下面我们通过实验来分析NodePort的实现机制。

www.katacoda.com 这个网站提供了一个交互式的Kubernetes playground,注册即可免费实验kubernetes的相关功能,下面我们就使用Katacoda来分析Nodeport的实现原理。

在浏览器中输入这个网址:https://www.katacoda.com/courses/kubernetes/networking-introduction, 打开后会提供了一个实验用的Kubernetes集群,并可以通过网元模拟Terminal连接到集群的Master节点。

执行下面的命令创建一个nodeport类型的service。

kubectl apply -f nodeport.yaml

查看创建的service,可以看到kubernetes创建了一个名为webapp-nodeport-svc的service,并为该service在主机节点上创建了30080这个Nodeport。

master $ kubectl get svc
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes             ClusterIP   10.96.0.1       <none>        443/TCP        36m
webapp1-nodeport-svc   NodePort    10.103.188.73   <none>        80:30080/TCP   3m

webapp-nodeport-svc后端对应两个Pod,其Pod的IP分别为10.32.0.3和10.32.0.5。

master $ kubectl get pod -o wide
NAME                                           READY     STATUS    RESTARTS   AGE       IPNODE      NOMINATED NODE
webapp1-nodeport-deployment-785989576b-cjc5b   1/1       Running   0          2m        10.32.0.3
webapp1-nodeport-deployment-785989576b-tpfqr   1/1       Running   0          2m        10.32.0.5

通过netstat命令可以看到Kube-proxy在主机网络上创建了30080监听端口,用于接收从主机网络进入的外部流量。

master $ netstat -lnp|grep 30080
tcp6       0      0 :::30080                :::*                    LISTEN      7427/kube-proxy

下面是Kube-proxy创建的相关iptables规则以及对应的说明。可以看到Kube-proxy为Nodeport创建了相应的IPtable规则,将发向30080这个主机端口上的流量重定向到了后端的两个Pod IP上。

iptables-save > iptables-dump
# Generated by iptables-save v1.6.0 on Thu Mar 28 07:33:57 2019
*nat
# Nodeport规则链
:KUBE-NODEPORTS - [0:0]
# Service规则链
:KUBE-SERVICES - [0:0]
# Nodeport和Service共用的规则链
:KUBE-SVC-J2DWGRZTH4C2LPA4 - [0:0]
:KUBE-SEP-4CGFRVESQ3AECDE7 - [0:0]
:KUBE-SEP-YLXG4RMKAICGY2B3 - [0:0]

# 将host上30080端口的外部tcp流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp --dport 30080 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到Cluster IP 10.103.188.73的内部流量转到KUBE-SVC-J2DWGRZTH4C2LPA4链
KUBE-SERVICES -d 10.103.188.73/32 -p tcp -m comment --comment "default/webapp1-nodeport-svc: cluster IP" -m tcp --dport 80 -j KUBE-SVC-J2DWGRZTH4C2LPA4

#将发送到webapp1-nodeport-svc的流量转交到第一个Pod(10.32.0.3)相关的规则链上,比例为50%
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-YLXG4RMKAICGY2B3
#将发送到webapp1-nodeport-svc的流量转交到第二个Pod(10.32.0.5)相关的规则链上
-A KUBE-SVC-J2DWGRZTH4C2LPA4 -m comment --comment "default/webapp1-nodeport-svc:" -j KUBE-SEP-4CGFRVESQ3AECDE7

#将请求重定向到Pod 10.32.0.3
-A KUBE-SEP-YLXG4RMKAICGY2B3 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.3:80
#将请求重定向到Pod 10.32.0.5
-A KUBE-SEP-4CGFRVESQ3AECDE7 -p tcp -m comment --comment "default/webapp1-nodeport-svc:" -m tcp -j DNAT --to-destination 10.32.0.5:80

从上面的实验可以看到,通过将一个Service定义为NodePort类型,Kubernetes会通过集群中node上的Kube-proxy为该Service在主机网络上创建一个监听端口。Kube-proxy并不会直接接收该主机端口进入的流量,而是会创建相应的Iptables规则,并通过Iptables将从该端口收到的流量直接转发到后端的Pod中。

NodePort的流量转发机制和Cluster IP的iptables模式类似,唯一不同之处是在主机网络上开了一个“NodePort”来接受外部流量。从上面的规则也可以看出,在创建Nodeport时,Kube-proxy也会同时为Service创建Cluster IP相关的iptables规则。

备注:除采用iptables进行流量转发,NodePort应该也可以提供userspace模式以及ipvs模式,这里未就这两种模式进行实验验证。

从分析得知,在NodePort模式下,集群内外部的通讯如下图所示:

NodePort
在这里插入图片描述

Logo

开源、云原生的融合云平台

更多推荐