文章目录
- 简单了解 k8s Service
- 为什么需要Service
- Service 的机制
- 简单了解Service类型
- 为什么需要 DNS
- 环境变量注入(服务发现)
- 缺点
- 什么是DNS
- Pod 如何知道 DNS服务器地址
- DNS域名解析原理
- A记录
- SRV 记录
- CNAME 记录
- K8s 域名解析策略
- None
- ClusterFirstWithHostNet
- ClusterFirst
- Default
简单了解 k8s Service
为什么需要Service
- 云原生,指的就是快速扩缩容,适应动态变化等,这样的机制就会使得pod的IP不是固定的,每次重启,都会变动
- 由于pod对应的IP容易变动,因为pod的重启,其IP就会和原来不同,如果相关联服务,采用pod IP,那每次pod 重启就需要修改使用此服务的IP
- 因此 k8s Service 提供了一个稳定访问的机制,提供稳定的IP
Service 的机制
- Service的命名机制
{service name}.{service namespace}.svc.{domin}
- domin部分可由kubelet配置,参数为
--cluster-dns=<dns service ip\>
,此可配置集群域名后缀,默认为cluster.local
- Service 提供的 IP 成为 cluster IP,是个虚拟 IP,直接访问是无法访问的,必须要结合 端口port
- Service 是一组逻辑上关联的 pod
- 利用 selector,将label为 app:MyApp 的 pod 聚合在一起,形成个组,我们可以称为 Endpoints,这也是一种k8s资源
- EndPoints 在 Service 有 selector时会自动创建,在没有selecotr时则不会创建
- 所以现在的关系是 Service(Cluster IP)–> Endpoints --> 一组Pod(Pod ip)
- 就是Service是个空头司令,Endpoints 相当于个小班长,Pod才是干活的,这样的管理机制,这是管理层(备注:Service 和 Endpoints 是同名的,这样才知道我们都是三连或几连的)
- 如何从Service下发指令到Pod呢?
kube-proxy
出来啦,其相当于一个通讯兵,通过iptables或ipvs规则,架设通讯线路,这样就完成了命令的下发 - 此种Service的DNS 映射关系为
{service name}.{service namespace}.svc.{domin}
-->Cluster IP
- 特殊的Service(Headless Service)
- 这种Service没有selector,就是没有聚合器
- 此种 Service 不会产生 Cluster IP,但是还是具有自己的名字my-service,可通过dns进行域名访问,但目前无工作pod
- 不过目前就是光杆司令,连个小弟都没有
- 但是若创建同名的Endpoints,则会自动关联上,就相当于找到了失散的兄弟
- Endpoints会带有selector,也就是有一组关联的Pod,也就是更好消息,好兄弟还领着一帮人一起
- 此种Service的DNS 映射关系为
{service name}.{service namespace}.svc.{domin}
-->后端Pod IP 列表
# 普通service
# 下面就是说访问 Service 就会 访问到对应容器的 9376端口
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80 # service 端口
targetPort: 9376 # 容器端口
-----
# 无头service(headless service)
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
简单了解Service类型
类型 | ||
普通服务 | Cluster IP | 四层负载均衡,就是 ip+port 到某个具体pod |
Load Balancer | 外部负载均衡 | 通过loadBalancerSourceRanges 限制 哪些范围IP可访问此服务 |
NodePort | 开启一个端口,供外部访问 | 但要保证所在主机的IP的外部可以访问的 |
无头Service | 没有NodeSecltor | |
Ingress | 七层负载均衡,就是url+端点到不同服务 | 这个不属于Service,k8s有Ingress资源 七层负载均衡举例: host:www.example.com path: /foo --> service1 path:/bar --> service2 |
为什么需要 DNS
因为最早采用环境变量注入pod方式,有很多不便之处
环境变量注入(服务发现)
最早时候,为了让Pod可以访问集群内的服务,kubelet会预先将系统当前所有服务的IP和端口信息,以环境变量
的形式注入到容器中。这样Pod中的应用可通过读取环境变量,从而获得所需服务的地址信息。
简单举例,Kubelet为每个Pod注入如下环境变量信息
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
...
...
目前所有已启动的Service的信息
缺点
- 容易环境变量泛滥,Docker启动参数过长,影响性能,甚至直接导致容器启动失败
- Pod想要访问的任何Service,必须要在Pod被创建前创建,否则这些环境变量就不会被注入
什么是DNS
白话来说,就是集群内启动个DNS服务器,当Pod想访问某个Service却不知道时,直接问该DNS服务器,服务器则会返回给他相应的IP地址
- DNS存储的就是 域名和IP的映射
- Pod去访问时,用的是域名,之后得到相应的IP,因为IP才可以用于网络传输
Pod 如何知道 DNS服务器地址
kubelet
会将DNS Server 的 IP地址写到容器的/etc/resolv.conf
文件中
具体来说
- 集群内 DNS 服务启动后,会获得 Cluster IP (就是Service 的IP,但只能在集群内使用)
- 系统(安装程序)会给kubelet配置 --cluster-dns=<dns service ip>
- 该 DNS IP 则会在容器启动时传递,写入到每个容器的
/etc/resolv.conf
文件中
DNS域名解析原理
对于 Service,K8s DNS服务器会生成三类 DNS 记录,分别是 A 记录、 SRV 记录、 CNAME 记录
A记录
- 用于将域或子域指向某个IP地址,是DNS记录的最基本类型
- 记录包含域名,解析它的IP地址和以秒为单位的TTL,TTL代表生存时间,是此记录的到期时间
- 普通Service的A记录的映射关系
-
{service name}.{service namespace}.svc.{domin}
-->Cluster IP
- headless Service 的 A 记录映射关系:
-
{service name}.{service namespace}.svc.{domin}
-->后端Pod IP 列表
- 如果 Pod Spec 指定 hostname 和 subdomin,那么会额外生成 Pod 的 A 记录
-
{hostname}.{subdomain}.{pod namespace}.pod.cluster.local
-->Pod IP
SRV 记录
- 通过描述某些服务协议和地址促进服务发现
- 定义一个符号名称和作为域名一部分的传输协议,并定义给定服务的优先级、权重、端口和目标
_sip._tcp.example.com. 3600 IN SRV 10 70 5060 srvrecord.example.com
_sip._tcp.example.com. 3600 IN SRV 10 20 5060 srvrecord2.ex
_sip 是服务的符号名称
_tcp 是服务使用的传输协议
两个记录都定义了10的优先级
第一个指定权重70,第二个指定权重20
最后两值定义了要连接的端口和主机名,以便与服务通信
- k8s DNS 的 SRV 记录按照一个约定出城的规定实现了对服务端口的查询
-
_{port name}._{port protocol}.{service name}.{service namespace}.svc.cluster.local
-->Service Port
- SRV 记录是为 普通 或 headless 服务的部分指定端口创建的
- 普通服务
- 被解析的端口号和域名是 my-svc.my-namespace.svc.cluster.local
- Headless 服务
- 此 name 解析为多个 answer,每个 answer 都支持服务
- 每个 answer 都包含 auto-generated-name.my-svc.my-namespace.svc.cluster.local 表单的 Pod 端口号和域名
CNAME 记录
- 别名
- 用于将域或子域指向另一个主机名
- 可用于联合服务的跨集群服务发现
K8s 域名解析策略
None
- 没有
- k8s 1.9 版本引入一个新选项值,允许 Pod 忽略 K8s 环境中的 DNS 设置
ClusterFirstWithHostNet
- 对于使用主机网络的 Pod,是可以直接访问宿主机的 /etc/resolv.conf 文件的
- 因此默认会使用宿主机的 DNS 配置,因此会导致集群内的容器无法通过域名访问集群内的服务
- 所以对于使用 hostNetwork 的 Pod,用户应该明确设置其 DNS 策略为 ClusterFirstWithHostNet
ClusterFirst
- 任何与配置的集群域后缀不匹配的 DNS 查询,将转发到从宿主机上集成的上游域名服务器
- 所以集群管理员应根据需要配置上游 DNS 服务器
Default
- Pod 从宿主机上集成名称解析配置