13. Kubernetes Services

本文由 CNCF + Alibaba 云原生技术公开课 整理而来

Service:服务发现与负载均衡

  • 为什么需要服务发现?

在 Kubernetes 集群里面会通过 Pod 去部署应用,与传统的应用部署不同,传统应用部署在给定的机器上面去部署,去调用别的机器的 IP 地址非常简单。

在 Kubernetes 集群里面应用是通过 Pod 去部署的, 而 Pod 的生命周期是短暂的。在 Pod 的生命周期过程中,比如它创建或销毁,它的 IP 地址都会发生变化,这样就不能使用传统的部署方式,不能指定 Pod IP 去访问指定的应用。

另外在 Kubernetes 中,虽然有 Deployment 的应用部署模式,但还是需要创建一个 Pod 组,然后这些 Pod 组需要提供一个统一的访问入口,以及怎么去控制流量负载均衡到这个组里面。比如说测试环境、预发布环境和线上环境,其实在部署的过程中需要保持同样的一个部署模板以及访问方式。因为这样就可以用同一套应用的模板在不同的环境中直接发布。

最后应用服务需要暴露到外部去访问,需要提供给外部的用户去调用或访问的。那怎么让 Pod 网络暴露到去给外部访问呢?此时就需要服务发现。

  • Service-服务发现与负载均衡 :

在 Kubernetes 里面,应用程序的服务发现与负载均衡就是通过 Service 来完成的。向上,Service 提供了外部网络以及 Pod 网络的访问,即外部网络可以通过 Service 去访问,Pod 网络也可以通过 Service 去访问。

向下,Kubernetes 对接了另外一组 Pod,即可以通过 Service 的方式去负载均衡到一组 Pod 上面去,这样相当于解决了前面所说的问题。而且提供了统一的访问入口去做服务发现,然后又可以给外部网络访问,解决不同的 Pod 之间的访问,提供统一的访问地址。


Service 用法

下面简单介绍 Service 的用法。

  • Service 语法:

my-service Service yaml 文件示例:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  labels:
    app: my-service
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

文件解析:

apiVersion: v1      表示 Service 的 API 版本是 v1

kind        表示 Kubernetes 资源类型是 Service

metadata    表示 Service 的元数据,元数据通常包含 name、namespace、labels、annotations 等

spec    表示 Service 的期望状态,selector 表示 Pod 选择器,选择带相同 label 的 Pod;
        ports 表示 Service 的协议和端口,并指定 Pod 的端口
  • 创建和查看 Service
kubectl apply -f <yaml-file>                #创建

kubectl describe service <service-name>             #查看

kubectl describe service 时,能够看到一个 Endpoints 属性,该属性的值就是通过 selector 匹配到的后端 Pod 的 IP 和 targetPort 组成的一组地址的列表;而 IP 属性的值就是 Kubernetes 自动为 Service 分配的 ClusterIPClusterIP 是虚拟 IP,在集群内唯一。

在集群里,所有的 Pod 和 Node 都可以通过 ClusterIP 和 yaml 中指定的 port 去访问到这个 ServiceService 会把它选择的 Pod 及其 IP:Port 都挂载到后端,这样一来,当访问 ServiceClusterIP 时,就可以负载均衡到后端的这些 Pod 上面去。

Pod 的生命周期有变化时,比如说其中一个 Pod 销毁,Service 就会自动从后端移除这个 Pod。即使 Pod 的生命周期有变化,也和 Service 无关,用户访问的地址并不需要改变。

  • 集群内访问 Service

在 Kubernetes 集群里面,其他 Pod 要怎么访问到 Service 呢?有 3 种方式:

1. 可以通过 Service 的 ClusterIP 去访问

2. 可以直接访问服务名,依靠 DNS 解析。同一个 Namespace 里 Pod 可以直接通过 Service 的名字去访问到 Service;
   不同的 Namespace 里面,可以通过 <service-name>.<namespace-name> 去访问 Service

3. 通过环境变量访问,在同一个 Namespace 里的 Pod 启动时,Kubernetes 会把 Service 的一些简单的配置(如 IP 地址、端口等)通过环境变量的方式放到 Pod 里面
  • Headless Service

Headless Service 就是没有 ClusterIPServiceService 在创建时可以指定 clusterIP: None,这样 Kubernetes 就不会分配 ClusterIPServiceHeadless Service 没有 ClusterIP 怎么做到负载均衡以及统一的访问入口呢?

Pod 可以直接通过 <service-name> 以 DNS A 记录的方式解析到所有后端 Pod 的 IP 地址,由客户端选择一个后端的 IP 地址,这个 A 记录会随着 Pod 的生命周期变化,返回的 A 记录列表也发生变化,这样就要求客户端应用要从 A 记录把所有 DNS 返回到 A 记录的列表里面 IP 地址中,客户端自己去选择一个合适的地址去访问 Pod

  • 向集群外暴露 Service

怎么把集群的应用暴露给外部去访问呢?Kubernetes 中提供了 3 种方式:

NodePort,将 ClusterIP 映射到集群的 Node 上的一个端口,这样就可以直接访问 Node 的这个端口访问到 ClusterIP

LoadBalancer,在 NodePort 上面做一层转换,NodePort 其实是集群里面每个 Node 上的同一端口,
   LoadBalancer 是在所有的 Node 前挂上一个负载均衡,这个负载均衡会提供一个统一的入口
   
Ingress,在集群中创建 Ingress 对象,用户访问 Ingress 对象中指定的域名 和 url,然后 Ingress 会将所有流量转发到对应 Service 的 ClusterIP

架构设计

  • Kubernetes 服务发现架构:

在这里插入图片描述

Kubernetes 分为 Master 节点和 Node 节点:

Master 负责维护集群的目标状态

Node 负责运行实际的业务负载

Master 节点控制所有 Node 节点。Master 节点上的 APIServer 统一管理 Kubernetes 所有对象,所有的组件都会注册到 APIServer 上面去监听这个对象的变化,例如 Pod 生命周期发生变化等事件。

这里面最关键的有三个组件:

Cloud Controller Manager,负责去配置 LoadBalancer 给外部去访问

Coredns,通过 Coredns 去观测 APIServer 里面的 Service 后端 Pod 的变化,去配置 Service 的 DNS 解析,实现可以通过 Service 的名字直接访问到 Service 的 ClusterIP,或者是 Headless Service 中的 IP 列表的解析

kube-proxy,位于 Node 节点上,它通过监听 Service 以及 Pod 变化,然后实际去配置集群里面的 Pod 或者 ClusterIP 的访问

实际的访问链路是什么样的呢?从集群内部的一个 Pod 去访问 ServicePod 首先通过 Coredns 这里去解析出 ClusterIPPod 会拿这个 ClusterIP 去做请求,它的请求到 Node 的网络之后,就会被 kube-proxy 所配置的 iptables 或者 IPVS 去做一层拦截处理,之后去负载均衡到每一个实际的后端 Pod 上面去,这样就实现了一个负载均衡以及服务发现。

对于外部的流量,通过公网访问的一个请求,它是通过外部的一个负载均衡器 Cloud Controller Manager 去监听 Service 的变化之后,去配置的一个负载均衡器,然后转发到节点上的一个 NodePort 上面去,NodePort 也会经过 kube-proxy 配置的一个 iptables,把 NodePort 的流量转换成 ClusterIP,紧接着转换成后端的一个 Pod 的 IP 地址,去做负载均衡以及服务发现。

这就是整个 Kubernetes 服务发现以及 Kubernetes Service 整体的结构。


猜你喜欢

转载自blog.csdn.net/miss1181248983/article/details/112144764
今日推荐