文章目录

  • 简单了解 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的信息

缺点

  1. 容易环境变量泛滥,Docker启动参数过长,影响性能,甚至直接导致容器启动失败
  2. Pod想要访问的任何Service,必须要在Pod被创建前创建,否则这些环境变量就不会被注入

什么是DNS

白话来说,就是集群内启动个DNS服务器,当Pod想访问某个Service却不知道时,直接问该DNS服务器,服务器则会返回给他相应的IP地址

  • DNS存储的就是 域名和IP的映射
  • Pod去访问时,用的是域名,之后得到相应的IP,因为IP才可以用于网络传输

Pod 如何知道 DNS服务器地址

kubelet会将DNS Server 的 IP地址写到容器的/etc/resolv.conf文件中

具体来说

  1. 集群内 DNS 服务启动后,会获得 Cluster IP (就是Service 的IP,但只能在集群内使用)
  2. 系统(安装程序)会给kubelet配置 --cluster-dns=<dns service ip>
  3. 该 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 从宿主机上集成名称解析配置