NodePort 服务并非在所有节点上都可用
NodePort services not available on all nodes
我正在尝试 运行 一个 3 节点 Kubernetes 集群。我已经启动了集群并且 运行ning 足以让我在不同的节点上提供服务 运行ning。不幸的是,我似乎无法让基于 NodePort 的服务正常工作(反正我理解正确性......)。我的问题是,我定义的任何 NodePort 服务仅在它们的 pod 所在的节点上外部可用 运行ning,我的理解是它们应该在集群中的任何节点上外部可用。
一个例子是本地 Jira 服务,它应该 运行ning 在端口 8082(内部)和外部 32760 上。这是服务定义(只是服务部分):
apiVersion: v1
kind: Service
metadata:
name: jira
namespace: wittlesouth
spec:
ports:
- port: 8082
selector:
app: jira
type: NodePort
这是 kubectl get service --namespace wittle south 的输出
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.100.119.22 <none> 8081:31377/TCP 3d
jira NodePort 10.105.148.66 <none> 8082:32760/TCP 9h
ws-mysql ExternalName <none> mysql.default.svc.cluster.local 3306/TCP 1d
此服务的 pod 的 HostPort 设置为 8082。集群中的三个节点是 nuc1、nuc2、nuc3:
Eric:~ eric$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
nuc1 Ready master 3d v1.9.2
nuc2 Ready <none> 2d v1.9.2
nuc3 Ready <none> 2d v1.9.2
以下是尝试通过主机和节点端口访问 Jira 实例的结果:
Eric:~ eric$ curl https://nuc1.wittlesouth.com:8082/
curl: (7) Failed to connect to nuc1.wittlesouth.com port 8082: Connection refused
Eric:~ eric$ curl https://nuc2.wittlesouth.com:8082/
curl: (7) Failed to connect to nuc2.wittlesouth.com port 8082: Connection refused
Eric:~ eric$ curl https://nuc3.wittlesouth.com:8082/
curl: (51) SSL: no alternative certificate subject name matches target host name 'nuc3.wittlesouth.com'
Eric:~ eric$ curl https://nuc3.wittlesouth.com:32760/
curl: (51) SSL: no alternative certificate subject name matches target host name 'nuc3.wittlesouth.com'
Eric:~ eric$ curl https://nuc2.wittlesouth.com:32760/
^C
Eric:~ eric$ curl https://nuc1.wittlesouth.com:32760/
curl: (7) Failed to connect to nuc1.wittlesouth.com port 32760: Operation timed out
根据我的阅读,cube-proxy 似乎没有做它应该做的事情。我尝试阅读文档以解决 cube-proxy 问题,它似乎有点过时(当我在 iptables-save 中 grep 主机名时,它什么也没找到)。这是 kubernetes 版本信息:
Eric:~ eric$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.1", GitCommit:"3a1c9449a956b6026f075fa3134ff92f7d55f812", GitTreeState:"clean", BuildDate:"2018-01-04T11:52:23Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.2", GitCommit:"5fa2db2bd46ac79e5e00a4e6ed24191080aa463b", GitTreeState:"clean", BuildDate:"2018-01-18T09:42:01Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
看起来 kube-proxy 是 运行ning:
eric@nuc2:~$ ps waux | grep kube-proxy
root 1963 0.5 0.1 54992 37556 ? Ssl 21:43 0:02 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf
eric 3654 0.0 0.0 14224 1028 pts/0 S+ 21:52 0:00 grep --color=auto kube-proxy
和
Eric:~ eric$ kubectl get pods --namespace=kube-system
NAME READY STATUS RESTARTS AGE
calico-etcd-6vspc 1/1 Running 3 2d
calico-kube-controllers-d669cc78f-b67rc 1/1 Running 5 3d
calico-node-526md 2/2 Running 9 3d
calico-node-5trgt 2/2 Running 3 2d
calico-node-r9ww4 2/2 Running 3 2d
etcd-nuc1 1/1 Running 6 3d
kube-apiserver-nuc1 1/1 Running 7 3d
kube-controller-manager-nuc1 1/1 Running 6 3d
kube-dns-6f4fd4bdf-dt5fp 3/3 Running 12 3d
kube-proxy-8xf4r 1/1 Running 1 2d
kube-proxy-tq4wk 1/1 Running 4 3d
kube-proxy-wcsxt 1/1 Running 1 2d
kube-registry-proxy-cv8x9 1/1 Running 4 3d
kube-registry-proxy-khpdx 1/1 Running 1 2d
kube-registry-proxy-r5qcv 1/1 Running 1 2d
kube-registry-v0-wcs5w 1/1 Running 2 3d
kube-scheduler-nuc1 1/1 Running 6 3d
kubernetes-dashboard-845747bdd4-dp7gg 1/1 Running 4 3d
cube-proxy 似乎正在为我的服务创建 iptables 条目:
eric@nuc1:/var/lib$ sudo iptables-save | grep hostnames
eric@nuc1:/var/lib$ sudo iptables-save | grep jira
-A KUBE-NODEPORTS -p tcp -m comment --comment "wittlesouth/jira:" -m tcp --dport 32760 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "wittlesouth/jira:" -m tcp --dport 32760 -j KUBE-SVC-MO7XZ6ASHGM5BOPI
-A KUBE-SEP-LP4GHTW6PY2HYMO6 -s 192.168.124.202/32 -m comment --comment "wittlesouth/jira:" -j KUBE-MARK-MASQ
-A KUBE-SEP-LP4GHTW6PY2HYMO6 -p tcp -m comment --comment "wittlesouth/jira:" -m tcp -j DNAT --to-destination 192.168.124.202:8082
-A KUBE-SERVICES ! -s 10.5.0.0/16 -d 10.105.148.66/32 -p tcp -m comment --comment "wittlesouth/jira: cluster IP" -m tcp --dport 8082 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.105.148.66/32 -p tcp -m comment --comment "wittlesouth/jira: cluster IP" -m tcp --dport 8082 -j KUBE-SVC-MO7XZ6ASHGM5BOPI
-A KUBE-SVC-MO7XZ6ASHGM5BOPI -m comment --comment "wittlesouth/jira:" -j KUBE-SEP-LP4GHTW6PY2HYMO6
不幸的是,目前我对 iptables 一无所知,所以我不知道这些条目看起来是否正确。我怀疑我在 kubeadm init 期间的非默认网络设置可能与此有关,因为我试图将 Kubernetes 设置为不使用我网络的相同 IP 地址范围(基于 192.168)。我使用的 kubeadm init 语句是:
kubeadm init --pod-network-cidr=10.5.0.0/16 --apiserver-cert-extra-sans ['kubemaster.wittlesouth.com','192.168.5.10'
如果您注意到我正在使用默认为 192.168.0.0 的 pod 网络池的 calico,我在创建 calico 服务时修改了 calico 的 pod 网络池设置(不确定这是否相关或不)。
此时,我的结论是我不了解 NodePort 服务应该如何工作,或者我的集群配置有问题。非常感谢任何有关后续诊断步骤的建议!
对于第一部分,HostPort 几乎完全符合预期,它应该只在 运行 所在的主机上工作,在这里它确实如此。 NodePort 仅在一个节点上工作的事实是一个问题,因为您正确地假设它应该在所有节点上工作。
因为它在其中一个上工作,看起来您的 API 服务器和 kube-proxy 正在工作,不太可能是由它们中的任何一个引起的。
首先要检查的是你的 calico 是否工作正常,以及你是否可以从所有节点连接到实际的 pod 运行 你的 jira。如果没有,那就是你的问题。我建议 运行 tcpdump 在你卷曲到的节点和有 pod 的节点上 运行 查看数据包是否到达节点,以及它们如何离开它们(特别是不响应的接收节点卷曲)
当您定义一个 NodePort 服务时,实际上有三个端口在起作用:
- 容器端口:这是您的 pod 实际监听的端口,它仅在集群内从 pod 到 pod 直接访问您的容器时可用(JIRA 的默认端口为 8080)。您将服务中的
targetPort
设置为此端口。
- 服务端口:这是服务本身在集群内部公开的负载平衡端口。对于单个 pod,没有负载平衡在起作用,但它仍然是您服务的入口点。您的服务定义中的
port
对此进行了定义。如果您不指定 targetPort
,则它假定 port
和 targetPort
相同。
- 节点端口:路由到您的服务的每个工作节点上公开的端口。这是一个通常在 30000-33000 范围内的端口(取决于集群的配置方式)。这是您可以从集群外部访问的唯一端口。这是用
nodePort
. 定义的
假设您在标准端口上使用 运行 JIRA,您需要一个类似于以下内容的服务定义:
apiVersion: v1
kind: Service
metadata:
name: jira
namespace: wittlesouth
spec:
ports:
- port: 80 # this is the service port, can be anything
targetPort: 8080 # this is the container port (must match the port your pod is listening on)
nodePort: 32000 # if you don't specify this it randomly picks an available port in your NodePort range
selector:
app: jira
type: NodePort
因此,如果您使用该配置,则对 NodePort 服务的传入请求将变为:NodePort (32000) -> service (80) -> pod (8080)。 (在内部它可能实际上绕过了服务,我对此不是100%确定,但你可以这样从概念上考虑它)。
您似乎也在尝试使用 HTTPS 直接访问 JIRA。您是否在 JIRA pod 中配置了证书?如果是这样,您需要确保它是 nuc1.wittlesouth.com
的有效证书,或者告诉 curl 使用 curl -k
.
忽略证书验证错误
我正在尝试 运行 一个 3 节点 Kubernetes 集群。我已经启动了集群并且 运行ning 足以让我在不同的节点上提供服务 运行ning。不幸的是,我似乎无法让基于 NodePort 的服务正常工作(反正我理解正确性......)。我的问题是,我定义的任何 NodePort 服务仅在它们的 pod 所在的节点上外部可用 运行ning,我的理解是它们应该在集群中的任何节点上外部可用。
一个例子是本地 Jira 服务,它应该 运行ning 在端口 8082(内部)和外部 32760 上。这是服务定义(只是服务部分):
apiVersion: v1
kind: Service
metadata:
name: jira
namespace: wittlesouth
spec:
ports:
- port: 8082
selector:
app: jira
type: NodePort
这是 kubectl get service --namespace wittle south 的输出
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.100.119.22 <none> 8081:31377/TCP 3d
jira NodePort 10.105.148.66 <none> 8082:32760/TCP 9h
ws-mysql ExternalName <none> mysql.default.svc.cluster.local 3306/TCP 1d
此服务的 pod 的 HostPort 设置为 8082。集群中的三个节点是 nuc1、nuc2、nuc3:
Eric:~ eric$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
nuc1 Ready master 3d v1.9.2
nuc2 Ready <none> 2d v1.9.2
nuc3 Ready <none> 2d v1.9.2
以下是尝试通过主机和节点端口访问 Jira 实例的结果:
Eric:~ eric$ curl https://nuc1.wittlesouth.com:8082/
curl: (7) Failed to connect to nuc1.wittlesouth.com port 8082: Connection refused
Eric:~ eric$ curl https://nuc2.wittlesouth.com:8082/
curl: (7) Failed to connect to nuc2.wittlesouth.com port 8082: Connection refused
Eric:~ eric$ curl https://nuc3.wittlesouth.com:8082/
curl: (51) SSL: no alternative certificate subject name matches target host name 'nuc3.wittlesouth.com'
Eric:~ eric$ curl https://nuc3.wittlesouth.com:32760/
curl: (51) SSL: no alternative certificate subject name matches target host name 'nuc3.wittlesouth.com'
Eric:~ eric$ curl https://nuc2.wittlesouth.com:32760/
^C
Eric:~ eric$ curl https://nuc1.wittlesouth.com:32760/
curl: (7) Failed to connect to nuc1.wittlesouth.com port 32760: Operation timed out
根据我的阅读,cube-proxy 似乎没有做它应该做的事情。我尝试阅读文档以解决 cube-proxy 问题,它似乎有点过时(当我在 iptables-save 中 grep 主机名时,它什么也没找到)。这是 kubernetes 版本信息:
Eric:~ eric$ kubectl version
Client Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.1", GitCommit:"3a1c9449a956b6026f075fa3134ff92f7d55f812", GitTreeState:"clean", BuildDate:"2018-01-04T11:52:23Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"9", GitVersion:"v1.9.2", GitCommit:"5fa2db2bd46ac79e5e00a4e6ed24191080aa463b", GitTreeState:"clean", BuildDate:"2018-01-18T09:42:01Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}
看起来 kube-proxy 是 运行ning:
eric@nuc2:~$ ps waux | grep kube-proxy
root 1963 0.5 0.1 54992 37556 ? Ssl 21:43 0:02 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf
eric 3654 0.0 0.0 14224 1028 pts/0 S+ 21:52 0:00 grep --color=auto kube-proxy
和
Eric:~ eric$ kubectl get pods --namespace=kube-system
NAME READY STATUS RESTARTS AGE
calico-etcd-6vspc 1/1 Running 3 2d
calico-kube-controllers-d669cc78f-b67rc 1/1 Running 5 3d
calico-node-526md 2/2 Running 9 3d
calico-node-5trgt 2/2 Running 3 2d
calico-node-r9ww4 2/2 Running 3 2d
etcd-nuc1 1/1 Running 6 3d
kube-apiserver-nuc1 1/1 Running 7 3d
kube-controller-manager-nuc1 1/1 Running 6 3d
kube-dns-6f4fd4bdf-dt5fp 3/3 Running 12 3d
kube-proxy-8xf4r 1/1 Running 1 2d
kube-proxy-tq4wk 1/1 Running 4 3d
kube-proxy-wcsxt 1/1 Running 1 2d
kube-registry-proxy-cv8x9 1/1 Running 4 3d
kube-registry-proxy-khpdx 1/1 Running 1 2d
kube-registry-proxy-r5qcv 1/1 Running 1 2d
kube-registry-v0-wcs5w 1/1 Running 2 3d
kube-scheduler-nuc1 1/1 Running 6 3d
kubernetes-dashboard-845747bdd4-dp7gg 1/1 Running 4 3d
cube-proxy 似乎正在为我的服务创建 iptables 条目:
eric@nuc1:/var/lib$ sudo iptables-save | grep hostnames
eric@nuc1:/var/lib$ sudo iptables-save | grep jira
-A KUBE-NODEPORTS -p tcp -m comment --comment "wittlesouth/jira:" -m tcp --dport 32760 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "wittlesouth/jira:" -m tcp --dport 32760 -j KUBE-SVC-MO7XZ6ASHGM5BOPI
-A KUBE-SEP-LP4GHTW6PY2HYMO6 -s 192.168.124.202/32 -m comment --comment "wittlesouth/jira:" -j KUBE-MARK-MASQ
-A KUBE-SEP-LP4GHTW6PY2HYMO6 -p tcp -m comment --comment "wittlesouth/jira:" -m tcp -j DNAT --to-destination 192.168.124.202:8082
-A KUBE-SERVICES ! -s 10.5.0.0/16 -d 10.105.148.66/32 -p tcp -m comment --comment "wittlesouth/jira: cluster IP" -m tcp --dport 8082 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.105.148.66/32 -p tcp -m comment --comment "wittlesouth/jira: cluster IP" -m tcp --dport 8082 -j KUBE-SVC-MO7XZ6ASHGM5BOPI
-A KUBE-SVC-MO7XZ6ASHGM5BOPI -m comment --comment "wittlesouth/jira:" -j KUBE-SEP-LP4GHTW6PY2HYMO6
不幸的是,目前我对 iptables 一无所知,所以我不知道这些条目看起来是否正确。我怀疑我在 kubeadm init 期间的非默认网络设置可能与此有关,因为我试图将 Kubernetes 设置为不使用我网络的相同 IP 地址范围(基于 192.168)。我使用的 kubeadm init 语句是:
kubeadm init --pod-network-cidr=10.5.0.0/16 --apiserver-cert-extra-sans ['kubemaster.wittlesouth.com','192.168.5.10'
如果您注意到我正在使用默认为 192.168.0.0 的 pod 网络池的 calico,我在创建 calico 服务时修改了 calico 的 pod 网络池设置(不确定这是否相关或不)。
此时,我的结论是我不了解 NodePort 服务应该如何工作,或者我的集群配置有问题。非常感谢任何有关后续诊断步骤的建议!
对于第一部分,HostPort 几乎完全符合预期,它应该只在 运行 所在的主机上工作,在这里它确实如此。 NodePort 仅在一个节点上工作的事实是一个问题,因为您正确地假设它应该在所有节点上工作。
因为它在其中一个上工作,看起来您的 API 服务器和 kube-proxy 正在工作,不太可能是由它们中的任何一个引起的。
首先要检查的是你的 calico 是否工作正常,以及你是否可以从所有节点连接到实际的 pod 运行 你的 jira。如果没有,那就是你的问题。我建议 运行 tcpdump 在你卷曲到的节点和有 pod 的节点上 运行 查看数据包是否到达节点,以及它们如何离开它们(特别是不响应的接收节点卷曲)
当您定义一个 NodePort 服务时,实际上有三个端口在起作用:
- 容器端口:这是您的 pod 实际监听的端口,它仅在集群内从 pod 到 pod 直接访问您的容器时可用(JIRA 的默认端口为 8080)。您将服务中的
targetPort
设置为此端口。 - 服务端口:这是服务本身在集群内部公开的负载平衡端口。对于单个 pod,没有负载平衡在起作用,但它仍然是您服务的入口点。您的服务定义中的
port
对此进行了定义。如果您不指定targetPort
,则它假定port
和targetPort
相同。 - 节点端口:路由到您的服务的每个工作节点上公开的端口。这是一个通常在 30000-33000 范围内的端口(取决于集群的配置方式)。这是您可以从集群外部访问的唯一端口。这是用
nodePort
. 定义的
假设您在标准端口上使用 运行 JIRA,您需要一个类似于以下内容的服务定义:
apiVersion: v1
kind: Service
metadata:
name: jira
namespace: wittlesouth
spec:
ports:
- port: 80 # this is the service port, can be anything
targetPort: 8080 # this is the container port (must match the port your pod is listening on)
nodePort: 32000 # if you don't specify this it randomly picks an available port in your NodePort range
selector:
app: jira
type: NodePort
因此,如果您使用该配置,则对 NodePort 服务的传入请求将变为:NodePort (32000) -> service (80) -> pod (8080)。 (在内部它可能实际上绕过了服务,我对此不是100%确定,但你可以这样从概念上考虑它)。
您似乎也在尝试使用 HTTPS 直接访问 JIRA。您是否在 JIRA pod 中配置了证书?如果是这样,您需要确保它是 nuc1.wittlesouth.com
的有效证书,或者告诉 curl 使用 curl -k
.