Kubernetes 服务发现和域名解析
1 服务访问
Service 介绍
https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
通过对Pod及其工作负载的控制资源RC和Deployment的学习,所有的应用服务都是工作在pod资源中,由于每个Pod都有独立的ip地址,而随着Pod的大量的动态创建和销毁操作后,会导致Pod的名称和IP很有可能发生了变化
假设有前端应用的pod和后端应用的pod,那么在频繁变动的场景中,集群中的应用之间该如何相互通信呢?难道是让我们以类似nginx负载均衡的方式手工定制pod ip然后进行一一管理么?显然这是很难做到的。
Kubernetes集群提供了这样的一个资源对象Service,它定义了一组Pod的逻辑集合和一个用于访问它们的入口策略
Pod 有几个天然的问题:
- Pod IP是临时的,重启后IP会变
- Pod 可能有多个副本,需要负载均衡
- Pod随时可能被调度到不同节点
Service 提供了一个稳定的访问入口,解耦了调用方和 Pod 的直接依赖。
客户端 → Service (固定IP/DNS) → Pod1
→ Pod2
→ Pod3
Service 本质上就是一个四层的反向代理,集群内和外的客户端可以通过如下流程最终实现访问Pod应用
集群内部Client --> service网络 -->Pod网络 -->容器应用
集群外部Client --> 主机节点网络--> service网络 -->Pod网络 -->容器应用
Service 资源在master端的Controller组件中,由 Service Controller 来进行统一管理。
Service是Kubernetes中最高一级的抽象资源对象,每个Service提供一个独立的服务,集群Service彼此间使用TCP/IP进行通信,将不同的服务组合在一起运行起来,就形成了所谓的"系统",效果如下图:

每个Pod都有一个专用的IP地址,加上Pod内部容器的Port端口,就组成了一个访问Pod专用的EndPoint(Pod IP+Container Port),从而实现了用户外部资源访问Pod内部应用的效果
范例: 查看Kubernetes 内置的Service
[root@master1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
[root@master1 ~]# kubectl get svc kubernetes -o yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2026-04-25T10:56:18Z"
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "202"
uid: 9a259b52-e4c4-4f5b-b13f-f35bd6cb7740
spec:
clusterIP: 10.96.0.1
clusterIPs:
- 10.96.0.1
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: https
port: 443
protocol: TCP
targetPort: 6443
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
#对应同名的Endpoint
[root@master1 ~]kubectl describe ep kubernetes
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
Name: kubernetes
Namespace: default
Labels: endpointslice.kubernetes.io/skip-mirror=true
Annotations: <none>
Subsets:
Addresses: 10.0.0.134
NotReadyAddresses: <none>
Ports:
Name Port Protocol
---- ---- --------
https 6443 TCP
Events: <none>
Service 的访问流程

Service 工作模型
代理模型
Userspace 模式
原理:kube-proxy 在用户态监听端口,流量先通过 iptables 转发到用户态进程,再由进程做负载均衡转发到 Pod。
特点:性能差,延迟高,不支持 UDP,仅早期 K8S 使用。
Iptables /nftables 模式
Iptables:K8S 传统默认模式,通过内核 netfilter 规则实现转发,规则是线性遍历,集群规模大时性能下降。
nftables:v1.24+ 新增,作为 iptables 的替代方案,规则更高效,性能更好,是下一代推荐方案。
IPVS 模式
原理:内核级负载均衡,使用哈希表存储规则,查找效率 O (1),支持多种调度算法(轮询、加权轮询、最少连接等)。
适用场景:大规模集群(服务数 > 1000),是生产环境高性能的首选
eBPF 模式(如 Cilium)
原理:完全绕过 kube-proxy,通过 eBPF 程序在内核中直接处理流量转发和负载均衡。
特点:性能极高,延迟低,支持高级网络功能(如透明加密、网络策略),是云原生网络的未来趋势。
Envoy / Istio 模式
(服务网格) 原理:Sidecar 代理模式,在每个 Pod 中注入 Envoy 代理,由 Istio 控制平面统一管理流量规则。
特点:七层流量管理、灰度发布、熔断、可观测性等功能齐全,但架构复杂,运维成本高。
范例: kubeadm方式将默认的iptables模式修改为IPVS模式
#查看当前模式,默认为iptables
[root@master1 ~]#curl 127.0.0.1:10249/proxyMode
iptables
[root@master1 ~]#ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
[root@master1 ~]#kubectl edit configmap kube-proxy -n kube-system
mode: "ipvs" #修改此行,默认为""
#删除所有kube-proxy对应的Pod,建议reboot生效
[root@master1 ~]#kubectl delete pod -n kube-system -l k8s-app=kube-proxy
#验证结果
[root@master1 ~]#curl 127.0.0.1:10249/proxyMode
ipvs
#每个节点都生成kube-ipvs0的虚拟网卡
[root@master1 ~]# ip a show kube-ipvs0
5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default
link/ether 3e:ad:51:41:9f:1b brd ff:ff:ff:ff:ff:ff
inet 10.97.7.154/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.10/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
inet 10.96.0.1/32 scope global kube-ipvs0
valid_lft forever preferred_lft forever
#再次查看出现IPVS规则
[root@master1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 10.0.0.134:6443 Masq 1 3 0
TCP 10.96.0.10:53 rr
-> 10.244.0.14:53 Masq 1 0 0
-> 10.244.0.15:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.0.14:9153 Masq 1 0 0
-> 10.244.0.15:9153 Masq 1 0 0
TCP 10.97.7.154:6379 rr
-> 10.244.1.41:6379 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.244.0.14:53 Masq 1 0 0
-> 10.244.0.15:53 Masq 1 0 0
对比总结

选择建议
- 小规模集群:iptables模式(默认)
- 大规模生产:IPVS模式
- 高性能需求:eBPF + Cilium
- 微服务治理:服务网格(Envoy/Istio)
svc类型
clusterip 东西,集群内的Pod相互访问
nodeport 从北向南,集群外访问集群内 = clusterIP+3XXXX
默认随机端口范围30000~32767, 可指定为固定端口
loadbalancer 从北向南,集群外访问集群内 = nodePort + EXTERNAL-IP = clusterIP+3XXXX + EXTERNAL-IP(也可以使用
ExternalIP 实现)
externalname 从南向北,从集群内访问集群外
server管理
创建server
对于Service的创建有两种方法:
-
命令行方法
-
YAML 文件方法
基础语法
#创建命令1:
kubectl create service [flags] NAME [--tcp=port:targetPort] [--dry-run]
#创建命令2:
kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP]
[--target-port=number-or-name] [--name=name] [--external-ip=external-ip-ofservice] [--type=type] [options]
[root@master1 ~]#kubectl expose deployment myapp --target-port 80 --port 80 --name myapp-svc --type LoadBalancer -o yaml --dry-run=client
apiVersion: v1
kind: Service
metadata:
creationTimestamp: null
labels:
app: myapp
name: myapp-svc
spec:
ports:
- port: 80 # Service 对外端口
protocol: TCP
targetPort: 80 # 容器内部端口
selector:
app: myapp # 自动匹配 deployment=myapp 的 Pod
type: LoadBalancer# 负载均衡类型
status:
loadBalancer: {}
#查看命令:
kubectl get svc
范例: kubectl create 创建 service
kubectl create service clusterip my-service1 --tcp=5678:80
kubectl create service clusterip my-service2 --clusterip="None"
kubectl create service clusterip my-service3 --clusterip="10.96.1.3" --tcp="999"
[root@master1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 18d
my-service1 ClusterIP 10.103.145.12 <none> 5678/TCP 4m53s
my-service2 ClusterIP None <none> <none> 3m33s
my-service3 ClusterIP 10.96.1.3 <none> 999/TCP 97s
redis-svc ClusterIP 10.97.7.154 <none> 6379/TCP 39h
查看 Service CIDR:
kubectl cluster-info dump | grep -m 1 service-cluster-ip-range
范例:kubectl expose 创建 service
[root@master1 ~]kubectl create deployment myapp --image=registry.cn-beijing.aliyuncs.com/wangxiaochun/demo:v1.0 --replicas=3
[root@master1 ~]kubectl expose deployment myapp1 --target-port 80 --port 80 --name myapp1-svc --type LoadBalancer -o yaml --dry-run=clientapiVersion: v1
kind: Service
metadata:
labels:
app: myapp1
name: myapp1-svc
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: myapp1
type: LoadBalancer
status:
loadBalancer: {}
[root@master1 ~]# kubectl expose deployment myapp1 --target-port=80 --port=80 --name=myapp1-svc --type=LoadBalancer
service/myapp1-svc exposed
[root@master1 ~]#
[root@master1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp1-svc LoadBalancer 10.97.42.54 <pending> 80:31387/TCP 8s
[root@master1 ~]# curl 10.97.42.54
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myapp1-7659db7ff8-br5fm, ServerIP: 10.244.1.46!
[root@master1 ~]# curl 10.97.42.54
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myapp1-7659db7ff8-zp8wb, ServerIP: 10.244.1.45!
[root@master1 ~]# curl 10.97.42.54
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myapp1-7659db7ff8-xtjt7, ServerIP: 10.244.1.47!
[root@master1 ~]# curl 10.97.42.54
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myapp1-7659db7ff8-br5fm, ServerIP: 10.244.1.46!
[root@master1 ~]# curl 10.97.42.54
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myapp1-7659db7ff8-zp8wb, ServerIP: 10.244.1.45!

范例
#一步实现创建所有pod和相应的service
[root@master1 ~]# kubectl run pod-test --image=registry.cn-beijing.aliyuncs.com/wangxiaochun/pod-test:v0.1 --expose=true --port=80
service/pod-test created
pod/pod-test created
[root@master1 ~]# kubectl get all
service/pod-test ClusterIP 10.96.10.141 <none> 80/TCP 10s
[root@master1 ~]# kubectl get pod --show-labels -o wide
pod-test 1/1 Running 0 37s 10.244.1.48 node1 <none> <none> run=pod-test
[root@master1 ~]# curl 10.96.10.141
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: pod-test, ServerIP: 10.244.1.48!
范例
[root@master1 ~]# kubectl create deployment deployment-test --image=registry.cn-beijing.aliyuncs.com/wangxiaochun/pod-test:v0.1 --replicas=2deployment.apps/deployment-test created
#查看pod信息
[root@master1 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
deployment-test-5c4c96d8b-5szth 1/1 Running 0 31m 10.244.1.49 node1 <none> <none>
deployment-test-5c4c96d8b-qq6kc 1/1 Running 0 31m 10.244.1.50 node1 <none> <none>
#对已有的Deployment创建对应的service
[root@master1 ~]#kubectl expose deployment deployment-test --port 80
#查看service
[root@master1 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
deployment-test ClusterIP 10.105.207.10 <none> 80/TCP 7s
#可以看到后端的两个Pod的IP地址
[root@master1 ~]# kubectl get ep
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME ENDPOINTS AGE
deployment-test 10.244.1.49:80,10.244.1.50:80 91s
kubernetes 10.0.0.134:6443 18d
#测试名称解析,10.96.0.10为coredns服务器地址
[root@master1 ~]# dig -t A deployment-test.default.svc.cluster.local @10.96.0.10 +short
10.105.207.10
#通过service的IP访问后端的Pod
[root@master1 ~]# curl 10.105.207.10
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: deployment-test-5c4c96d8b-qq6kc, ServerIP: 10.244.1.50!
[root@master1 ~]# curl 10.105.207.10
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: deployment-test-5c4c96d8b-5szth, ServerIP: 10.244.1.49!
#创建测试的Pod
[root@master1 ~]#kubectl run busybox --image busybox:1.30.0 -- sleep 3600
#测试访问service
[root@master1 ~]#kubectl exec -it busybox -- sh
#无法ping通
/ # ping -c1 deployment-test
PING deployment-test (10.111.116.76): 56 data bytes
#可以通过sevice名称访问http服务
/ # wget -qO - deployment-test
kubernetes pod-test v0.1!! ClientIP: 10.244.1.51, ServerName: deployment-test-5c4c96d8b-5szth, ServerIP: 10.244.1.49!
/ # wget -qO - deployment-test
kubernetes pod-test v0.1!! ClientIP: 10.244.1.51, ServerName: deployment-test-5c4c96d8b-qq6kc, ServerIP: 10.244.1.50!


ClusterIP(默认类型)
核心特点
- 仅集群内部可访问,外部(宿主机 / 公网)无法直接访问
- 会分配一个集群内部的虚拟 IP(ClusterIP),比如
10.96.x.x - 同一个集群里的 Pod、节点都能通过这个 IP 访问服务
- 适合内部服务之间互相调用(比如后端服务调用数据库)
访问方式
- 集群内:
curl <ClusterIP>:<port> - 集群外:❌ 无法直接访问
nodePort 类型
核心特点
集群内部 + 集群外部(宿主机层面)都能访问
会在每个节点上开放一个 30000-32767 之间的端口(NodePort)
外部可以通过「任意节点 IP:NodePort」访问服务
流量路径:外部请求 → 节点 IP:NodePort → 转发到集群内的 ClusterIP → 再转发到 Pod
适合开发测试、简单对外暴露服务
访问方式
集群内:curl :
集群外:curl <任意节点IP>:(比如 192.168.91.192:30066)
LoadBalancer
核心特点
- 集群内 + 公网都能访问(依赖云厂商支持)
- 本质是
NodePort+ 云厂商提供的外部负载均衡器 - 会分配一个公网 IP(或云厂商的负载均衡域名),直接对外提供服务
- 流量路径:公网请求 → 云 LB → 转发到集群内的节点 / ClusterIP → 再到 Pod
- 适合生产环境对外提供服务,比如公网网站、API
访问方式
- 集群内:
curl <ClusterIP>:<port> - 集群外 / 公网:
curl <LoadBalancerIP>:<port>
ExternalName
核心特点
- 仅集群内部可访问,作用是把集群内的服务指向外部域名
- 不会分配 ClusterIP,而是通过
externalName字段指定一个外部域名(比如api.baidu.com) - 集群内的 Pod 访问这个 Service 时,会被直接解析为指定的外部域名
- 适合集群内服务调用外部第三方服务,比如调用外部数据库、API
访问方式
- 集群内:直接访问 Service 名,会被解析为外部域名
- 集群外:❌ 无法直接访问
| 类型 | 集群内访问 | 集群外(宿主机)访问 | 公网访问 | 核心用途 |
|---|---|---|---|---|
| ClusterIP | ✅ | ❌ | ❌ | 内部服务间调用 |
| NodePort | ✅ | ✅(节点 IP + 端口) | ❌(无公网 IP) | 开发测试、简单对外暴露 |
| LoadBalancer | ✅ | ✅ | ✅公网 IP) | 生产环境对外提供服务 |
| ExternalName | ✅ | ❌ | ❌ | 集群内访问外部服务 |
示例 ClusterIP类型
# 1. ClusterIP 类型(默认,只能集群内部访问)
apiVersion: v1
kind: Service
metadata:
name: svc-clusterip
spec:
type: ClusterIP
selector:
app: myweb
ports:
- port: 80
targetPort: 80
验证
[root@master1 pod]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
deployment-test ClusterIP 10.105.207.10 <none> 80/TCP 8h
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 19d
service-clusterip-multi-port ClusterIP 10.97.93.81 <none> 80/TCP,443/TCP 8h
service-nodeport NodePort 10.107.156.23 <none> 80:30066/TCP 4h17m
svc-clusterip ClusterIP 10.109.90.16 <none> 80/TCP 26m
svc-external ExternalName <none> www.baidu.com <none> 25m
[root@master1 pod]# curl 10.109.90.16
kubernetes pod-test v0.1!! ClientIP: 10.244.0.0, ServerName: myweb-7699f6b8cc-7sf8b, ServerIP: 10.244.1.61!
示例 nodePort 类型
# ====================== 第一部分:部署 Pod(必须)======================
apiVersion: apps/v1
kind: Deployment
metadata:
name: myweb # 名字叫 myweb
spec:
replicas: 1 # 跑 1 个副本
selector:
matchLabels:
app: myweb # 匹配下面 Pod 的标签
template:
metadata:
labels:
app: myweb # Pod 自带标签(Service 靠它找到 Pod)
spec:
containers:
- name: myweb
image: registry.cn-beijing.aliyuncs.com/wangxiaochun/pod-test:v0.1 # 显示 v0.1 的镜像
ports:
- containerPort: 80 # 容器内部端口
---
# ====================== 第二部分:Service 暴露服务(必须)======================
apiVersion: v1
kind: Service
metadata:
name: service-nodeport
spec:
type: NodePort # 外部可访问
selector:
app: myweb # 找到上面的 Pod
ports:
- port: 80 # Service 端口
targetPort: 80 # 容器端口
nodePort: 30066 # 外部访问端口


范例:使用 ExternalName Service 实现代理外部服务
#创建文件
[root@master1 ~]#cat service-externalname-web.yaml
kind: Service
apiVersion: v1
metadata:
name: svc-externalname-web
namespace: default
spec:
type: ExternalName
externalName: www.wangxiaochun.com # 必须是域名,不能是IP
# externalName: myapp.demo.svc.cluster.local # 也可以指向集群内部其他Service
ports: # 可选,写不写都行,只做标记,不生效
- protocol: TCP
port: 80
targetPort: 80
selector: {} # 必须空,因为不关联Pod
#应用
[root@master1 ~]#kubectl apply -f service-externalname-web.yaml
#注意: service没有Cluster-IP,即为无头服务Headless Service
[root@master1 ~]#kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc-externalname-web ExternalName <none> www.wangxiaochun.com 80/TCP 10s
#注意:ExternalName没有对应同名的Endpoints
[root@master1 ~]#kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 10.0.0.134:6443 19d
#解析
[root@master1 ~]#kubectl run pod-$RANDOM --image=registry.cn-beijing.aliyuncs.com/wangxiaochun/admin-box:v0.1 -it --rm --command -- /bin/bash
root@pod-9322 /# host svc-externalname-web
svc-externalname-web.default.svc.cluster.local is an alias for www.wangxiaochun.com.
www.wangxiaochun.com is an alias for cloud.magedu.com.
cloud.magedu.com has address 123.149.76.43
root@pod-9322 /# nslookup svc-externalname-web
Server: 10.96.0.10
Address: 10.96.0.10#53
svc-externalname-web.default.svc.cluster.local canonical name = www.wangxiaochun.com.
Name: www.wangxiaochun.com
Address: 123.149.76.43
www.wangxiaochun.com canonical name = cloud.magedu.com.
root@pod-9322 /# ping -c1 svc-externalname-web
PING svc-externalname-web (123.149.76.43): 56 data bytes
64 bytes from 123.149.76.43: seq=0 ttl=127 time=27.356 ms
--- svc-externalname-web ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 27.356/27.356/27.356 ms

CoreDNS
K8s 默认集群内部 DNS 服务,替代旧版 kube-dns,轻量、插件化。

CoreDNS 只负责"名字 → Service IP"的解析, 真正的流量转发由 Service / kube-proxy 完成。
K8s 集群内,客户端用域名访问服务时,CoreDNS 先把域名翻译成 Service 的固定 IP,再由 Service 把流量转发到后端真实 Pod 的容器端口,全程客户端只需要感知域名,完全屏蔽了后端 Pod 的变化。
比如你要访问集群内的 nginx 服务:
客户端 Pod 发起请求:curl nginx.default.svc.cluster.local
请求先到 CoreDNS,把域名解析成 Service 的 ClusterIP:10.98.123.45
流量到 Service 的 80 端口,Service 通过 Label 找到后端的 nginx Pod
流量转发到 Pod 的 IP(比如 10.244.1.5)的 80 端口
最终请求落到 Pod 内 nginx 容器的 80 端口,返回响应
mg-BlCFyFhp-1780650141524)]
CoreDNS
K8s 默认集群内部 DNS 服务,替代旧版 kube-dns,轻量、插件化。
外链图片转存中...(img-jRriUrtp-1780650141524)
CoreDNS 只负责"名字 → Service IP"的解析, 真正的流量转发由 Service / kube-proxy 完成。
K8s 集群内,客户端用域名访问服务时,CoreDNS 先把域名翻译成 Service 的固定 IP,再由 Service 把流量转发到后端真实 Pod 的容器端口,全程客户端只需要感知域名,完全屏蔽了后端 Pod 的变化。
比如你要访问集群内的 nginx 服务:
客户端 Pod 发起请求:curl nginx.default.svc.cluster.local
请求先到 CoreDNS,把域名解析成 Service 的 ClusterIP:10.98.123.45
流量到 Service 的 80 端口,Service 通过 Label 找到后端的 nginx Pod
流量转发到 Pod 的 IP(比如 10.244.1.5)的 80 端口
最终请求落到 Pod 内 nginx 容器的 80 端口,返回响应