k8s原生service不支持tcp与udp混用,必须分设独立service或通过ingress-nginx的tcp-services/udp-services configmap配合service端口开放和启动参数实现四层代理。

直接说结论:K8s原生Service支持多个TCP端口,但不支持UDP与TCP混用;暴露UDP端口必须单独声明,且Ingress-Nginx需额外配置ConfigMap + Service端口开放才能代理TCP/UDP流量。
Service里同时写TCP和UDP端口会报错
很多人尝试在同一个Service的ports列表里混写protocol: TCP和protocol: UDP,比如:
ports: - port: 80 targetPort: 8080 protocol: TCP - port: 53 targetPort: 5353 protocol: UDP
这会导致kubectl apply失败,错误信息是:Service "xxx" is invalid: spec.ports[1].protocol: Invalid value: "UDP": cannot mix TCP and UDP protocols in the same Service。K8s强制要求一个Service只能有一种协议类型。
解决办法只有两个:
- 为TCP和UDP分别创建两个独立的
Service(推荐用于简单场景) - 用
ingress-nginx统一入口,通过tcp-services/udp-servicesConfigMap做四层转发(适合需要复用同一IP+不同端口的生产环境)
用kubectl expose快速暴露单协议多端口
如果你只暴露TCP端口(比如Go服务同时监听8080和9090),kubectl expose是最省事的方式:
先确保Deployment里已声明多个containerPort:
containers: - name: go-app image: my-go-app:latest ports: - containerPort: 8080 - containerPort: 9090
再执行:
kubectl expose deployment go-app --name=go-tcp-svc --port=80 --target-port=8080 --port=90 --target-port=9090
注意:--port和--target-port成对出现,每对对应一个端口映射。命令会自动识别多个containerPort并生成多端口Service。
但kubectl expose不支持指定protocol参数,它默认用TCP;要暴露UDP,必须手写YAML或用helm等工具生成。
让ingress-nginx代理TCP/UDP需要三步缺一不可
很多用户只改了tcp-services ConfigMap,却发现端口不通——因为漏掉了另外两处关键配置:
-
第一步:在
ingress-nginx命名空间下创建tcp-servicesConfigMap,例如将外部9000转到default/go-app:8080:
apiVersion: v1 kind: ConfigMap metadata: name: tcp-services namespace: ingress-nginx data: 9000: "default/go-app:8080"
-
第二步:修改
ingress-nginx的Service(通常是ingress-nginx-controller),显式暴露9000端口,并设protocol: TCP:
ports: - name: proxied-tcp-9000 port: 9000 targetPort: 9000 protocol: TCP
-
第三步:确认
ingress-nginxDeployment的容器启动参数中包含--tcp-services-configmap=$(POD_NAMESPACE)/tcp-services(Helm安装默认已加,手动部署需检查)
UDP同理,用udp-services ConfigMap + Service中暴露对应UDP端口 + 启动参数--udp-services-configmap。
Go服务自身监听多端口时的常见坑
Go程序里如果用net.Listen("tcp", ":8080")和net.Listen("udp", ":5353"),要注意:
- 容器内必须用
0.0.0.0绑定,不能写127.0.0.1,否则targetPort无法连通 - K8s健康检查(
livenessProbe/readinessProbe)默认走HTTP,若只暴露TCP/UDP,得改用tcpSocket探针,否则Pod一直CrashLoopBackOff - UDP连接无状态,
readinessProbe用tcpSocket无效,得靠应用层心跳或跳过UDP端口的探测
最易被忽略的一点:UDP服务在NodePort模式下,K8s不会做连接跟踪(conntrack),高并发时可能丢包;生产环境强烈建议走LoadBalancer类型Service或ingress-nginx代理,而不是直接NodePort暴露UDP。











