K8s Service 发现:一场“寻宝游戏”与 DNS 的“罗盘”🧭
大家好,我是你们的老朋友,人称“Bug终结者”的码农老王。今天咱们来聊聊 Kubernetes (K8s) 里一个至关重要,但又容易被忽略的环节——Service 发现。 别怕,听起来高大上,其实就像一场有趣的“寻宝游戏”,而 DNS 解析就是指引我们找到宝藏的“罗盘”。
开场白:为啥需要“寻宝”?
想象一下,你开了一家在线购物网站。后端服务那叫一个多:用户认证服务、商品目录服务、购物车服务、支付服务… 它们就像一个个藏在不同地方的“宝藏”,需要互相协作才能完成用户的订单。问题来了:这些服务的位置(IP 地址和端口)可不是固定的!它们会因为扩容、故障迁移等原因,像“幽灵”一样飘忽不定。
如果没有一种机制能让这些服务“自动找到彼此”,那你的网站就得天天宕机,老板得天天找你“喝茶”,程序员们也得天天加班到怀疑人生 😭。
所以,Service 发现就应运而生了。它就像一个中央情报局,负责收集、维护所有服务的地址信息,并提供给需要它们的服务。
Service 发现:K8s 的“爱情丘比特”❤️
在 K8s 的世界里,Service 就像一个“爱情丘比特”,负责将请求(爱意)引导到正确的 Pod(恋人)那里。 Service 负责提供一个稳定的入口点(IP 地址和端口),而背后的 Pod 们则可以随意变动,不用担心影响到别人。
Service 的类型有很多,常见的有:
- ClusterIP: 这是默认类型,Service 会分配一个集群内部的虚拟 IP 地址,只能在集群内部访问。就像一个“内部专用通道”。
- NodePort: Service 会在每个 Node 节点上开放一个端口,外部可以通过
NodeIP:NodePort
访问 Service。 相当于在每个节点上都开了一扇“小窗户”。 - LoadBalancer: Service 会请求云服务商创建一个负载均衡器,外部可以通过负载均衡器的 IP 地址访问 Service。 这就像拥有了一个“专用高速公路入口”。
- ExternalName: Service 会将集群内部的 Service 映射到外部的一个域名,相当于一个“别名”。
让我们用一个表格来总结一下:
Service 类型 | 作用 | 访问方式 | 适用场景 |
---|---|---|---|
ClusterIP | 在集群内部创建一个虚拟 IP 地址,提供一个稳定的访问入口。 | 集群内部访问 | 内部服务之间的通信。 |
NodePort | 在每个 Node 节点上开放一个端口,使得可以通过 NodeIP:NodePort 访问 Service。 |
NodeIP:NodePort |
暴露服务给集群外部,但需要手动配置负载均衡。 |
LoadBalancer | 请求云服务商创建一个负载均衡器,外部可以通过负载均衡器的 IP 地址访问 Service。 | 负载均衡器 IP 地址 | 暴露服务给集群外部,并且自动进行负载均衡。 |
ExternalName | 将集群内部的 Service 映射到外部的一个域名。 | 外部域名 | 访问集群外部的服务。 |
DNS 解析: “罗盘”是如何工作的?
现在,我们知道了 Service 的作用,但服务之间如何找到 Service 呢? 这就要靠 DNS 解析这个“罗盘”来指路了!
K8s 集群内部通常会运行一个 DNS 服务,例如 CoreDNS 或 KubeDNS。 当一个 Pod 需要访问一个 Service 时,它会向 DNS 服务发起查询请求,询问 Service 的 IP 地址。
这个查询过程是这样的:
- Pod 发起 DNS 查询: Pod 向 K8s 集群内部的 DNS 服务器 (通常是 CoreDNS) 发起 DNS 查询请求,请求的域名是 Service 的 FQDN (Fully Qualified Domain Name),例如:
my-service.my-namespace.svc.cluster.local
。 - DNS 服务器解析域名: CoreDNS 接收到请求后,会根据 K8s 的 Service 信息进行解析。
- ClusterIP Service: CoreDNS 会返回 Service 的 ClusterIP 地址。
- Headless Service: CoreDNS 会返回所有后端 Pod 的 IP 地址列表。
- Pod 获得 IP 地址: Pod 收到 DNS 服务器返回的 IP 地址后,就可以通过该 IP 地址和 Service 的端口号与 Service 进行通信了。
举个例子:
假设我们有一个名为 my-app
的 Deployment,它需要访问一个名为 my-db
的 Service,这个 Service 位于 default
命名空间中。
那么,my-app
Pod 就可以通过以下域名访问 my-db
Service:
my-db.default.svc.cluster.local
这个域名会被解析为 my-db
Service 的 ClusterIP 地址。
更进一步,我们来拆解一下这个域名:
my-db
: Service 的名称。default
: Service 所在的命名空间。svc
: 表示这是一个 Service。cluster.local
: 集群的域名后缀,可以通过--cluster-domain
参数配置。
那么,DNS 解析是如何与 Service 的类型联系起来的呢?
- ClusterIP Service: DNS 服务器会返回 Service 的 ClusterIP 地址。 就像“罗盘”指向了宝藏的具体位置。
- Headless Service: 这是一种特殊的 Service,它没有 ClusterIP 地址,而是直接将请求转发到后端的 Pod。 DNS 服务器会返回所有后端 Pod 的 IP 地址列表,客户端可以选择其中一个进行连接。 就像“罗盘”指向了多个宝藏的藏宝图。
为什么需要 FQDN 呢?
使用 FQDN 的好处是,它可以确保域名在整个集群中是唯一的。 就像一个人的身份证号码,确保不会有重名的情况发生。
Headless Service:一个有趣的例外
刚才提到了 Headless Service,它有点像个“叛逆者”,不按常理出牌。 它没有 ClusterIP 地址,而是直接将请求转发到后端的 Pod。
Headless Service 有两种类型:
None
: 客户端需要自己发现 Pod 的 IP 地址,例如通过环境变量或者 API Server。ClusterIP: None
: DNS 服务器会返回所有后端 Pod 的 IP 地址列表,客户端可以选择其中一个进行连接。
Headless Service 的应用场景:
- StatefulSet: StatefulSet 是一种特殊的 Deployment,它会为每个 Pod 分配一个唯一的序号和域名。 Headless Service 可以配合 StatefulSet 使用,为每个 Pod 提供一个稳定的域名,方便进行服务发现。
- 需要客户端直接连接 Pod 的场景: 例如,某些数据库需要客户端直接连接到特定的 Pod,以便进行数据同步或者备份。
CoreDNS:K8s 的“御用” DNS 服务器
CoreDNS 是一个用 Go 语言编写的、轻量级的、可扩展的 DNS 服务器。 它被广泛用作 K8s 集群内部的 DNS 服务器,负责解析 Service 的域名,并提供服务发现功能。
CoreDNS 的优点:
- 轻量级: 占用资源少,启动速度快。
- 可扩展: 可以通过插件扩展其功能。
- 与 K8s 集成: 可以自动发现 K8s 的 Service 和 Pod 信息。
- 配置简单: 使用 Corefile 进行配置,易于理解和维护。
CoreDNS 的配置:
CoreDNS 的配置文件是 Corefile,它定义了 CoreDNS 的行为。 Corefile 通常位于 /etc/coredns/Corefile
。
一个典型的 Corefile 如下所示:
.:53 {
errors
health {
lameduck 5
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
prefer_udp
}
cache 30
loop
reload
loadbalance
}
这个 Corefile 的含义如下:
.:53
: 监听所有接口的 53 端口 (DNS 默认端口)。errors
: 启用错误日志。health
: 启用健康检查。ready
: 启用就绪检查。kubernetes
: 启用 K8s 集成,监听cluster.local
域名。pods insecure
: 允许 Pod 通过 DNS 查询 Pod 的 IP 地址。fallthrough
: 如果 DNS 查询无法在 K8s 集群内部解析,则将其转发到上游 DNS 服务器。ttl 30
: 设置 DNS 记录的 TTL (Time To Live) 为 30 秒。
prometheus
: 启用 Prometheus 指标收集,监听 9153 端口。forward
: 将 DNS 查询转发到/etc/resolv.conf
中配置的上游 DNS 服务器。cache
: 启用 DNS 缓存,减少 DNS 查询次数。loop
: 检测 DNS 循环。reload
: 允许动态加载 Corefile。loadbalance
: 启用负载均衡。
Service 发现的幕后英雄:kube-proxy
除了 DNS 解析,还有一个幕后英雄在默默地为 Service 发现保驾护航,它就是 kube-proxy。
kube-proxy 是 K8s 的一个组件,它运行在每个 Node 节点上,负责实现 Service 的虚拟 IP 地址和负载均衡。
kube-proxy 的工作模式:
kube-proxy 有三种工作模式:
- userspace: 这是最古老的工作模式,它通过 userspace 的代理来实现 Service 的负载均衡。 性能较差,不建议使用。
- iptables: 这是默认的工作模式,它通过 iptables 规则来实现 Service 的负载均衡。 性能较好,但规则数量较多时可能会影响性能。
- ipvs: 这是一种更新的工作模式,它通过 IPVS (IP Virtual Server) 来实现 Service 的负载均衡。 性能最好,适用于大规模集群。
kube-proxy 的作用:
- 为 Service 创建虚拟 IP 地址: kube-proxy 会为每个 Service 创建一个虚拟 IP 地址,并将该 IP 地址绑定到 Node 节点上。
- 实现 Service 的负载均衡: kube-proxy 会根据 Service 的类型和配置,将请求转发到后端的 Pod。
- 维护 Service 的 Endpoint 信息: kube-proxy 会定期从 API Server 获取 Service 的 Endpoint 信息,并更新 iptables 规则或 IPVS 配置。
总结:Service 发现的“寻宝图”🗺️
总而言之,K8s 的 Service 发现机制就像一张精密的“寻宝图”,它由以下几个关键要素组成:
- Service: 提供一个稳定的入口点,隐藏后端的 Pod 的变化。
- DNS 解析 (CoreDNS): 将 Service 的域名解析为 IP 地址。
- kube-proxy: 实现 Service 的虚拟 IP 地址和负载均衡。
它们互相协作,共同保证了服务之间的可靠通信,让我们的应用能够稳定运行。
进阶思考:更高级的 Service 发现姿势
除了 K8s 内置的 Service 发现机制,还有一些更高级的 Service 发现方案,例如:
- Service Mesh: 例如 Istio、Linkerd,它们通过在应用之间注入 sidecar 代理,来实现更精细的流量管理、安全策略和可观察性。 Service Mesh 就像一个“智能管家”,负责处理服务之间的所有通信细节。
- Consul、etcd: 这些是独立的 Key-Value 存储系统,可以用来存储 Service 的地址信息,并提供服务发现功能。 它们就像一个“公共注册中心”,所有服务都可以将自己的地址信息注册到这里。
这些高级方案通常用于更复杂的场景,例如微服务架构、跨集群通信等。
结尾:祝你“寻宝”成功!
希望通过今天的讲解,你对 K8s 的 Service 发现机制有了更深入的了解。 记住,Service 发现就像一场有趣的“寻宝游戏”,而 DNS 解析就是指引我们找到宝藏的“罗盘”。 祝你在 K8s 的世界里“寻宝”成功! 💰💰💰
下次有机会,我们再来聊聊 Service Mesh 的那些事儿,敬请期待! 😃