全网最详细的 K8s Service 不能访问排查流程
对于新安装的 Kubernetes,经常出现的一个问题是Service没有正常工作。如果您已经运行了Deployment并创建了一个Service,但是当您尝试访问它时没有得到响应,希望这份文档能帮助您找出问题所在。先来熟悉下Service工作逻辑:为了完成本次演练的目的,我们先运行几个Pod。$ kubectl run hostnames --image=k8s.gcr.io/serve_hos
对于新安装的 Kubernetes,经常出现的一个问题是 Service
没有正常工作。如果您已经运行了 Deployment
并创建了一个 Service
,但是当您尝试访问它时没有得到响应,希望这份文档能帮助您找出问题所在。
先来熟悉下Service工作逻辑:
为了完成本次演练的目的,我们先运行几个 Pod
。
$ kubectl run hostnames --image=k8s.gcr.io/serve_hostname \
--labels=app=hostnames \
--port=9376 \
--replicas=3
deployment.apps/hostnames created
确认您的 Pods
是运行状态:
$ kubectl get pods -l app=hostnames
NAME READY STATUS RESTARTS AGE hostnames-632524106-bbpiw 1/1 Running 0 2m hostnames-632524106-ly40y 1/1 Running 0 2m hostnames-632524106-tlaok 1/1 Running 0 2m
问题1:Service 存在吗?
细心的读者会注意到我们还没有真正创建一个 Service
- 其实这是我们有意的。这是一个有时会被遗忘的步骤,也是第一件要检查的事情。
那么,如果我试图访问一个不存在的 Service
,会发生什么呢?假设您有另一个 Pod
,想通过名称使用这个 Service
,您将得到如下内容:
u@pod$ wget -O- hostnames
Resolving hostnames (hostnames)... failed: Name or service not known.
wget: unable to resolve host address 'hostnames'
因此,首先要检查的是 Service
是否确实存在:
$ kubectl get svc hostnames
No resources found.
Error from server (NotFound): services "hostnames" not found
我们已经有一个罪魁祸首了,让我们来创建 Service
。就像前面一样,这里的内容仅仅是为了步骤的执行 - 在这里您可以使用自己的 Service
细节。
$ kubectl expose deployment hostnames --port=80 --target-port=9376
service/hostnames exposed
再查询一遍,确定一下:
$ kubectl get svc hostnames
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.0.1.175 <none> 80/TCP 5s
与前面相同,这与您使用 YAML 启动的 Service
一样:
apiVersion: v1
kind: Service
metadata:
name: hostnames
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80
targetPort: 9376
现在您可以确认 Service
存在。
问题2:Service 是否通过 DNS 工作?
从相同 Namespace
下的 Pod
中运行:
u@pod$ nslookup hostnames
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
如果失败,那么您的 Pod
和 Service
可能位于不同的 Namespace
中,请尝试使用限定命名空间的名称:
u@pod$ nslookup hostnames.default
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
如果成功,那么需要调整您的应用,使用跨命名空间的名称去访问服务,或者,在相同的 Namespace
中运行应用和 Service
。如果仍然失败,请尝试一个完全限定的名称:
u@pod$ nslookup hostnames.default.svc.cluster.local
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: hostnames.default.svc.cluster.local
Address 1: 10.0.1.175 hostnames.default.svc.cluster.local
注意这里的后缀:”default.svc.cluster.local”。”default” 是我们正在操作的 Namespace
。”svc” 表示这是一个 Service
。”cluster.local” 是您的集群域,在您自己的集群中可能会有所不同。
您也可以在集群中的 Node 上尝试此操作:
注意: 10.0.0.10 是我的 DNS
Service
,您的可能不同)
u@node$ nslookup hostnames.default.svc.cluster.local 10.0.0.10
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: hostnames.default.svc.cluster.local
Address: 10.0.1.175
如果您能够使用完全限定的名称查找,但不能使用相对名称,则需要检查 /etc/resolv.conf
文件是否正确。
u@pod$ cat /etc/resolv.conf
nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local example.com
options ndots:5
nameserver
行必须指示您的集群的 DNS Service
,它通过 --cluster-dns
标志传递到 kubelet
。
search
行必须包含一个适当的后缀,以便查找 Service
名称。在本例中,它在本地 Namespace
(default.svc.cluster.local
)、所有 Namespace
中的 Service
(svc.cluster.local
)以及集群(cluster.local
)中查找服务。根据您自己的安装情况,可能会有额外的记录(最多 6 条)。集群后缀通过 --cluster-domain
标志传递给 kubelet
。本文档中,我们假定它是 “cluster.local”,但是您的可能不同,这种情况下,您应该在上面的所有命令中更改它。
options
行必须设置足够高的 ndots
,以便 DNS 客户端库考虑搜索路径。在默认情况下,Kubernetes 将这个值设置为 5,这个值足够高,足以覆盖它生成的所有 DNS 名称。
问题3:DNS 是否可以解析默认服务?
如果上面仍然失败 - DNS 查找不到您需要的 Service
- 我们可以后退一步,看看还有什么不起作用。Kubernetes 主 Service
应该一直是工作的:
u@pod$ nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
如果失败,您可能需要转到这个文档的 kube-proxy 部分,或者甚至回到文档的顶部重新开始,但不是调试您自己的 Service
,而是调试 DNS。
问题4:Service 能够通过 IP 访问么?
假设我们可以确认 DNS 工作正常,那么接下来要测试的是您的 Service
是否工作正常。从集群中的一个节点,访问 Service
的 IP(从上面的 kubectl get
命令获取)。
u@node$ curl 10.0.1.175:80
hostnames-0uton
u@node$ curl 10.0.1.175:80
hostnames-yp2kp
u@node$ curl 10.0.1.175:80
hostnames-bvc05
如果 Service
是正常的,您应该得到正确的响应。如果没有,有很多可能出错的地方,请继续。
问题5:Service 是对的吗?
这听起来可能很愚蠢,但您应该加倍甚至三倍检查 Service
是否正确,并且与您的 Pod
匹配。查看 Service
并验证它:
$ kubectl get service hostnames -o json
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "hostnames",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/services/hostnames",
"uid": "428c8b6c-24bc-11e5-936d-42010af0a9bc",
"resourceVersion": "347189",
"creationTimestamp": "2015-07-07T15:24:29Z",
"labels": {
"app": "hostnames"
}
},
"spec": {
"ports": [
{
"name": "default",
"protocol": "TCP",
"port": 80,
"targetPort": 9376,
"nodePort": 0
}
],
"selector": {
"app": "hostnames"
},
"clusterIP": "10.0.1.175",
"type": "ClusterIP",
"sessionAffinity": "None"
},
"status": {
"loadBalancer": {}
}
}
spec.ports[]
中描述的是您想要尝试访问的端口吗?targetPort
对您的 Pod
来说正确吗(许多 Pod
选择使用与 Service
不同的端口)?如果您想把它变成一个数字端口,那么它是一个数字(9376)还是字符串 “9376”?如果您想把它当作一个指定的端口,那么您的 Pod
是否公开了一个同名端口?端口的 protocol
和 Pod
的一样吗?
更多推荐
所有评论(0)