自建Kubernetes集群服务无法暴露至公网问题求助
嘿,我来帮你捋清楚这个问题!首先先给你吃个定心丸:在没有云服务商支持的自建K8s集群里,用NodePort类型的Service时,kubectl get services里的ExternalIP列一直显示Pending是完全正常的——这个字段是给云厂商的LoadBalancer控制器用的,咱们自建集群没这玩意儿,所以不用纠结这个状态。咱们的核心目标是让服务通过节点的公网IP+NodePort端口能被外部访问。
接下来一步步排查解决:
1. 先确认你的Service配置没写错
先检查你的Service YAML文件,确保spec.type是NodePort,而不是LoadBalancer。比如正确的配置应该是这样的:
apiVersion: v1 kind: Service metadata: name: hello-world-svc spec: type: NodePort selector: app: hello-world # 这个必须和你的Deployment里Pod的label完全匹配! ports: - protocol: TCP port: 80 # Service内部集群访问的端口 targetPort: 8080 # 你的hello-world Pod里实际监听的端口 nodePort: 30007 # 可选,指定一个30000-32767范围内的端口,不指定的话K8s会自动分配
要是你不小心把类型写成了LoadBalancer,那ExternalIP肯定会一直Pending,改成NodePort就好。
2. 确认Service已经正确关联到Pod
执行kubectl get svc,看你的Service那一行的ENDPOINTS列,如果是空的,说明你的Service的selector和Deployment的label不匹配,导致没找到对应的Pod。这时候得去检查Deployment的YAML里的labels字段,和Service的selector保持一致才行。
另外,看PORT(S)列,应该显示类似80:30007/TCP,后面的30007就是K8s分配的NodePort端口,记下来这个端口号。
3. 你用错IP了!172.31.8.110是内网IP呀!
你尝试访问的172.31.8.110是典型的内网私有IP,公网是访问不到的!先搞清楚你的Ubuntu服务器的公网IP是什么:
- 在服务器上执行
curl ifconfig.me,就能拿到公网IP; - 或者去你的服务器托管商的控制台里找公网IP。
然后用http://<你的公网IP>:<刚才拿到的NodePort端口>来访问,比如http://123.45.67.89:30007。
4. 开放防火墙和安全组的端口
Ubuntu 16.04默认用ufw防火墙,得把NodePort端口开放出来:
# 开放你那个具体的NodePort端口,比如30007 sudo ufw allow 30007/tcp # 或者直接开放整个NodePort端口范围(30000-32767),方便以后加服务 sudo ufw allow 30000:32767/tcp # 重启防火墙让规则生效 sudo ufw reload
另外,要是你的服务器在机房或者有云服务商的安全组,一定要去安全组里加一条入站规则,允许外部访问这个NodePort端口(或者整个30000-32767范围)。
5. 检查kube-proxy和网络插件状态
先确认集群的网络插件(比如flannel、calico)是正常运行的:
kubectl get pods -n kube-system
看网络插件的Pod是不是都是Running状态。然后检查kube-proxy有没有正常监听NodePort端口:
netstat -tulpn | grep <你的NodePort端口>
要是没看到kube-proxy在监听这个端口,就重启kube-proxy试试:
kubectl rollout restart daemonset kube-proxy -n kube-system
最后再测试访问
把上面的步骤都走完之后,再用浏览器或者curl访问http://<你的公网IP>:<NodePort端口>,应该就能看到你的hello world服务了!
内容的提问来源于stack exchange,提问作者Mudit

