一 总述

1 service 作用

POD 中运行的容器存在动态、弹性的变化(容器的重启IP地址会变化),因此便产生了service,其资源为此类POD对象提供一个固定、统一的访问接口及负载均衡能力,并借助DNS系统的服务发现功能,解决客户端发现容器难得问题

service 和POD 对象的IP地址在集群内部可达,但集群外部用户无法接入服务,解决的思路有:
1 在POD上做端口暴露(hostPort)
2 在工作节点上公用网络名称空间(hostNetwork)
3 使用service 的NodePort 或 loadbalancer (service 依赖于 DNS资源服务)
4 ingress七层负载均衡和反向代理资源

2 service资源及实现模型

1 service 概述

1 service是微服务的一种实现,事实上其是一种抽象:通过关注定义出多个POD对象组合而成的逻辑集合,以及访问这组POD的策略,service关联POD 需要标签选择器完成,其基于标签选择器将一组POD定义成一个逻辑集合,并通过自己的IP地址和端口调度代理请求至后端POD之上。


2 service 对象的IP地址称为cluster IP,位于K8S集群配置指定的专用IP地址范围内,其是一种虚拟IP地址,其在service对象创建后保持不变,并且能够被同一集群中的POD资源访问,service端口接受客户端的请求并将其转发至后端POD中的相应端口,因此,其又被称为四层代理,因其工作在TCP/IP层。


3 service 资源通过API server 持续监视标签选择器匹配到的后端POD对象,并实时跟踪各对象的变动,service并不直接连接POD对象,而是通过endpoints 资源对象类型处理,其有IP地址和端口组成,默认情况下,当创建service对象时,其关联的endpoints对象也会被自动创建。

2 虚拟IP和服务代理

1 虚拟IP

一个service对象就是工作节点上的一些iptables或ipvs,用于将到达service对象的IP地址的流量转发到相应的endpoint对象指定的IP地址和端口上,kube-proxy组件通过api-server持续监控着各个service及其相关的POD对象,并将其创建或变动实时反映到工作节点的iptable或ipvs上。


ipvs是借助于netfilter实现的网络请求报文调度框架,支持rr、wrr、lc、wlc、sh、sed和nq 等十余种调度算法,用户空间的命令行工具是ipvsadm,用于管理工作于ipvs上的调度规则。


service IP 事实上是用于生成iptables 或 ipvs 规则时使用的ip地址,仅用于实现K8S集群网络的内部通信,并能够通过规则中定义的转发服务请求作为目标地址予以响应,这也是其成为虚拟IP地址的原因。

2 代理模型

1 userspace 代理模型(用户空间模型)

userspace 是Linux操作系统的用户空间,这种模型中,kube-proxy 负责跟踪API server 上的endpoints对象的变动,并根据其进行相关的调整策略。

对于每个service对象,其都会随机打开一个本地端口,任何到达此端口的请求都会被代理到当前service资源的后端各个POD对象上,其默认使用RR调度策略。

其代理的过程是: 请求到达service后,其被转发到内核,经由套接字送往用户空间的kube-proxy,而后经由kube-proxy送回内核空间,并调度至后端POD,其传输方式效率太低。在1.1 版本之前,其是默认的转发策略。

2 iptables代理模型

kube-proxy 负责跟踪API server上 service和 endpoints对象的变动,并据此作出service资源定义的变动,对于每个service,都会创建iptabls规则直接捕获到达clusterIP 和PORT 的流量,并将其重定向到当前的service后端,默认算法是随机调度算法,POD 直接请求service IP 地址通过其直接访问对应的POD服务,在1.2开始成为默认类型,其使用的是iptables的目标地址转换至后端的POD对象,相对而言,其不用在内核和用户空间之间切换,因此更加高效,但其不能再被挑中的POD资源无响应时进行重定向,但用户空间(userspace)模型可以。

3 ipvs模型

此模型跟踪API service上的service和endpoints对象的变动,据此来调用netlink接口创建IPVS规则,并确保API server中的变动保持同步,其流量调度策略在IPVS中实现,其余的在iptables中实现。
ipvs 支持众多调度算法,如rr、lc、dh、sh、sed和nq 等。

二 service 资源基本应用

service 本身不提供服务,其是通过后端POD提供对应的服务,因此,service资源对象通常要和deployment谢忠完成应用的创建和对外发布。

1 创建service 资源

1 使用命令行创建service资源

创建POD资源

 kubectl run   nginx  --image=nginx:1.14  --replicas=3

查看deployment资源
kubernetes  service  和 ingress
其名称为nginx

创建对应的service资源

kubectl expose  deployment nginx --name=nginx --port=80 --target-port=80 --protocol=TCP

查看生成的service
kubernetes  service  和 ingress

查看生成的endpoints对应关系
kubernetes  service  和 ingress
node节点资源访问

kubernetes  service  和 ingress

2 使用配置文件创建service

#[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用于匹配后面POD对象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就绪性探测,用于探测服务是否正常运行,若未就绪则service不能向该POD上调度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名称
spec:
    selector:  # 用于匹配后面POD对象
        app: service
    ports:
        - protocol: TCP  # 使用的协议
          port: 80  #service 端口号
          targetPort: 80  # 后端POD端口号

部署

kubectl apply -f demo.yaml 

查看service访问的接口
kubernetes  service  和 ingress

查看service详细信息

kubernetes  service  和 ingress

其默认类型是clusterIP,使用地址为自动配置,此类型的service对象只能通过集群内部访问。若集群中的POD对象的标签为app=service,则其会被自动关联至service后端

创建http服务用以验证

kubectl run http  --image=httpd  -l app=service

查看POD是否启动成功
kubernetes  service  和 ingress

查看 endpoints

kubernetes  service  和 ingress

测试
其IP地址为service对应的IP地址

for  i in  1 2 3;do curl http://10.0.0.52 && echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ;done

查看
kubernetes  service  和 ingress

kubernetes  service  和 ingress

当kubernetes 集群的service代理模式为iptables,它默认使用的算法是随机调度,因此service会将客户端的请求随机调度至关联的某个POD资源上。

2 service 会话粘滞性

1 概述

service 会话粘滞性
service 资源支持session affinity(黏性会话或会话黏性)机制,能够将来自同一个客户端的请求始终转发至同一个后端POD,其会降低负载均衡的效果,因此,当客户端访问POD中的应用程序时,如果有基于客户端身份保存某些私有信息,并基于这些私有信息追踪用户的活动一类的需求时,就应该启动会话保持机制。


session affinity的效果会在一定时间期限内生效,默认是10800秒,超出此时间之后,客户端的再次访问会被调度算法重新调度,另外service资源的session affinity 机制仅能基于客户端IP地址识别客户端身份,他会把经由同一个NAT 服务器进行源地址转换的所有客户端识别为统一客户端,调度粒度粗糙且效果不佳,因此,实践中不推荐使用此种方法实现粘性会话。

2 设置字段解析

kubectl explain service.spec.sessionAffinityConfig.clientIP.timeoutSeconds
用于配置配置其会话保持时长,是一个嵌套字段,使用时长是1-86400,默认是10800

kubectl explain service.spec.sessionAffinity
用于定义要使用的黏性会话的类型,其仅支持"none
和"clinetIP"两种类型。

none :不使用sessionaffinity,默认值
clientIP:基于客户端IP地址识别客户端身份,把来自同一个源IP地址的请求始终调度到同一个POD对象上。

3 部署实例并验证

1 删除上面创建实例

kubectl delete -f demo.yaml 

修改实例

[root@master1 service]# cat demo1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用于匹配后面POD对象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就绪性探测,用于探测服务是否正常运行,若未就绪则service不能向该POD上调度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名称
spec:
    selector:  # 用于匹配后面POD对象
        app: service
    ports:
        - protocol: TCP  # 使用的协议
          port: 80  #service 端口号
          targetPort: 80  # 后端POD端口号
    sessionAffinity: ClientIP  #配置会话粘滞基于客户端
    sessionAffinityConfig:  # 配置会话粘滞时间
        clientIP:
            timeoutSeconds: 86400

部署

kubectl apply -f demo1.yaml 

查看后端POD情况
kubernetes  service  和 ingress

查看serviceIP地址
kubernetes  service  和 ingress

测试
kubernetes  service  和 ingress

kubernetes  service  和 ingress

其实现了会话保持

3 服务发现

1 概述

由于各个服务之间需要能够够正常通信并提供统一的稳定的访问入口,所以POD客户端中的应用需要知道某service资源的IP地址和端口号,这边产生了service discovery

2 服务发现实现机制

1 部署稳定的服务注册中心
2 服务提供者(POD及其应用)提供自己的位置信息,并在变动后及时更新信息
3 消费者(serice)周期性层注册中心获取服务者提供的最新信息从而发现要访问的目标服务字段

3 服务发现类型

1 客户端发现: 由客户端到注册中心发现其依赖到服务的相关信息,其需要内置的发现程序和发现逻辑
2 服务端发现:需要使用中央路由器或服务均衡器的组件,服务消费者(客户端 )将其请求发送到中央路由器或负载均衡器,由他们负责查询服务注册中心获取服务提供者的位置信息,并将服务消费者的请求转发给服务提供者(POD及其应用)

coreDNS
DNS是原始的服务发现系统之一,但其传播速度过慢,后期常见的服务注册中心是zookeeper 和 etcd 等分布式键值存储系统,其只提供基本的数据存储功能,距离实现完整的服务发现机制还有大量的开发任务,
Netflix 和 eureka 是目前较流行的服务发现系统之一,是专门开发用来实现服务发现的系统,以可用性目的为先,可以在多种故障期间保持服务发现和服务注册功能的可用,

传统DNS不适合微服务环境,但skyDNS实现了,

自K8S 1.3 开始,其服务发现的DNS 更新为了kubeDNS,而另一个较新的是 coreDNS,是基于GO语言开发,通过串接一组实现DNS功能的插件的插件连进行工作,自1.11开始coreDNS取代了kubeDNS成为默认的DNS附件。

4 服务发现

1 环境变量

创建POD资源时,kubelet会将其所属名称空间内的每个活动的service对象以一系列环境变量的形式注入其中,其支持使用kubernetes service环境变量以及与docker的links 兼容的环境变量


1 kubernetes service 环境变量
kubernetes 为每个service资源生成包括下面形式的环境变量,在同一名称空间(默认名称空间default)中创建的POD对象自动拥有这些变量

.{SVCNAME}_SERVICE_HOST
.{SVCNAME}_SERVICE_PORT
注意 : 如果SVCNAME 中使用了链接线,则kubernetes会在定义为环境变量时将其转换为下划线


2 docker link 形式的环境变量
Docker使用--link 选项实现容器链接时所设置的环境变量形式,在创建POD对象时,kubernetes会将与此形式兼容的一系列环境变量注入POD对象中。

查看之前创建的POD的环境变量
1 进入POD

kubectl exec -it  service-demo-7677648c64-m4nqh -- /bin/bash

查看
kubernetes  service  和 ingress

其中DEMO_SERVICE 是之前创建的service的名称,其以DEMO_SERVICE_SERVICE开头的是kubernetes service资源的环境变量


基于环境变量的服务发现其功能简单,已用,但存在局限,仅有那些与创建POD对象在同一名称空间中且实现存在的service对象的信息才能以环境变量的形式入驻,那些处于非同一名称空间或者在POD资源创建之后创建的service对象的相关环境变量则不会被添加。

2 cluster DNS

kubernetes上用于名称解析和服务发现的clusterDNS 是集群的核心附件之一,集群中创建的每个service对象,都会有其自动生成相关资源记录,默认情况,集群中各POD对象会自动配置clusterDNS 作为其名称解析服务器,并在其DNS搜索列表中包含其所属的名称空间的域名后缀。

不管是使用clusterDNS还是coreDNS,其提供的DNS的服务发现解决方案都会负责解析下面资源类型以实现服务发现。


1 拥有clusterIP的service资源,具有下面类型的资源记录
A 记录: <service>.<ns>.svc.<zone>.<ttl> IN A <cluster-ip>

SRV记录: <port>.<proto>.<service>.<ns>.svc.<zone>.<ttl> IN SRV <weight> <priority><port-number><service>.<ns>.svc.<zone>
PTR记录:<d>.<c>.<b><a>.in-addr.arpa.<ttl> IN PTR <service>.<ns>.svc.<zone>


2 headless 类型的service 资源

A 记录 : <service>.<ns>.svc.<zone>.<ttl> IN A <endpoint-ip>

SRV 记录 : <port>.<proto>.<service>.<ns>.svc.<zone>.<ttl> IN <weight><priority> <port-number> <hostname>.<ns>.svc.<zone>
PTR 记录:<d>.<c>.<b>.<a>.in-addr-arpa.<ttl>IN PTR <hostname>.<service>.<ns>.svc.<zone>


3 externalName 类型资源的service资源,具有CNAME类型的资源记录 。

CNAME 记录: <service>.<ns>.svc.<zone>.<ttl> IN CNAME <extname>

名称解析和服务发现是kubernetes系统需要功能得以实现的基础服务,其通常是集群安装完成应该部署的附加组件,使用kubeadm 初始化一个集群时,其会自动部署。

3 DNS

创建service资源对象时,clusterDNS 会自动创建资源记录用于名称解析和服务注册。POD可直接使用其DNS 访问service资源,每个service对象相关的DNS 记录如下:

.{SVCNAME}.{NAMESPACE}.{CLUSTER_DOMAIN}

.{SVCNAME}.{NAMESPACE}.svc.{CLUSTER_DOMAIN}
--cluster-dns 指定了集群DNS服务的工作地址
--cluster-domino 定义了集群使用的本地域名。因此系统初始化默认会将"cluster.local."和主机所在的域"ilinux.io."作为DNS的本地域使用,这些信息会在POD创建时以DNS配置的相关信息注入它的/etc/resolv.conf 配置文件中

查看
kubernetes  service  和 ingress

{NAMESPACE}.svc.{CLUSTER_DEMAIN}: 如 default.svc.cluster.local

svc.{CLUSTER_DOMAIN}: 如 svc.luster.local

{CLUSTER_DOMAIN}: 如 cluster.local

{WORK_NODE_DOMAIN}: 如上述未定义

4 服务暴露

默认的service 的IP默认是在集群内部可达,但若需要外部访问,则需要进行处理

1 service类型

1 clusterIP : 集群内部可达,无法被外部客户端访问,创建service的默认访问类型

2 NodePort:建立在clusterIP之上(集群上的NODE节点+端口)均和访问到。

3 loadbalancer:在NodePort之上,通过cloud provider提供的负载均衡器将服务暴露到集群外部,因此loadbalancer具有NodePort和clusterIP。一个loadbalancer类型的service会指向关联至kubernetes集群外部的,切实存在的某个负载均衡设备,该设备通过工作节点上的NodePort 向集群内部发送请求流量,其优势在于能够把来自集群外部客户端的请求调度至所有节点的NodePort 之上,而不是依赖于客户端自动决定链接至那个节点,从而避免了因客户端指定的节点故障而导致的服务不可用。

4 externalName: 通过将service映射到映射至由externalName字段的内容指定的主机名来暴露服务,此主机名需要被DNS服务解析成CNAME 类型的记录,其无clusterIP 和 Noport,也没有标签选择器,因此没endpoints ,其是一个域名,是CNAME结构,集群内部的域名。

2 NodePort

1 概述

NodePort 及节点Port,其在安装s集群系统时会预留一个端口范围用于NodePort,默认是30000-32767之间的端口,ClusterIP类型可省略.spec.type,但其NodePort类型则必须指定对应的type方可。

2 删除之前的实例 :

kubectl delete -f demo.yaml 

修改结果如下

#root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用于匹配后面POD对象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就绪性探测,用于探测服务是否正常运行,若未就绪则service不能向该POD上调度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名称
spec:
    type: NodePort  #指定其类型为NodePort
    selector:  # 用于匹配后面POD对象
        app: service
    ports:
        - protocol: TCP  # 使用的协议
          port: 80  #service 端口号
          targetPort: 80  # 后端POD端口号
          nodePort: 32380  # 指定其节点端口为32380

此处可不配置nodePort,其会自动生成nodePort

3 部署

 kubectl apply -f demo.yaml 

查看
kubernetes  service  和 ingress

其NodePort 资源会创建ClusterIP,事实上,其会作为节点从NodePort 接入流量后转发至目标地址,目标端口则是与service资源对应的spec.ports.port属性中定义的端口。

NodeIP:NodePort------> SrviceIP:ServicePort------>PodIP:PodPort

4 访问测试

kubernetes  service  和 ingress
kubernetes  service  和 ingress

其内部可通过clusterIP进行访问

kubernetes  service  和 ingress

3 loadBalancer

1 概述

NodePort 如果外部客户端无法得知其IP地址和对应映射的端口,则其访问不成功,其次,若对应IP地址的Node节点故障,则其访问也将失败,因此,一般还应在集群外部创建一个具有公网IP地址的负载均衡器。由其接入外部客户端请求并调度至集群节点相应的NodePort之上。

相关实例如下:

2 删除之前配置

kubectl delete -f demo.yaml 

3 修改配置结果如下

[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用于匹配后面POD对象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就绪性探测,用于探测服务是否正常运行,若未就绪则service不能向该POD上调度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名称
spec:
    type: LoadBalancer  #指定其类型为LoadBalancer
    selector:  # 用于匹配后面POD对象
        app: service
    ports:
        - protocol: TCP  # 使用的协议
          port: 80  #service 端口号
          targetPort: 80  # 后端POD端口号
          nodePort: 32380  # 指定其节点端口为32380

4 部署

kubectl apply -f demo.yaml 

查看
kubernetes  service  和 ingress

5 访问测试

其可以使用NodePort的方式进行访问
kubernetes  service  和 ingress

kubernetes  service  和 ingress

IaaS 云计算环境提供了LBaaS服务,它允许租户动态的在自己的网络中创建一个负载均衡器,那些部署在此类环境上的kubernetes集群在创建service资源时可以直接调用此接口按需创建一个软负载均衡器,而具有这种功能的service资源及为loadBalancer类型,其目前环境不支持此种配置。

4 externalName

1 概述

externalName 类型的service资源用于将集群外部的服务发布到集群中以供Pod中的应用程序访问,因此,其不需要使用任何标签选择器关联至任何POD对象,但必须要使用spec.externalName属性定义一个CNAME记录用于返回外部真正提供服务的主机别名,而后通过CNAME 记录值获取到相关主机的IP地址。

2 配置实例

实例如下:

#[root@master1 service]# cat ex.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: tomcat
spec:
    containers:
        - name: tomcat
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: external-tomcat-svc
    namespace: default
spec:
    type: ExternalName
    externalName: www.baidu.com
    ports:
        - protocol: TCP
          port: 80
          targetPort: 80
          nodePort: 0
    selector: {}

3 部署服务

kubectl apply -f ex.yaml 

查看
kubernetes  service  和 ingress

等到此service资源 external-tomcat-svc 创建完成后,各POD对象即可通过external-tomcat-svc 或其FQDN格式的名称 external-tomcat-svc.default.svc.cluster 访问相应的资源,ClusterDNS 会将此名称以CNAME 格式解析为.spec.externalName字段中的名称,而后通过DNS服务将其解析为相应的主机的IP地址.

4 测试 :

需要安装nslookup 如下

#链接其中一个POD
kubectl exec  -it nginx-7bc476d88b-p5sv2  -- /bin/bash
安装nslookup
apt-get  update 
apt-get install dnsutils

查看解析

kubernetes  service  和 ingress

解析到其name 为www.baidu.com
由于 externalName 类型的service资源实现于DNS级别,客户端将其直接接入外部服务而完全不需要服务代理,因此,其无序配置clusterIP,此种类型也可称为headless Service

5 headless

1 概述

service 对象隐藏了个POD资源,并负责将客户端请求流量调度至POD上,但也有可能存在客户端需要直接访问service资源后端的所有POD资源,这时就应该向客户端暴露每个POD资源的IP地址,而不是中间层service对象的ClusterIP,这种类型便是无头服务。


headless service 对象没有ClusterIP,因此便无相关负载均衡或代理问题,其如何为此类service配置IP地址,其取决于标签选择器的定义。

1 具有标签选择器
端点控制器(endpoints controller)会在API中为其创建endpoints记录,并将clusterDNS服务中的A记录直接解析到service后端的各个POD对象的IP地址上。
2 没有标签选择器: 端点控制器(endpoints controller)不会在API中为其创建endpoints记录,clusterDNS的配置分为两种类型,对externalName的服务创建CNAME 记录,对其他三种类型来说,为那些与当前service共享的名称空间的所有endpoints对象创建一条记录。

2 创建服务资源

实例

[root@master1 service]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: service-demo
    namespace: default
spec:
    selector:  #用于匹配后面POD对象
        matchLabels:
            app: service
    template:
        metadata:
            labels:
                app: service
        spec:
            containers:
                - name: service-demo
                  image: nginx:1.14
                  ports:  # 配置暴露端口
                    - name: http
                      containerPort: 80
                  readinessProbe:  #增加就绪性探测,用于探测服务是否正常运行,若未就绪则service不能向该POD上调度流量
                    httpGet:
                        port: 80
                        path:  /index.html 
---
apiVersion: v1
kind: Service
metadata:
    name: demo-service  # service名称
spec:
    clusterIP: None  #指定其类型为Headless Service资源
    selector:  # 用于匹配后面POD对象
        app: service
    ports:
        - protocol: TCP  # 使用的协议
          port: 80  #定义暴露的端口
          targetPort: 80  # 后端POD端口号
          name: httpport  # 定义名字

部署服务

kubectl apply -f demo.yaml 

查看服务
kubernetes  service  和 ingress

其资源信息中没有ClusterIP,但其存在endpoints,


查看其解析,其后端是POD的IP地址。其通过标签选择器选择到此IP地址。于是客户端向此service对象发起的请求将直接接入到POD资源中,而不再由service进行代理转发。

kubernetes  service  和 ingress

查看访问资源
kubernetes  service  和 ingress

3 ingress资源应用

1 概述

kubernetes 提供了两种内建的负载均衡机制,一种是位于传输层的TCP/IP service资源,其实现的是TCP负载均衡器,另一种是ingress资源,其实现的是HTTP(S)负载均衡器。

TCP负载均衡器
iptables 和 ipvs均实现的是四层调度,其不能基于URL 的请求调度机制,其也不支持为此类负载均衡配置任何类型的健康检查机制。

2 ingress 和 ingress controller

ingress 是kubernetes API 的标准资源类型之一,其其实是一组基于DNS名称或URL路径把请求转发至service资源的规则,用于将集群外部的请求流量转发至集群内部完成服务发布,ingress 资源自身并不能进行"流量穿透" ,其仅仅是一组路由规则的集合,这些规则要发挥相应的作用,则需要ingress controller,其可监听套接字,然后给据这些规则的匹配机制路由请求流量。


注意 :ingress 不同于deployment,其不是直接运行与kube-controller-manager的一部分,其是kubernetes集群的一个重要附件,需要单独安装才能使用。

ingress 控制器可以由任何具有反向代理(http/https)功能的服务器程序实现,如nginx、envoy、haproxy、vulcand和traefik等,ingress控制器自身也是运行与集群中的POD资源对象,其与北代理的运行的POD资源的应用运行于同一网络中。

另外: ingress控制器可基于ingress资源定义的规则将客户端请求流量直接转发到service对应的后端POD资源上,其会绕过service资源,省去了kube-proxy实现的端口代理开销。

3 创建ingress资源

注:在此之前,需要先配置ingress资源控制器正常运行

如下
kubernetes  service  和 ingress

集体配置可参考 :https://blog.51cto.com/11233559/2364393 中的安装和配置ingress服务

创建ingress资源

[root@master1 ingress]# cat demo.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: deploy-ingress
    namespace: default
spec:
    selector:
        matchLabels:
            app: ingress
    template:
        metadata:
            namespace: default
            labels:
                app: ingress
        spec:
            containers:
                - name: pod-ingress
                  image: nginx:1.14
                  ports:
                    - name: http
                      containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        kubernetes.io/ingress.class: "nginx"  
spec:
    rules:
        - host: www.inginx.com  #指定访问使用的URL
          http:  
            paths:
                - backend:
                    serviceName: service-ingress  #指定service的名称
                    servicePort: 80  #指定service的端口号

部署服务

kubectl apply -f demo.yaml

查看服务
kubernetes  service  和 ingress
访问查看

kubernetes  service  和 ingress

相关字段解析:

[root@master1 ingress]# kubectl explain   ingress.spec
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec is the desired state of the Ingress. More info:
     https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status

     IngressSpec describes the Ingress the user wishes to exist.

FIELDS:
   backend  <Object>#默认的后端服务,用于哪些没有匹配到任何规则的请求,定义ingress时,必须选择backend或rules其中的一个。
     A default backend capable of servicing requests that don't match any rule.
     At least one of 'backend' or 'rules' must be specified. This field is
     optional to allow the loadbalancer controller or defaulting logic to
     specify a global default.

   rules    <[]Object>  # 用于定义当前ingress字段的转发规则列表,未定义rules规则,或者没有匹配到任何规则,所有流量都会转发到由backend定义的默认后端。
     A list of host rules used to configure the Ingress. If unspecified, or no
     rule matches, all traffic is sent to the default backend.

   tls  <[]Object>#TLS 配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向了不同的主机,必须通过SBI TLS扩展机制来支持此功能。
     TLS configuration. Currently the Ingress only supports a single TLS port,
     443. If multiple members of this list specify different hosts, they will be
     multiplexed on the same port according to the hostname specified through
     the SNI TLS extension, if the ingress controller fulfilling the ingress
     supports SNI.
[root@master1 ingress]# kubectl explain   ingress.spec.backend
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: backend <Object>

DESCRIPTION:
     A default backend capable of servicing requests that don't match any rule.
     At least one of 'backend' or 'rules' must be specified. This field is
     optional to allow the loadbalancer controller or defaulting logic to
     specify a global default.

     IngressBackend describes all endpoints for a given service and port.

FIELDS:
   serviceName  <string> -required-  #用于指定service名称
     Specifies the name of the referenced service.

   servicePort  <string> -required-  # 用于指定service端口
     Specifies the port of the referenced service.
rules对象相关

spec:
    rules:
        - host:  #指定访问URL名称
          http: 
                paths:
                    - backend:  #用于指定后端service信息
                                serviceName:
                                servicePort:
                        path: #用于指定后缀 

注意 :ingress.spec.rules.host 属性值目前不支持使用IP地址,也不支持后跟":PORT"格式的端口号,且此字段值留空表示通配所有的主机名。

[root@master1 ingress]# kubectl explain   ingress.spec.tls
KIND:     Ingress
VERSION:  extensions/v1beta1

RESOURCE: tls <[]Object>

DESCRIPTION:
     TLS configuration. Currently the Ingress only supports a single TLS port,
     443. If multiple members of this list specify different hosts, they will be
     multiplexed on the same port according to the hostname specified through
     the SNI TLS extension, if the ingress controller fulfilling the ingress
     supports SNI.

     IngressTLS describes the transport layer security associated with an
     Ingress.

FIELDS:
   hosts    <[]string>  # 包含与使用的TLS证书值内的主机名称字符串列表,因此,使用的主机名必须匹配tlsSecret 中的名称
     Hosts are a list of hosts included in the TLS certificate. The values in
     this list must match the name/s used in the tlsSecret. Defaults to the
     wildcard host setting for the loadbalancer controller fulfilling this
     Ingress, if left unspecified.

   secretName   <string> # 用于引用SSL会话的secret对象名称,在基于SNI实现多主机路由的场景中,此字段为可选。
     SecretName is the name of the secret used to terminate SSL traffic on 443.
     Field is left optional to allow SSL routing based on SNI hostname alone. If
     the SNI host in a listener conflicts with the "Host" header field used by
     an Ingre***ule, the SNI host is used for termination and value of the Host
     header is used for routing.

4 ingress资源类型

1 单个service资源类型

暴露单个服务的方法很多,如服务类型中的NodePort,loadBalancer等,方式旨在指定默认后端服务

#[root@master1 ingress]# cat nginx.yaml 
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: default-backend-nginx
    namespace: default
spec:
    backend:
        serviceName: nginx # 指定service名称
        servicePort: 80  #指定service端口

查看服务
kubernetes  service  和 ingress

2 基于URL路径进行流量分发

[root@master1 ingress]# cat demo.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: nginx
    namespace: default
    labels:
        app: ingress
spec:
    containers:
        - name: pod-ingress
          image: nginx:1.12
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: ingress1
spec:
    containers:
        - name: pod-ingress1
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress1
    namespace: default
spec:
    selector:
        app: ingress1
    ports:
        - protocol: TCP
          targetPort: 8080
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        ingress.kubernetes.io/rewrite-target: / 
spec:
    rules:
        - host: www.inginx.com  #指定访问使用的URL
          http:  
            paths: 
                - path: /nginx
                  backend:
                    serviceName: service-ingress  #指定service的名称
                    servicePort: 80  #指定service的端口号
                - path: /tomcat
                  backend:
                    serviceName: service-ingress1
                    servicePort: 80

部署并查看

kubectl apply -f demo.yaml 

查看
kubernetes  service  和 ingress

目前: ingress-nginx尚不能很好的支持此项功能,因此其目前不能使用

测试结果如下

kubernetes  service  和 ingress
kubernetes  service  和 ingress

可看到其配置文件中版本号和测试结果版本号一致。

3 基于主机名称的虚拟主机

1 去除上述配置

kubectl delete -f demo.yaml 

配置相关服务

#[root@master1 ingress]# cat demo.yaml 
apiVersion: v1
kind: Pod
metadata:
    name: nginx
    namespace: default
    labels:
        app: ingress
spec:
    containers:
        - name: pod-ingress
          image: nginx:1.12
          ports:
            - name: http
              containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
    name: tomcat
    namespace: default
    labels:
        app: ingress1
spec:
    containers:
        - name: pod-ingress1
          image: tomcat:8.5.35
          ports:
            - name: tomcat
              containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress
    namespace: default
spec:
    selector:
        app: ingress
    ports:
        - protocol: TCP
          targetPort: 80
          port: 80
---
apiVersion: v1
kind: Service
metadata:
    name: service-ingress1
    namespace: default
spec:
    selector:
        app: ingress1
    ports:
        - protocol: TCP
          targetPort: 8080
          port: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: demo-ingress
    annotations:
        ingress.kubernetes.io/rewrite-target: / 
spec:
    rules:
        - host: www.inginx.com  #指定访问使用的URL
          http:  
            paths: 
                - path: 
                  backend:
                    serviceName: service-ingress  #指定service的名称
                    servicePort: 80  #指定service的端口号
        - host: www.ttomcat.com
          http:
            paths:
                - path:
                  backend:
                    serviceName: service-ingress1
                    servicePort: 80

部署

kubectl apply -f demo.yaml 

配置相关域名解析

kubernetes  service  和 ingress

测试
kubernetes  service  和 ingress
kubernetes  service  和 ingress

4 基于TLS 类型的ingress资源

这种类型用于以HTTPD发布service资源,基于一个含有私钥和证书的secret对象即可配置TLS协议的ingress资源,目前,ingress资源仅支持单TLS端口,并且还会卸载TLS会话,在ingress资源中引用此secret即可让ingress控制器加载并配置HTTPS服务。

1 生成证书

 openssl genrsa -out tls.key 2048
 openssl req -new -x509 -key tls.key -out tls.crt -subj  /C=CN/ST=shaanxi/L=xi\'an/O=linux/CN=www.inginx.io -days 3650

注: TLS secret中包含的证书必须以tls.crt作为其键名,私钥文件必须以tls.key作为键名。其CN=www.inginx.io 必须与后面对应的host相同

2 生成secret资源对象

kubectl create secret tls nginx-secret --cert=tls.crt --key=tls.key  

查看

kubernetes  service  和 ingress

3 部署配置

#[root@master1 ingress]# cat demo1.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
    name: nginx-https-deploy
    namespace: default
spec:
    selector:
        matchLabels:
            app: nginx-https
    template:
        metadata:
            namespace: default
            labels:
                app: nginx-https
        spec:
            containers:
                - name: nginx-https
                  image: nginx:1.14
                  ports:
                    - name: http
                      containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
    name: https-demo
spec:
    selector:
        app: nginx-https
    ports:
        - port: 80
          targetPort: 80
          protocol: TCP
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
    name: https-ingress
    namespace: default
    annotations:
        kubernetes.io/ingress.class: "nginx"
spec:
    tls: 
        - hosts:
            - www.inginx.io   #指定其访问使用的域名
          secretName: nginx-secret  #指定其访问时使用的证书
    rules:
        - host: www.inginx.io
          http:
            paths:
                - path: /
                  backend:
                    serviceName: https-demo
                    servicePort: 80

部署

kubectl apply -f demo1.yaml

配置相关解析

kubernetes  service  和 ingress

4 访问查看

kubernetes  service  和 ingress
证书信息查看
kubernetes  service  和 ingress