• kubernetes之service


    service出现的动机

    Kubernetes Pods 是有生命周期的。他们可以被创建,而且销毁不会再启动。 如果您使用 Deployment 来运行您的应用程序,则它可以动态创建和销毁 Pod。

    每个 Pod 都有自己的 IP 地址,但是在 Deployment 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。

    这导致了一个问题: 如果一组 Pod(称为“后端”)为群集内的其他 Pod(称为“前端”)提供功能,那么前端如何找出并跟踪要连接的 IP 地址,以便前端可以使用工作量的后端部分?

    进入 _Services_。

    定义 Service

    一个 Service 在 Kubernetes 中是一个 REST 对象,和 Pod 类似。 像所有的 REST 对象一样, Servic定义可以基于 POST 方式,请求 API server 创建新的实例。

    例如,假定有一组 Pod,它们对外暴露了 9376 端口,同时还被打上 app=MyApp 标签。

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

    上述配置创建一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,并且具有标签 "app=MyApp"Pod 上。 Kubernetes 为该服务分配一个 IP 地址(有时称为 “集群IP” ),该 IP 地址由服务代理使用。

    没有 selector 的 Service

    服务最常见的是抽象化对 Kubernetes Pod 的访问,但是它们也可以抽象化其他种类的后端。 实例:

    1.希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。

    2.希望服务指向另一个 Namespace 中或其它集群中的服务。

    3.您正在将工作负载迁移到 Kubernetes。 在评估该方法时,您仅在 Kubernetes 中运行一部分后端。

    在任何这些场景中,都能够定义没有 selector 的 Service。 实例:

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      ports:
        - protocol: TCP
          port: 30080
          targetPort: 80

    由于此服务没有选择器,因此 不会 自动创建相应的 Endpoint 对象。 您可以通过手动添加 Endpoint 对象,将服务手动映射到运行该服务的网络地址和端口:

    apiVersion: v1
    kind: Endpoints
    metadata:
      name: my-service
    subsets:
      - addresses:
          - ip: 192.168.100.80
        ports:
          - port: 30080

    VIP 和 Service 代理

    在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。

    为什么不使用 DNS 轮询?

    使用服务代理有以下几个原因:

    1.DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。  

    2.有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。  

    3.即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。

    userspace 代理模式

    这种模式,kube-proxy 会监视 Kubernetes master 对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的backend Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个 backend Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

    最后,它安装 iptables 规则,捕获到达该 ServiceclusterIP(是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod

    默认情况下,用户空间模式下的kube-proxy通过循环算法选择后端。默认的策略是,通过 round-robin 算法来选择 backend Pod

    userspace 代理模式

    iptables 代理模式

    这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会安装 iptables 规则,从而捕获到达该 ServiceclusterIP 和端口的请求,进而将请求重定向到 Service 的一组 backend 中的某个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend 组合。

    默认的策略是,kube-proxy 在 iptables 模式下随机选择一个 backend。

    使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理,而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。

    如果 kube-proxy 在 iptable s模式下运行,并且所选的第一个 Pod 没有响应,则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败,并会自动使用其他后端 Pod 重试。

    您可以使用 Pod readiness 探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着您避免将流量通过 kube-proxy 发送到已知已失败的Pod。

    iptables 代理模式

    IPVS 代理模式

    ipvs 模式下,kube-proxy监视Kubernetes服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保 IPVS 状态与所需状态匹配。 访问服务时,IPVS 将流量定向到后端Pod之一。

    IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数,但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

    IPVS提供了更多选项来平衡后端Pod的流量。 这些是:

    • rr: round-robin
    • lc: least connection (smallest number of open connections)
    • dh: destination hashing
    • sh: source hashing
    • sed: shortest expected delay
    • nq: never queue

    IPVS 代理模式

    注意:

    1.要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS Linux 在节点上可用。

    2.当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

    发布服务 —— 服务类型

    ClusterIP(集群内部通信), NodePort(接入集群外部流量),LoadBalancer(kubernetes部署在云环境上,lbaas负载均衡), ExternalName(集群外部的接入集群内部直接使用)

    ClusterIP类型

    示例

    apiVersion: v1
    kind: Service
    metadata:
         name: redis
         namespace: default
    spec:
         selector:
             app: myweb
             tier: frontend
         clusterIP: 10.98.98.98
         type:
         ports:
         - port: 30080
           targetPort: 80

    验证

    [root@master kubernetes]# kubectl get service
    NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)     AGE
    kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP     5d5h
    redis        ClusterIP   10.98.98.98   <none>        30080/TCP   27m

    [root@master kubernetes]# kubectl get pod --show-labels
    NAME                            READY   STATUS    RESTARTS   AGE   LABELS
    deploy-myweb-85996f4d65-dlgjr   1/1     Running   0          27m   app=myweb,pod-template-hash=85996f4d65,tier=frontend
    deploy-myweb-85996f4d65-fdjcm   1/1     Running   0          27m   app=myweb,pod-template-hash=85996f4d65,tier=frontend
    deploy-myweb-85996f4d65-g9qzg   1/1     Running   0          27m   app=myweb,pod-template-hash=85996f4d65,tier=frontend

    [root@master ~]# while true; do curl 10.98.98.98:30080/hostname.html; sleep 1;done
    deploy-myweb-85996f4d65-fdjcm
    deploy-myweb-85996f4d65-dlgjr
    deploy-myweb-85996f4d65-dlgjr
    deploy-myweb-85996f4d65-fdjcm
    deploy-myweb-85996f4d65-g9qzg
    deploy-myweb-85996f4d65-g9qzg
    deploy-myweb-85996f4d65-g9qzg
    deploy-myweb-85996f4d65-dlgjr

    NodePort类型

    示例

    ---
    apiVersion: v1
    kind: Service
    metadata:
         name: myweb-nodeport
         namespace: default
    spec:
         selector:
             app: myweb
             tier: frontend
         type: NodePort
         clusterIP: 10.99.99.99
         ports:
         - nodePort: 30080
           port: 80
           targetPort: 80

    验证

    [root@master kubernetes]# kubectl get service
    NAME             TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    kubernetes       ClusterIP   10.96.0.1     <none>        443/TCP        6d6h
    myweb-nodeport   NodePort    10.99.99.99   <none>        80:30080/TCP   3m58s

    image

    LoadBalancer 类型

    使用支持外部负载均衡器的云提供商的服务,设置 type 的值为 "LoadBalancer",将为 Service 提供负载均衡器。 负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过 Servicestatus.loadBalancer 字段被发布出去。

    实例:

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: MyApp
      ports:
        - protocol: TCP
          port: 80
          targetPort: 9376
      clusterIP: 10.0.171.239
      loadBalancerIP: 78.11.24.19
      type: LoadBalancer
    status:
      loadBalancer:
        ingress:
          - ip: 146.148.47.155

    来自外部负载均衡器的流量将直接打到 backend Pod 上,不过实际它们是如何工作的,这要依赖于云提供商。

    在这些情况下,将根据用户设置的 loadBalancerIP 来创建负载均衡器。 某些云提供商允许设置 loadBalancerIP。如果没有设置 loadBalancerIP,将会给负载均衡器指派一个临时 IP。 如果设置了 loadBalancerIP,但云提供商并不支持这种特性,那么设置的 loadBalancerIP 值将会被忽略掉。

    ExternalName类型

    如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。 通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量,将会被路由到 Service 的 Endpoint 上。 externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。

    根据 Service 的规定,externalIPs 可以同任意的 ServiceType 来一起指定。 在上面的例子中,my-service 可以在 “80.11.12.10:80”(externalIP:port) 上被客户端访问。

    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        app: MyApp
      ports:
        - name: http
          protocol: TCP
          port: 80
          targetPort: 9376
      externalIPs:
        - 80.11.12.10
  • 相关阅读:
    ASP.NET Core新书终于上市,完成今年一个目标,赠书活动
    .NET 5.0 RC2 发布,正式版即将在 11 月 .NET Conf 大会上发布
    .NET Standard 来日苦短去日长
    [C#.NET 拾遗补漏]09:数据标注与数据校验
    几个超级实用但很少人知道的 VS 技巧[更新]
    .NET 5 中 Target Framework 详解
    .NET 5.0 RC1 发布,离正式版发布仅剩两个版本
    Git 实用操作:撤销 Commit 提交(动图讲解)
    Git 实用操作:重写 Commit 历史
    [C#.NET 拾遗补漏]08:强大的LINQ
  • 原文地址:https://www.cnblogs.com/mycloudedu/p/12046782.html
Copyright © 2020-2023  润新知