一、Service定义详解
YAML格式的Service定义文件的完整内容如下:
对各属性的说明如下表所示:
二、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 命令创建
# 通过 expose 命令创建,端口默认与Pod端口保持一致
$ kubectl expose <rc> <rc-name>
- 通过yaml文件创建
Service定义中的关键字段是ports和selector。上例中ports定义部分指定了Service所需的虚拟端口号为8081,由于与Pod容器端口号8080不一 样,所以需要再通过targetPort来指定后端Pod的端口号。selector定义部分设置的是后端Pod所拥有的label:app=webapp。
可以通过如下命令来查看ClusterIp和端口:
$ kubectl get svc -n <namespace>
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的定 义中也可以相应地设置为将多个端口对应到多个应用服务。示例:
三、Headless Service
在某些应用场景中,开发人员希望自己控制负载均衡的策略,不使 用Service提供的默认负载均衡的功能,或者应用程序希望知道属于同组 服务的其他实例。Kubernetes提供了Headless Service来实现这种功能, 即不为Service设置ClusterIP(入口IP地址),仅通过Label Selector将后 端的Pod列表返回给调用的客户端。例如:
四、从集群外部访问Pod或Service
由于Pod和Service都是Kubernetes集群范围内的虚拟概念,所以集群 外的客户端系统无法通过Pod的IP地址或者Service的虚拟IP地址和虚拟 端口号访问它们。为了让外部客户端可以访问这些服务,可以将Pod或 Service的端口号映射到宿主机,以使客户端应用能够通过物理机访问容器应用。
4.1、将容器应用的端口号映射到物理机
4.1.1、通过设置容器级别的hostPort,将容器应用的端口号映射到物理机上:
4.1.2、通过设置Pod级别的hostNetwork=true
该Pod中所有容器的端 口号都将被直接映射到物理机上。在设置hostNetwork=true时需要注 意,在容器的ports定义部分如果不指定hostPort,则默认hostPort等于 containerPort,如果指定了hostPort,则hostPort必须等于containerPort的值:
4.2、将Service的端口号映射到物理机
4.2.1、通过设置nodePort映射到物理机,同时设置Service的类型为NodePort
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个容器的全部功能。
下面以CoreDNS为例说明Kubernetes集群DNS服务的搭建过程:
5.1、在创建DNS服务之前修改每个Node上 kubelet 的启动参数
修改每个Node上kubelet的启动参数,加上以下两个参数。
--cluster-dns=169.169.0.100:为DNS服务的ClusterIP地址。
--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,在进行域名解析时,这些插件将以从上到下的顺序依次执行:
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版本升级为稳定版。