1. Service资源基础概念
1.1 Service资源
Service是Kubernetes标准的API资源类型之一
- 为动态的Pod资源提供近似静态的流量入口
- 服务发现:通过标签选择器筛选同一名称空间下的Pod资源的标签,完成Pod筛选
- 实际上是由与Service同名的Endpoint或EndpointSlice资源及控制器完成
- 流量调度:由运行各工作节点的kube-proxy根据配置的模式生成相应的流量调度规则
- iptables
- ipvs
- 服务发现:通过标签选择器筛选同一名称空间下的Pod资源的标签,完成Pod筛选
- 持续监视着相关Pod资源的变动,并实时反映至相应的流量调度规则之上
1.2 动态可配置负载均衡
从Service的视角来看,Kubernetes集群的每个工作节点都是动态可配置的负载均衡器
- 对于隶属某Service的一组Pod资源,该Service资源能够将集群中的每个工作节点配置为该组Pod的负载均衡器
- 客户端可以是来自集群之上的Pod,也可以是集群外部的其它端点
- 对于一个特定的工作节点上的某Service来说,其客户端通常有两类
- ◆ 该节点之上的进程,可通过该Service的Cluster IP进入
- Service_IP:Service_Port
- ◆ 该节点之外的端点,可经由该Service的NodePort进入
- Node_IP:Node_Port
- ◆ 该节点之上的进程,可通过该Service的Cluster IP进入
显然,若客户端进入的节点,并非目标Pod所在的节点时,报文转发的路径中必然存在跃点
1.3 Service类型
Service根据其所支持的客户端接入的方式,可以分为4种类型
-
ClusterIP:在集群内部进行通信,。
- 功能:它为 Service 分配一个集群内的虚拟 IP 地址(Cluster IP),只能在 Kubernetes 集群内部使用,无法从外部直接访问。
- 场景:当需要集群内服务之间的通信时(例如,前端应用和后端数据库之间的通信)。
- 访问过程: Client --> Service_IP:Service_Port --> Pod_IP:Pod_Port
-
NodePort:从外部访问集群中的 Service,支持ClusterIP
- 功能:在每个节点上开放一个静态端口(30000-32767 之间的端口范围),外部流量通过这个端口可以访问集群内的 Service。虽然这种方式允许外部访问,但它没有提供负载均衡的功能。
- 场景:需要从外部直接访问集群内的应用,但不需要外部负载均衡器时使用。
- 访问过程: Client --> Node_IP:NodePort --> Pod_IP:Pod_Port
-
LoadBalancer:为外部流量提供负载均衡器。
- 功能:向云服务提供商(如 AWS, GCP, Azure)请求外部负载均衡器。该负载均衡器会分配一个外部 IP 地址,并将外部流量通过该 IP 地址分发到后端的 Pods。通常适用于需要暴露给互联网的服务。
- 场景:当你在云环境中运行 Kubernetes,并且需要将服务通过负载均衡器暴露给外部世界时
- 访问过程:Client --> LB_IP:LB_PORT --> Node_IP:NodePort --> Pod_IP:Pod_Port
-
ExternalName:将 Service 映射到外部的 DNS 名称。
- 功能:将 Kubernetes 集群内的 Service 请求重定向到外部的 DNS 名称。它不会创建 Kubernetes 集群内部的代理,而是直接将 DNS 查询映射到外部服务。
- 场景:当你需要从 Kubernetes 内部访问外部服务,并通过 Kubernetes 的 Service 进行管理时(例如访问外部的数据库或 API)。
- 访问过程: ServiceName --> external Service DNS Name
- 负责将集群外部的服务引入到集群中
- 需要借助于ClusterDNS上的CNAME资源记录完成
- 特殊类型,无需ClusterIP和NodePort
- 无须定义标签选择器发现Pod对象
1.4 Endpoint 资源
Endpoint
概念:Endpoint 是 Kubernetes 的一个 API 资源,存储了 Service 的实际后端地址,即符合 Service 标签选择器的 Pod 的 IP 和端口。
作用:当 Service 被创建时,Kubernetes 的控制器会根据 Service 的选择器动态生成或更新相应的 Endpoint 资源,确保流量正确路由到实际的 Pod。每次 Pod 状态或 IP 地址发生变化,Endpoint 也会更新,保证 Service 始终指向有效的后端。
注意:创建 Service时会自动创建Endpoint资源。集群外部服务引入到集群内部使用时,除了使用Service的ExternalName类型外,可以先创建Endpoint指定后端服务器,最后创建同名Service的方法。
EndpointSlice
概念:EndpointSlice 是对传统 Endpoint 资源的扩展,设计用于提高可扩展性和性能。在大型集群中,Endpoint 资源的单一结构可能导致性能瓶颈,因为每个 Service 可能有成百上千的 Pod。EndpointSlice 引入了分片机制,将后端 Pod 分为多个较小的“切片”。
作用:每个 EndpointSlice 只包含一部分后端 Pod 的地址信息,多个 EndpointSlice 可以一起提供完整的 Pod 列表。这样,当集群规模较大时,可以减少对单个资源的压力,提高网络性能和稳定性。
示例
Readiness Probe 的结果直接影响着 Kubernetes 中 Endpoint 的注册。当 Readiness Probe 检查通过时,Kubernetes 会将该 Pod 添加到对应的 Endpoint 中,表示这个 Pod 可以接收流量。反之,如果 Pod 的 Readiness Probe 失败,Kubernetes 会从 Endpoint 中移除这个 Pod,从而避免将流量发送给不健康或未准备好的 Pod。
2. Service及流量转发
2.1 创建Service资源
由Service表示的负载均衡器,主要定义如下内容
- 负载均衡器入口:ClusterIP及相关的Service Port、NodePort(每个节点的Node IP都可用)
- 根据通信需求,确定选择的类型
- 标签选择器:用于筛选Pod,并基于筛选出的Pod的IP生成后端端点列表(被调度的上游端点)
- Service类型的专有配置
2.2 标签和标签选择器
标签:附加在资源对象上的键值型元数据
- 键标识:由“键前缀(可选)”和“键名”组成,格式为“key_prefix/key_name”
- 键前缀必须使用DNS域名格式
- 键名的命名格式:支持字母、数字、连接号、下划线和点号,且只能以字母或数字开头;最长63个字符;
- “kubectl label”命令可管理对象的标签
标签选择器:基于标签筛选对象的过滤条件,支持两种类型
- 基于等值关系的选择器
- 操作符:=或==、!=
- 基于集合关系的选择器
- 操作符:in、notin和exists
- 使用格式:KEY in (VALUE1, VALUE2, …)、 KEY notin (VALUE1, VALUE2, …)、KEY 和 !KEY
示例:
添加标签,标签已存在,使用--overwrite覆盖
使用-号删除标签
添加Annotations注解示例
基于等值关系的选择器,1.过滤app=redis的pod 2.过滤app不等于redis的pod,同样会列出没有app标签的pod
基于集合关系的选择器,in表示app里面也有等于mysql wordpress demoapp的都符合条件。notin表示app不匹配mysql wordpress demoapp的以及没有app标签的都符合条件
存在性判定,匹配有app标签和没有app标签的pod
2.3 Service资源规范
Kubernetes上标准的API资源类型
apiVersion: v1
kind: Service
metadata:
name: …
namespace: …
spec:
type <string> # Service类型,默认为ClusterIP
selector <map[string]string> # 等值类型的标签选择器,内含“与”逻辑
ports: # Service的端口对象列表
- name <string> # 端口名称
protocol <string> # 协议,目前仅支持TCP、UDP和SCTP,默认为TCP
port <integer> # Service的端口号
targetPort <interger> # 后端目标进程的端口号或名称,名称需由Pod规范定义
nodePort <integer> # 节点端口号,仅适用于NodePort和LoadBalancer类型
clusterIP <string> # Service的集群IP,建议由系统自动分配
externalTrafficPolicy <string> # 外部流量策略处理方式,Local表示由当前节点处理,Cluster表示向集群范围调度
loadBalancerIP <string> # 外部负载均衡器使用的IP地址,仅适用于LoadBlancer
externalName <string> # 外部服务名称,该名称将作为Service的DNS CNAME值
2.4 Service资源示例
2.4.1 ClusterIP Service示例
---
kind: Service
apiVersion: v1
metadata:
name: demoapp-svc
namespace: demo
spec:
selector:
app: demoapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
internalTrafficPolicy: Cluster: 决定流量的路由策略,Cluster 意味着允许集群内的流量,sessionAffinity: None: 不使用会话亲和性(Session Affinity),意味着同一个客户端的请求不一定会总是被路由到同一个 Pod。
创建临时pod,使用curl命令测试访问serviceIP和名称,使用名称访问需要加名称空间,默认解析为default名称空间。pod使用的DNS为cluster dns,该dns为service网络的第十个地址
### 2.4.2 NodePort Service示例
---
kind: Service
apiVersion: v1
metadata:
name: demoapp-nodeport-svc
namespace: demo
spec:
type: NodePort
selector:
app: demoapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
# nodePort: 31398
# externalTrafficPolicy: Local
集群内部访问测试
使用nodeport集群外部访问测试
2.4.3 LoadBalancer Service示例
kind: Service
apiVersion: v1
metadata:
name: demoapp-loadbalancer-svc
namespace: demo
spec:
type: LoadBalancer
selector:
app: demoapp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
#loadBalancerIP: 1.2.3.4
externalTrafficPolicy: Local
访问测试
2.5 NodePort Service流量策略
流量策略一:Cluster,表示在整个Kubernetes集群范围内调度;
- 该流量策略下,请求报文从某个节点上的NodePort进入,该节点上的Service会将其调度至任何一个可用后端Pod之上,而不关心Pod运行于哪个节点;
流量策略二:Local,表示仅将请求调度至当前节点上运行的可用后端端点;
- 该流量策略下,请求报文从某节点NodePort进入后,该节点上的Service仅会将请求调度至当前节点上适配到该Service的后端端点
- 仅应该从运行有目标Service对象后端Pod对象的节点的NodePort 发起访问
- 需要在上层做一个loadbalancer
LoadBalancer类型的Service
在接入外部流量方面,NodePort存在着几个方面的问题
- 非知名端口、私网IP地址、节点故障转移、节点间负载均衡、识别能适配到某Service的Local流量策略的节点等
- 外置的Cloud Load Balancer可以解决以上诸问题
Service的externalTrafficPolicy字段用于控制集群外部流量进入集群时的路由和流量处理方式。它有两个可选值:Cluster和Local
- Cluster
- 行为:流量进入集群后,会通过 kube-proxy 负载均衡,可能会将流量转发到任意可用的 Pod,无论该 Pod 是否在接收流量的节点上运行。
- 作用:这种模式提供了跨集群节点的均衡负载,因此,所有节点都可以接收外部流量。
- 缺点:由于可能涉及跨节点的流量转发,源 IP 地址会被 kube-proxy 隐藏,外部客户端的真实 IP 无法传递给应用。
- Local
- 行为:流量只会路由到当前节点上正在运行相应 Service 的 Pod,不会进行跨节点的流量转发。
- 作用:这种模式可以保留客户端的源 IP,因为没有跨节点的流量转发。
- 缺点:如果某个节点上没有对应的 Pod,则该节点不会处理外部流量,负载均衡需要更精确。
3. Service名称解析
3.1 Service和Cluster DNS
Cluster DNS(CoreDNS)是Kubernetes集群的必备附件,负责为Kubernetes提供名称解析和服务发现
- 每个Service资源对象,在CoreDNS上都会自动生成一个遵循“<service>.<ns>.svc.<zone>”格式的名称
- <service>:当前Service对象的名称
- <ns>:当前Service对象所属的名称空间
- <zone>:当前Kubernetes集群使用的域名后缀,默认为“cluster.local”
- 围绕该名称会生成一些DNS格式的资源记录
CoreDNS会持续监视API Server上的Service资源对象的变动,并实时反映到相关的DNS资源记录中
Pod中各容器默认会在/etc/resolv.conf中,将nameserver指向CoreDNS相关的Service的ClusterIP
- 由kubelet创建Pod时根据指定的配置自动注入
示例:
进入容器内部解析service相关记录
3.2 Service在Cluster DNS上的资源记录
每个Service,在CoreDNS上都会有A/AAAA、SRV和PTR资源记录
- A/AAAA资源记录
- <service>.<ns>.svc.<zone>. <ttl> IN A <cluster-ip>
- <service>.<ns>.svc.<zone>. <ttl> IN AAAA <cluster-ip>
- 为每个定义了名称的端口生成一个SRV记录,以支持服务发现
- _<port>._<proto>.<service>.<ns>.svc.<zone>. <ttl> IN SRV <weight> <priority> <port-number> <service>.<ns>.svc.<zone>.
- 为每个A记录(例如a.b.c.d)或AAAA记录生成对应的PTR记录,例如
- <d>.<c>.<b>.<a>.in-addr.arpa. <ttl> IN PTR <service>.<ns>.svc.<zone>.
- h4.h3.h2.h1.g4.g3.g2.g1.f4.f3.f2.f1.e4.e3.e2.e1.d4.d3.d2.d1.c4.c3.c2.c1.b4.b3.b2.b1.a4.a3.a2.a1.ip6.arpa <ttl> IN PTR <service>.<ns>.svc.<zone>.
Pod可基于Service的DNS名称向其发起服务访问请求
3.3 Pod上的DNS解析策略
- Kubernetes支持在单个Pod资源规范上自定义DNS解析策略和配置,并组合生效
- spec.dnsPolicy:解析策略
- spec.dnsConfig:名称解析机制
- DNS解析策略
- Default:从运行在的节点继承DNS名称解析相关的配置
- ClusterFirst:于集群DNS服务上解析集群域内的名称,其他域名的解析则交由从节点继承而来的上游名称服务器
- ClusterFirstWithHostNet:专用于在设置了hostNetwork的Pod对象上使用的ClusterFirst策略
- None:用于忽略Kubernetes集群的默认设定,而仅使用由dnsConfig自定义的配置
- DNS解析机制
- nameservers <[]string>:DNS名称服务器列表,附加于由dnsPolicy生成的DNS名称服务器之后
- searches <[]string>:DNS名称解析时的搜索域,附加由于dnsPolicy生成的搜索域之后
- options <[]Object>:DNS解析选项列表,同dnsPolicy生成的解析选项合并成最终生效的定义
示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-with-dnspolicy
namespace: default
spec:
containers:
- name: demo
image: ikubernetes/demoapp:v1.0
imagePullPolicy: IfNotPresent
dnsPolicy: None #忽略集群默认设定使用dnsConfig自定义配置
dnsConfig:
nameservers:
- 10.96.0.10
- 223.5.5.5
- 223.6.6.6
searches: #搜索域
- svc.cluster.local
- cluster.local
- ilinux.io
options: #搜索域中间点号不能超过5个
- name: ndots
value: "5"
3.4 Headless Service
Service的各类型中,ClusterIP、NodePort和LoadBalancer都为其Service配置一个ClusterIP,CoreDNS上,这些Service对象的A记录也解析为它的ClusterIP;
广义上,那些没有ClusterIP的Service则称为Headless Service,它们又可以为分两种情形
- 有标签选择器,或者没有标签选择器,但有着与Service对象同名的Endpoint资源
- Service的DNS名称直接解析为后端各就绪状态的Pod的IP地址
- 调度功能也将由DNS完成
- 各Pod IP相关PTR记录将解析至Pod自身的名称,假设Pod IP为a.b.c.d,则其名称为a-b-c-d.<service>.<ns>.svc.<zone>
- 这种类型也就是狭义上的Headless Service
- 无标签选择器且也没有与Service对象同名的Endpoint资源
- Service的DNS名称将会生成一条CNAME记录,对应值由Service对象上的spec.externalName字段指定
示例:
externalname示例
[root@k8s-master01 services]#vim externalname-redis-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: externalname-redis-svc
namespace: default
spec:
type: ExternalName
externalName: redis.ik8s.io
ports:
- protocol: TCP
port: 6379
targetPort: 6379
nodePort: 0
selector: {}
解析该externalname服务会解析为redis.ik8s.io的ip地址
Headless Service示例
[root@k8s-master01 services]#vim demoapp-headless-svc.yaml
---
kind: Service
apiVersion: v1
metadata:
name: demoapp-headless-svc
spec:
clusterIP: None
selector:
app: demoapp
ports:
- port: 80
targetPort: 80
name: http
~
解析该无头服务时,解析为后端pod对应的ip地址,使用ptr反解pod的ip,解析为pod自己的主机名。
endpoints示例
[root@k8s-master01 services]#cat mysql-endpoints-demo.yaml
apiVersion: v1
kind: Endpoints
metadata:
name: mysql-external
namespace: default
subsets:
- addresses:
- ip: 172.29.9.51
- ip: 172.29.9.52
ports:
- name: mysql
port: 3306
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: mysql-external
namespace: default
spec:
type: ClusterIP
ports:
- name: mysql
port: 3306
targetPort: 3306
protocol: TCP
手动创建endpoints和service
4. CoreDNS配置方式简介
4.1 CoreDNS的默认配置
CoreDNS的配置都存储在名为coredns的ConfigMap对象中,该对象位于kube-system名称空间中
[root@k8s-master01 coredns]# kubectl get cm coredns -o yaml -n kube-system
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
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 {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
creationTimestamp: "2024-08-08T10:14:01Z"
name: coredns
namespace: kube-system
resourceVersion: "215"
uid: 8ca29b2a-96c6-4fdf-b61a-8dfe633b71e8
#服务器配置段 (Server Blocks),用于定义负责解析的权威区域,配置段放置于其后的花括号{}中;
#服务器配置段也可以指定要监听的端口号 (端口号之前需要使用一个冒号),默认为53;
#若在同一端口上配置了多个区域CoreDNS将使用最长匹配机制来评估并挑出最适配的服务器配置段;
#随后,请求将由该服务器配置段中的插件链按特定顺序 (在构建CoreDNS程序时由plugin.cfg文件指定) 进行路由;
#针对一个DNS查询,相应配置段插件链中的每个插件都会检查并确定是否应该对其进行处理
#每个服务器配置段都需要配置一些要使用的插件 (这些插件也可称为该服务器的插件链),用来为该服务器提供更加丰富的功能与配置,例如配置中的errors、health、ready、kubernetes、prometheus .forward等
CoreDNS的插件可大致分为两类
#负责处理请求的常规插件,这些插件才是插件链中的有效组成部分,例如errors、kubernetes和forward等;
#不处理请求的特殊插件,它们仅用来修改Server或Server Block中的配置,例如health、tls、startup、shutdown和root等插件;
这些用于处理请求的插件又大体可以分为两类:
#负责执行请求的插件
#后端插件: 用于配置区域数据的来源例如etcd、file和kubernetes等
4.2 CoreDNS上常用的插件简介
4.3 CoreDNS查询路由概述
CoreDNS处理DNS查询的方式:
- 针对每个套接字,CoreDNS会生成一个服务器(dnsserver.Server)
- 一个套接字上存在多个配置段(Server Block)时,CoreDNS将组合这些配置段生成单个服务器上的多个独立配置段,并将发往该套接字的DNS查询请求路由到最佳匹配的目标配置段
- 若不存在匹配的服务器配置段,则返回SERVERFAIL
CoreDNS的插件可大致分为两类:
- 负责处理请求的常规插件(Normal Plugin),这些插件才是插件链中的有效组成部分,例如errors、kubernetes和forward等
- 不处理请求的特殊插件,它们仅用来修改Server或Server Block中的配置,例如health、tls、startup、shutdown和root等插件,这类插件不会作为服务器配置段的插件链中的有效组成部署
常规插件可再次划分为两种类型:
- 负责以某种方式处理请求的插件
- 这类插件不是区域数据源,它们的运行方式是在自身处理完成后,会将查询传递给下一个插件
- 后端插件
- 用于配置区域数据的来源,例如etcd、file和kubernetes等
- 这类插件通常要为其负责的区域生成最终结果,它要么能正常响应查询,要么返回NXDOMAIN
- 但也可以使用fallthrough改变这种响应行为:未发现查询的目标资源记录时,将DNS查询请求转交给插件链中的下一个插件,随后终结于另一个后端插件,或再次由fallthrought改变这种行为
4.3.1 CoreDNS查询路由示例
配置示例
路由处理办法及相应的插件链
4.3.2 CoreDNS的kubernetes插件
插件的配置参数简介
- endpoint:指定kubernetes API Server的URL,默认为CoreDNS Pod所使用的ServiceAccount可接入的自身所在集群的API Server
- tls:用于建立远程k8s连接时要使用的tls证书、私钥和CA证书
- kubeconfig:用于谁到远程k8s时使用的kubeconfig文件
- namespaces:仅对外暴露(提供Service名称解析)的k8s名称空间的列表,默认为所有名称空间
- labels:namespace资源对象的标签选择器,匹配到的namespace中的Service才会对外暴露
- pods:为Pod生成基于IP的资源记录时的处理模式
- disabled:不处理Pod级别的名称解析请求,默认配置
- insecure:不检查k8s,而直接返回一个带有IP地址的A记录
- verified:若同一namespace中存在具有匹配的IP地址的Pod,则返回A记录
- noendpoints:禁止endpoint相关的资源记录,所有endpoint查询和headless查询都将生成NXDOMAIN
- fallthrough:若当前插件解析失败,则仅将针对指定zone列表中的查询请求继续交由插件链中后续的插件进行处理
- ignore empty_service:为没有任何就绪的Service返回NXDOMAIN
4.3.3 CoreDNS的rewrite插件
在CoreDNS内部对查询及响应进行重写,重写过程对客户端透明
语法:rewrite [continue|stop] FIELD [TYPE] [(FROM TO)|TTL] [OPTIONS]
- FIELD:用于指定请求或响应中的哪部分内容被重写
- type:请求的类型字段被重写,此时FROM/TO必须是DNS记录类型,如A、MX等
- name:重写查询请求中要查询的名称,默认情况下,其将执行名称的完全匹配
- class:消息的类别被重写,此时FROM/TO必须是DNS class的类型,如IN、CH或HS等
- edns0:将EDNS0选项附加到请求中
- ttl:重写响应报文中的TTL值
- TYPE:FILE字段为name时,用于指定匹配name值的方式
- exact(默认):精确匹配,与查询请求中的名称完全匹配
- substring:匹配查询请求中的名称的子串
- prefix:匹配查询请求中的名称的前缀
- suffix:匹配查询请求中的名称的后缀
- regex:使用正则表达式模式匹配查询请求中的名称
- FROM:要匹配的名称或类型
- TO:要重写成的目标名称或类型
- TTL:在响应报文中要设定的ttl值,仅适用于ttl FIELD
语法
- OPTIONS:name FIELD还支持对响应报文进行隐式重写
- answer auto:尽力完成响应报文中名称部分的重写
- answer name FROM TO:将响应报文中的匹配FROM的查询名称重写为TO
- answer value FROM TO:将响应报文中的匹配FROM的用于(例如CNAME或SRV资源记录中)响应的名称重写为TO
- continue:继续由后面的rule进行处理
- stop:将当前rule视作最后一条,即当前rule处理完成后即返回响应;此为默认行为
一般来说,重写查询的name比较常见
- 语法:rewrite [continue|stop] name [exact|prefix|suffix|substring|regex] STRING STRING [OPTIONS]
- 例如:rewrite name regex (jenkins.*)\.magedu\.com {1}.jenkins.svc.cluster.local
响应报文rewrite
-
隐式的响应重写,可以定义在rewrite name规则的OPTIONS中
- 例如: rewrite name regex (jenkins.*)\.magedu\.com {1}.jenkins.svc.cluster.local answer auto
- 例如: rewrite name regex (jenkins.*)\.magedu\.com {1}.jenkins.svc.cluster.local answer auto
-
显式报文重写,要使用明确定义的answer规则进行
- 例如
- 例如
示例1:
#导出coredns的配置并添加rewrite配置,应用生效
[root@k8s-master01 ~]#kubectl get cm coredns -n kube-system -o yaml >> /tmp/coredns.yaml
[root@k8s-master01 ~]#cat /tmp/coredns.yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
rewrite name demoapp-svc.magedu.com demoapp-svc.demo.svc.cluster.local
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
[root@k8s-master01 ~]#kubectl apply -f /tmp/coredns.yaml
测试解析demoapp-svc.magedu.com重写成了demoapp-svc.demo.svc.cluster.local的ip地址
示例2:
[root@k8s-master01 ~]#cat /tmp/coredns.yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
rewrite name regex (demoapp.*).magedu.com {1}.demo.svc.cluster.local answer auto #响应自动重写
#answer name (demoapp.*).demo.svc.cluster.local {1}.magedu.com #显示报文重写
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
[root@k8s-master01 ~]#kubectl apply -f /tmp/coredns.yaml
configmap/coredns configured
默认使用正regex正则,响应结果为非透明的,客户端看到的响应域名与查询域名不一致。
配置answer auto测试发现响应解析域名与查询一致。
显示重写配置
CoreDNS配置示例
prefer_udp:使用udp协议查询解析
forward:可以配置多个解析不同区域,多个forward时需要添加fallthrough,避免一个forward解析不了无法传递给下一个进行解析
[root@k8s-master01 ~]#cat /tmp/coredns.yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
rewrite {
name regex (demoapp.*).magedu.com {1}.demo.svc.cluster.local
answer name (demoapp.*).demo.svc.cluster.local {1}.magedu.com
}
hosts { #使用hosts解析节点名称
10.0.0.101 k8s-master01.magedu.com
10.0.0.102 k8s-node01.magedu.com
10.0.0.103 k8s-node02.magedu.com
fallthrough #该配置避免hosts无法解析其他域名时转发给下一配置进行解析
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf { #将根区域转发给节点DNS服务器进行解析
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
测试效果
5. Service流量转发小结
5.1 Service流量转发机制
- ClusterIP类型
- 源自Pod
- 没启动masquerade-all(全地址转换):请求报文的目标IP和目标端口由Service转为挑选出的后端Pod的IP和端口,并由后端Pod直接响应给客户端Pod
- 发夹问题:Pod访问自身所属的Service后,由Service又调度回该Pod
- 存在发夹问题(haripin)的场景中,需要启用源IP地址转换
- 启用masquerade-all:请求报文的源IP和目标IP都将由Service进行转换,原IP将转为客户端Pod所在节点在Pod网络中的IP地址
- 没启动masquerade-all(全地址转换):请求报文的目标IP和目标端口由Service转为挑选出的后端Pod的IP和端口,并由后端Pod直接响应给客户端Pod
- 源自非Pod网络中的请求流量
- 接入流量的节点充当NAT网关,请求报文的源IP和目标IP都将由Service进行转换
- 源自Pod
- NodePort和LoadBalancer类型
- 流量来自集群外部,节点扮演网关的角色,请求报文的源IP和目标IP都将由Service进行转换,原IP将转为客户端Pod所在节点的IP地址,以确保响应报文能正确送达
流量转发示意图:请求报文,目标地址转换都会进行,未启用masquerade-all时,源地址转换将视情况进行
- Pod网络是虚拟网络,最终还是要通过节点网络完成报文传送,因此,SNAT通常会使用节点网络中的地址