通过YAML创建Kubernetes NodePort Service后curl无法连接的问题
问题描述
我手动定义了如下Service:
apiVersion: v1 kind: Service metadata: name: my-app-dev labels: run: my-app-dev spec: type: NodePort selector: app: my-app-dev ports: - port: 18080 targetPort: 18080 name: http - port: 47100 targetPort: 47100 name: ignite-com - port: 47500 targetPort: 47500 name: ignite-disc
执行kubectl get svc返回:
my-app-dev NodePort 10.xxx.xxx.xxx <none> 18080:32058/TCP,47100:30524/TCP,47500:31437/TCP 12m
尝试通过curl http://kube代理IP:32058访问时,报错:curl: (7) Failed to connect to xxxxxx port 32058: Connection refused
但执行命令kubectl expose deployment my-app-dev --name=my-app-dev-2 --type=NodePort --port=18080 --target-port=18080后,新创建的Service可以正常访问:
my-app-dev NodePort 10.xxx.xxx.xxx <none> 18080:32058/TCP,47100:30524/TCP,47500:31437/TCP 12m my-app-dev-2 NodePort 10.xxx.xxx.xxx <none> 18080:30571/TCP 11s
此时curl http://kube代理IP:30571访问正常。
补充我的Deployment配置:
apiVersion: apps/v1 kind: Deployment metadata: labels: run: my-app-dev name: my-app-dev spec: replicas: 1 selector: matchLabels: run: my-app-dev template: metadata: labels: run: my-app-dev spec: containers: - name: private image: foo/bar volumeMounts: - name: config-data mountPath: /config ports: - containerPort: 18080 protocol: TCP name: http - containerPort: 47100 protocol: TCP name: ignite-com - containerPort: 47500 protocol: TCP name: ignite-disc env: - name: JAVA_OPTS value: "-Xms512m -Xmx512m -XX:+UseG1GC -XX:MaxInlineLevel=18 -Djava.net.preferIPv4Stack=true" - name: HOST valueFrom: fieldRef: fieldPath: status.hostIP initContainers: - name: config-data image: curlimages/curl command: ["sh", "-c", "TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token`; curl -k -H \"Authorization: Bearer $TOKEN\" https://kubernetes.default:443/api/v1/namespaces/default/services/my-app-dev >> /config/service.json"] volumeMounts: - name: config-data mountPath: /config volumes: - name: config-data emptyDir: {}
问题诊断
核心原因是Service与Pod的标签选择器不匹配:
- 手动创建的
my-app-devService的spec.selector设置为app: my-app-dev - 但Deployment中Pod的标签是
run: my-app-dev,Service无法找到对应的后端Pod,导致请求无法转发,出现连接拒绝错误 - 而
kubectl expose命令会自动根据Deployment的matchLabels生成Service的选择器(即run: my-app-dev),所以新创建的my-app-dev-2能正确关联Pod,访问正常
解决方案
有两种修改方式,任选其一即可:
方式一:修改手动创建的Service的选择器
将Service的spec.selector改为run: my-app-dev,与Pod标签一致:
apiVersion: v1 kind: Service metadata: name: my-app-dev labels: run: my-app-dev spec: type: NodePort selector: run: my-app-dev # 此处修改为与Pod匹配的标签 ports: - port: 18080 targetPort: 18080 name: http - port: 47100 targetPort: 47100 name: ignite-com - port: 47500 targetPort: 47500 name: ignite-disc
修改后执行kubectl apply -f <service-file.yaml>更新Service,之后即可通过原NodePort访问。
方式二:修改Deployment的Pod标签
将Deployment中Pod的标签改为app: my-app-dev,与原Service的选择器一致:
apiVersion: apps/v1 kind: Deployment metadata: labels: run: my-app-dev name: my-app-dev spec: replicas: 1 selector: matchLabels: app: my-app-dev # 修改此处标签 template: metadata: labels: app: my-app-dev # 修改此处标签 spec: # 其余配置保持不变
修改后执行kubectl apply -f <deployment-file.yaml>更新Deployment,Deployment会重新创建带有新标签的Pod,Service即可自动关联这些Pod。
验证步骤
修改完成后,可通过以下命令验证Service是否正确关联Pod:
kubectl describe svc my-app-dev
查看输出中的Endpoints字段,如果显示Pod的IP地址,说明关联成功。
内容的提问来源于stack exchange,提问作者user432024

