一、Service定义详解

YAML格式的Service定义文件的完整内容如下:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图1
对各属性的说明如下表所示:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图2
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图3

二、Service的基本用法

2.1、创建Service

一般来说,对外提供服务的应用程序需要通过某种机制来实现,对于容器应用最简便的方式就是通过TCP/IP机制及监听IP和端口号来实现。
直接通过Pod的IP地址和端口号可以访问到容器应用内的服务,但是Pod的IP地址是不可靠的,并且Pod的地址只能在K8S集群内访问到,例如:当Pod所在的Node发生故障时,Pod将被Kubernetes重新调度到另一个Node,Pod的IP地址将发生变化。更重要的是,如果容器应用本身是分布式的部署方式,通过多个实例共同提供服务,就需要在这些实例的前端设置一个负载均衡器来实现请求的分发。Kubernetes中的Service就是用于解决这些问题的核心组件。

  • pod ip地址变化问题
  • 多pod负载均衡问题

两种创建Service的方式:

  • 通过expose 命令创建
  1. # 通过 expose 命令创建,端口默认与Pod端口保持一致
  2. $ kubectl expose <rc> <rc-name>
  • 通过yaml文件创建
    【Kubernetes详解】(八)k8s 之 Service 详解一 - 图4
    Service定义中的关键字段是ports和selector。上例中ports定义部分指定了Service所需的虚拟端口号为8081,由于与Pod容器端口号8080不一 样,所以需要再通过targetPort来指定后端Pod的端口号。selector定义部分设置的是后端Pod所拥有的label:app=webapp。

可以通过如下命令来查看ClusterIp和端口:

  1. $ kubectl get svc -n <namespace>

【Kubernetes详解】(八)k8s 之 Service 详解一 - 图5

2.2、负载分发策略

  • RoundRobin:轮询模式,即轮询将请求转发到后端的各个Pod 上。
  • SessionAffinity:基于客户端IP地址进行会话保持的模式,即第 1次将某个客户端发起的请求转发到后端的某个Pod上,之后从相同的客 户端发起的请求都将被转发到后端相同的Pod上。

在默认情况下,Kubernetes采用RoundRobin模式对客户端请求进行负载分发,但我们也可以通过设置service.spec.sessionAffinity=ClientIP来启用SessionAffinity策略。这样,同一个客户端IP发来的请求就会被转发到后端固定的某个Pod上了。
通过Service的定义,Kubernetes实现了一种分布式应用统一入口的定义和负载均衡机制。Service还可以进行其他类型的设置,例如:设置多个端口号、直接设置为集群外部服务,或实现为Headless Service(无头 服务)模式。

2.3、多端口Service

有时一个容器应用也可能提供多个端口的服务,那么在Service的定 义中也可以相应地设置为将多个端口对应到多个应用服务。示例:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图6

三、Headless Service

在某些应用场景中,开发人员希望自己控制负载均衡的策略,不使 用Service提供的默认负载均衡的功能,或者应用程序希望知道属于同组 服务的其他实例。Kubernetes提供了Headless Service来实现这种功能, 即不为Service设置ClusterIP(入口IP地址),仅通过Label Selector将后 端的Pod列表返回给调用的客户端。例如:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图7

四、从集群外部访问Pod或Service

由于Pod和Service都是Kubernetes集群范围内的虚拟概念,所以集群 外的客户端系统无法通过Pod的IP地址或者Service的虚拟IP地址和虚拟 端口号访问它们。为了让外部客户端可以访问这些服务,可以将Pod或 Service的端口号映射到宿主机,以使客户端应用能够通过物理机访问容器应用。

4.1、将容器应用的端口号映射到物理机

4.1.1、通过设置容器级别的hostPort,将容器应用的端口号映射到物理机上:

【Kubernetes详解】(八)k8s 之 Service 详解一 - 图8

4.1.2、通过设置Pod级别的hostNetwork=true

该Pod中所有容器的端 口号都将被直接映射到物理机上。在设置hostNetwork=true时需要注 意,在容器的ports定义部分如果不指定hostPort,则默认hostPort等于 containerPort,如果指定了hostPort,则hostPort必须等于containerPort的值:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图9

4.2、将Service的端口号映射到物理机

4.2.1、通过设置nodePort映射到物理机,同时设置Service的类型为NodePort

【Kubernetes详解】(八)k8s 之 Service 详解一 - 图10

4.2.2、通过设置LoadBalancer映射到云服务商提供的LoadBalancer地 址。这种用法仅用于在公有云服务提供商的云平台上设置Service的场景。

五、DNS服务搭建和配置指南

作为服务发现机制的基本功能,在集群内需要能够通过服务名对服 务进行访问,这就需要一个集群范围内的DNS服务来完成从服务名到 ClusterIP的解析。
DNS服务在Kubernetes的发展过程中经历了3个阶段:
SkyDNS -> KubeDNS -> CoreDNS
Kubernetes集群的DNS服务由CoreDNS 提供。CoreDNS是CNCF基金会的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端。CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains设置,等等。
CoreDNS支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS。
CoreDNS没有使用多个容器的架构,只用一个容器便实现了 KubeDNS内3个容器的全部功能。

【Kubernetes详解】(八)k8s 之 Service 详解一 - 图11

下面以CoreDNS为例说明Kubernetes集群DNS服务的搭建过程:

5.1、在创建DNS服务之前修改每个Node上 kubelet 的启动参数

修改每个Node上kubelet的启动参数,加上以下两个参数。

  1. --cluster-dns=169.169.0.100:为DNS服务的ClusterIP地址。
  2. --cluster-domain=cluster.local:为在DNS服务中设置的域名。

然后重启kubelet服务。

5.2、创建CoreDNS应用

在部署CoreDNS应用前,至少需要创建一个ConfigMap、一个 Deployment和一个Service共3个资源对象。在启用了RBAC的集群中,还 可以设置ServiceAccount、ClusterRole、ClusterRoleBinding对CoreDNS容器进行权限设置。

  • ConfigMap “coredns”主要设置CoreDNS的主配置文件Corefile的内容,其中可以定义各种域名的解析方式和使用的插件;
  • Deployment “coredns”主要设置CoreDNS容器应用的内容;其中,replicas副本的数量通常应该根据集群的规模和服务数量确定,如果单个CoreDNS进程不足以支撑整个集群的DNS查询,则可以通过水平扩展提高查询能力。由于DNS服务是Kubernetes集群的关键核心服务,所以建议为其Deployment设置自动扩缩容控制器,自动管理其副本数量;另外,对资源限制部分(CPU限制和内存限制)的设置也应根据实际环境进行调整;
  • Service “coredns”是DNS服务的配置,这个服务需要设置固定的ClusterIP,也需要将所有Node上的kubelet 启动参数—cluster-dns设置为这个ClusterIP;

5.3、CoreDNS的配置说明

CoreDNS的主要功能是通过插件系统实现的。CoreDNS实现了一种 链式插件结构,将DNS的逻辑抽象成了一个个插件,能够灵活组合使用。
常用的插件如下:

  • loadbalance:提供基于DNS的负载均衡功能。
  • loop:检测在DNS解析过程中出现的简单循环问题。
  • cache:提供前端缓存功能。
  • health:对Endpoint进行健康检查。
  • kubernetes:从Kubernetes中读取zone数据。
  • etcd:从etcd读取zone数据,可以用于自定义域名记录。
  • file:从RFC1035格式文件中读取zone数据。
  • hosts:使用/etc/hosts文件或者其他文件读取zone数据,可以用 于自定义域名记录。
  • auto:从磁盘中自动加载区域文件。
  • reload:定时自动重新加载Corefile配置文件的内容。
  • forward:转发域名查询到上游DNS服务器。
  • proxy:转发特定的域名查询到多个其他DNS服务器,同时提供到多个DNS服务器的负载均衡功能。
  • prometheus:为Prometheus系统提供采集性能指标数据的 URL。
  • pprof:在URL路径/debug/pprof下提供运行时的性能数据。
  • log:对DNS查询进行日志记录。
  • errors:对错误信息进行日志记录。

在下面的示例中为域名“cluster.local”设置了一系列插件,包括 errors、health、kubernetes、prometheus、forward、cache、loop、reload 和loadbalance,在进行域名解析时,这些插件将以从上到下的顺序依次执行:
【Kubernetes详解】(八)k8s 之 Service 详解一 - 图12

5.4、Pod级别的DNS配置说明

除了使用集群范围的DNS服务(如CoreDNS),在Pod级别也能设置DNS的相关策略和配置。
在Pod的Y AML配置文件中通过spec.dnsPolicy字段设置DNS策略。
目前可以设置的DNS策略如下:

  • Default:继承Pod所在宿主机的DNS设置。
  • ClusterFirst:优先使用Kubernetes环境的DNS服务(如 CoreDNS提供的域名解析服务),将无法解析的域名转发到从宿主机继 承的DNS服务器。
  • ClusterFirstWithHostNet:与ClusterFirst相同,对于以 hostNetwork模式运行的Pod,应明确指定使用该策略。
  • None:忽略Kubernetes环境的DNS配置,通过spec.dnsConfig自定义DNS配置。这个选项从Kubernetes 1.9版本开始引入,到Kubernetes 1.10版本升级为Beta版,到Kubernetes 1.14版本升级为稳定版。