跳转至

一、Service 发布应用

"什么是 Service?"

Kubernetes Service 定义了:Service 是一种可以访问 Pod 逻辑分组的策略, Service 通常是通过 Label Selector访问 Pod 组; Service 能够提供负载均衡的能力,但是在使用上有些限制:只提供 4 层负载均衡能力,而没有 7 层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上 4 层负载均衡是不支持的。

"为什么 Pod 的 IP 会变化?"

Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,所以说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化

"如何解决 Pod 的 IP 会变的问题?"

答:当 Pod 宕机后重新生成时,其 IP 等状态信息可能会变动,Service 会根据 Pod 的 Label 对这些状态信息进行监控和变更,保证上游服务不受 Pod 的变动而影响。

是运行 Pod IpDocker 网桥的 IP 地址段进行分配的,通常是一个虚拟的二层网络,外部网络并没有办法访问,并且,Pod Ip是随时会变的,不是固定的,k8s 引入了 Service 的概念,通过 Service 管理这些 PodService 创建后的 Service IP 是固定的。但是 Service IP(Cluster IP) 是一个虚拟的 IP ,由 Kubernetes 管理和分配 IP 地址,外部网络无法访问。k8s 有三种方式暴露 Service 给外部网络访问。

创建 service 与 deployment 流程

image-20240125141158827

  1. 当创建 Deployment 时,Kubernetes 控制器会根据 Deployment 的定义 的 replicas 数创建相应数量的 Pod 副本。这些 Pod 副本将根据 Deployment 的模板 template进行配置,比如 labelsapp: web 并分配唯一独立的 IP 地址,并且具有自己的网络标识。这些 PodIP 地址是由 Kubernetes 集群的网络插件负责分配的。

  2. 在创建 Deployment 时,Deployment 控制器会监控 Pod 的状态,并根据所需的 replicas 副本数来管理它们的运行状态。如果 Pod 发生故障、被删除或需要扩展副本数,Deployment 控制器将负责启动新的 Pod 副本或终止不需要的 Pod 副本,以确保所需的 Pod 数目处于活动状态。

  3. ServiceDeployment 是两个独立的资源对象,它们之间没有直接的关联。但可使用 Service 的标签选择器来选择与 Deployment 关联的 Pod,并将请求路由到这些 Pod 上。

  4. 当创建 Service 并指定与 DeploymentPod 相关联的标签选择器时,Service 将使用该选择器来查找与 Deployment 相关联的 Pod,并将它们作为 Service 的后端目标。当前端客户端发送请求到 Service 时,Service 将使用负载均衡机制将请求转发到与 Deployment 关联的 Pod 上。

  5. 总结: 创建 Deployment 时,Kubernetes 控制器会根据 Deployment 的定义创建 Pod 副本,并为每个 Pod 分配唯一的 IP 地址。Deployment 控制器负责管理 Pod 副本的运行状态。ServiceDeployment 是独立的资源对象,但可以使用 Service 的标签选择器来选择与 Deployment 关联的 Pod ,并将请求路由到这些 Pod 上。

  1. 当创建一个 名为 my-serviceService 时,Kubernetes 会根据 Service 的标签选择器(selector)来查找匹配的 Pod,并为该 Service 创建一个与其同名的 Endpoint 对象。Endpoint 对象存储了与 Service 相关联的 就绪完成的 Pod 的网络地址信息。当创建或删除 Pod 时,Kubernetes 控制器会检测到这些变化,并相应地更新与这些 Pod 相关联的 Endpoint 对象。这意味着当 Pod 的地址发生变化时,Endpoint 对象也会相应地发生变化。

  2. Service 接收来自前端客户端的请求时,它会通过 Endpoint 对象查找要转发到哪个 Pod 的地址进行访问。负载均衡(例如 kube-proxy)会根据一定的算法从 Endpoint 对象中选择一个 Pod 的地址,并将请求转发到该地址上的 Pod。这种机制确保了在 Pod 地址发生变化时,Service 可以动态地更新其所使用的 Endpoint 对象,并将流量正确地路由到新的 Pod 地址上。这使得您可以在集群中动态添加或删除 Pod,并且 Service 能够自动适应这些变化。

总结起来,当创建 Service 时,Kubernetes 会为该 Service 创建一个与其同名的 Endpoint 对象,并根据 Service 的标签选择器来匹配 PodEndpoint 对象存储了与 Service 相关联的 Pod 的网络地址信息。负载均衡通过 Endpoint 对象确定要转发请求的 Pod 地址,并将流量正确地路由到该地址上的 Pod。当 Pod 地址发生变化时,Endpoint 对象会相应地更新,以确保 Service 可以正确地路由请求到新的 Pod 地址上。

Service 有以下几种类型:

默认类型,自动分配一个仅 ClusterIP 内部可以访问的虚拟服务 IP,集群内部有效,适用于集群内多个 service 之间互相通讯;

imges

ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过: NodePort 来访问该服务,外层配合 Nginx 对用户提供访问。

img

NodePort 的基础上,借助 Cloud Provider 创建一个外部负载均衡器,并将请求转发到 NodePort

img

把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有 Kubernetes 1.7或更高版本的kube-dns才支持。

Service 是怎么运行的?
  • 客户端访问节点时通过 iptables 实现
  • iptables 规则是通过 kube-proxy 写入
  • apiserver 通过监控 kube-proxy 去进行对服务和端点的监控
  • kube-proxy 通过 pod 的标签( lables)去判断这个断点信息是否写入到 Endpoints 里

img

暴露服务的三种方式:

ClusterIP 主要在每个 node 节点使用 iptables ,将发向 ClusterIP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口。

img

为了实现图上的功能,主要需要以下几个组件的协同工作:

apiserver:用户通过 kubectl 命令向 apiserver 发送创建 service 的命令, apiserver 接收到请求后将数据存储到 etcdkube-proxyKubernetes的每个节点中都有一个叫做 kube-porxy 的进程,这个进程负责感知 service、 pod 的变化,并将变化的信息写入本地的 iptables 规则中iptables:使用 NAT 等技术将 virtualIP 的流量转至 endpoint 中创建 myapp-deploy.yaml 文件

1. 创建 Service 的 YAML 描述文件

datarc-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: datarc
# 执行创建
kubectl apply -f datarc-namespace.yaml

2. 创建 deployment 资源

datarc-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: datarc
  name: datarc-test-pod
  labels:
    app: datarc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: datarc
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: datarc
    spec:
      containers:
      - image: nginx:1.13
        name: datarc-1
        resources: {}
status: {} 
# 执行创建
kubectl apply -f datarc-deployment.yaml

3. 创建 Service 资源

datarc-service.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: datarc
  name: datarc-test-pod
spec:
  type: ClusterIP
  selector:
    app: datarc
  ports:
  - name: http
    port: 80
    targetPort: 8080
# 执行创建
kubectl apply -f datarc-service.yaml

4. 查看 Service 资源

# 查看 SVC
kubectl get svc -n datarc
kubectl describe svc datarc-test-pod -n datarc

将服务的类型设置成 NodePort 每个集群节点都会在节点上打开一个端口, 对于 NodePort 服务, 每个集群节点在节点本身(因此得名叫 NodePort)上打开一个端口,并将在该端口上接收到的流量重定向到基础服务。该服务仅在内部集群 IP 和端口上才可访间, 但也可通过所有节点上的专用端口访问。

k8s 上可以给 Service 设置成 NodePort 类型,这样的话可以让 Kubernetes 在其所有节点上开放一个端口给外部访问(所有节点上都使用相同的端口号), 并将传入的连接转发给作为 Service 服务对象的 pod。这样我们的 pod 就可以被外部请求访问。

  • (NodePort的原理在于在 Node上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy进一步到给对应的 pod)

1. 创建 Service 的 YAML 描述文件

datarc-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: datarc
# 执行创建
kubectl apply -f datarc-namespace.yaml

2. 创建 deployment 资源

datarc-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: datarc
  name: datarc-test-pod
  labels:
    app: datarc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: datarc
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: datarc
    spec:
      containers:
      - image: nginx:1.13
        name: datarc-1
        resources: {}
status: {}
# 执行创建
kubectl apply -f datarc-deployment.yaml

3. 创建 Service 资源

datarc-service.yaml
apiVersion: v1
kind: Service
metadata:
  namespace: datarc
  name: datarc-test-pod
spec:
  selector:
    app: datarc
  type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
  ports:
  - name: http #名字
    protocol: TCP       #协议类型 TCP/UDP
    port: 80  #集群内的其他容器组可通过 80 端口访问 Service
    targetPort: 80  #将请求转发到匹配 Pod 的 80 端口
    nodePort: 32600   #通过任意节点的 32600 端口访问 Service
    # 注:spec.ports.nodePort这个参数是指Node节点对外开放访问的端口号,如果不指定,则Kubernetes会随机选择一个端口号
# 执行创建
kubectl apply -f datarc-service.yaml

4. 查看 Service 资源

# 查看 SVC
kubectl get svc -n datarc
kubectl describe svc datarc-test-pod -n datarc

NodePort总结

简单易用,但是服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护,所以生产环境不建议这么使用。

将服务的类型设置成 LoadBalance , NodePort 类型的一 种扩展,这使得服务可以通过一个专用的负载均衡器来访问, 这是由 Kubernetes 中正在运行的云基础设施提供的。 负载均衡器将流量重定向到跨所有节点的节点端口。客户端通过负载均衡器的 IP 连接到服务。

"创建自定义 ENDPOINTS"

1. 安装 nginx

2. 编写 endpoint 文件

poststart.yaml
version: '3'
services:
  nginx:
    restart: always
    container_name: nginx
    image: nginx
    ports:
      - 8080:80
image-20240131180434087