kubernetes原生service不支持tcp与udp混用,必须拆分为两个独立service;混写会触发api校验失败报错,nodeport模式下udp端口需显式指定,且go应用须监听对应协议端口。

Kubernetes 原生 Service 不支持在一个资源中同时声明 TCP 和 UDP 端口;必须拆成两个独立 Service,否则 kubectl apply 会直接报错。
Service 混写 TCP/UDP 协议会触发 API 校验失败
你不能在同一个 Service 的 spec.ports[] 里写一个 protocol: TCP 和一个 protocol: UDP。K8s API 层强制要求所有端口协议一致,错误信息类似:
Service "go-svc" is invalid: spec.ports[1].protocol: Invalid value: "UDP": cannot mix TCP and UDP protocols in the same Service
这不是配置疏漏,是硬性限制。哪怕只差一个字段、只多一条端口定义,也会被拒绝。
- 想暴露
TCP 80+TCP 443→ 可以共用一个Service - 想暴露
TCP 80+UDP 53→ 必须拆成两个Service,各自指定protocol -
type: ClusterIP、NodePort、LoadBalancer全部受此约束,无例外
NodePort 场景下 UDP 必须显式指定 nodePort
当你用 type: NodePort 暴露 UDP 服务时,nodePort 字段不能省略 —— K8s 不会像 TCP 那样自动分配可用端口给 UDP(v1.22+ 仍如此)。漏写会导致创建失败,或 nodePort 被设为 0,最终无法访问。
- TCP 和 UDP 的
nodePort各自独立占用端口范围(默认30000–32767),互不干扰 - 例如:TCP 用
nodePort: 30080,UDP 就得另选一个,比如nodePort: 30053 - 若端口范围耗尽,需调整
--service-node-port-rangekube-apiserver 参数
Go 应用容器内必须监听对应协议和端口
Service 只是流量入口,真正收包靠 Go 进程自己。如果 Service 声明了 targetPort: 5353 且 protocol: UDP,但 Go 代码没启动 UDP listener,连接会直接超时或被拒绝。
- TCP 示例:
http.ListenAndServe(":8080", nil)或net.Listen("tcp", ":9090") - UDP 示例:
udpAddr, _ := net.ResolveUDPAddr("udp", ":5353"); conn, _ := net.ListenUDP("udp", udpAddr) - 务必同时启动 TCP 和 UDP listener,不能只启一个
- 容器内监听地址必须是
:8080或0.0.0.0:8080,不能是127.0.0.1:8080(否则其他 Pod 无法访问) -
Dockerfile中的EXPOSE无实际作用,但建议写全(如EXPOSE 8080 5353/udp)便于协作理解
Headless Service 下端口不转发,只靠 DNS + 客户端直连
当使用 clusterIP: None 的 Headless Service 时,ports 字段不再用于代理,而是为了生成 SRV 记录供客户端查出真实 Pod IP + port 组合。
- 若 Go 服务监听
:8081,客户端必须知道这个端口号,并拼接<pod-ip>:8081</pod-ip>直连 - 要让
net.LookupSRV正常工作,调用时协议名必须匹配(UDP 服务就得传"udp",不是默认的"tcp") -
selector必须精确匹配 Pod 标签,否则Endpoints对象为空,DNS 查不到任何记录 - 若需稳定网络标识(如 Raft 成员注册),必须搭配
StatefulSet使用,否则 Pod 重建后 DNS 名称会变
最易被忽略的是:UDP 端口在 NodePort 模式下不会自动分配,以及 Go 进程监听地址写成 127.0.0.1 导致跨 Pod 访问失败 —— 这两类问题在线上排查时往往卡半天,其实只改一行代码或一个字段就能解决。











