• kubernetes系列08—service资源详解


    本文收录在容器技术学习系列文章总目录

    1、认识service

    1.1 为什么要使用service

      Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行 滚动升级)。 每个 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?答案是:Service

    1.2 service介绍

      Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。 这一组 Pod 能够被 Service 访问到,通常是通过 Label Selector(下面我们会讲到我们为什么需要一个没有label selector的服务)实现的。

      举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。 Service 定义的抽象能够解耦这种关联。

      对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变更,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod

    1.3 三种代理模式

    •  userspace 代理模式(K8S 1.1之前版本)
    •  iptables 代理模式(K8S 1.10之前版本)
    •  ipvs 代理模式(K8S 1.11 之后版本,激活ipvs需要修改配置)

    1.3.1 userspace 代理模式

      这种模式,kube-proxy 会监视 Kubernetes master  Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到代理端口的请求,都会被代理到 Service backend Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个 backend Pod,是基于 Service  SessionAffinity 来确定的。 最后,它安装 iptables 规则,捕获到达该 Service  clusterIP(是虚拟 IP)和 Port 的请求,并重定向到代理端口,代理端口再代理请求到 backend Pod

      网络返回的结果是,任何到达 Service IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 KubernetesService、或 Pod 的任何信息。

      默认的策略是,通过 round-robin 算法来选择 backend Pod。 实现基于客户端 IP 的会话亲和性,可以通过设置 service.spec.sessionAffinity 的值为 "ClientIP" (默认值为 "None")。

     1.3.2 iptables 代理模式

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

      默认的策略是,随机选择一个 backend实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。

      和 userspace 代理类似,网络返回的结果是,任何到达 Service IP:Port 的请求,都会被代理到一个合适的 backend,不需要客户端知道关于 KubernetesService、或 Pod 的任何信息。 这应该比 userspace 代理更快、更可靠。然而,不像 userspace 代理,如果初始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes

    1.3.3 ipvs代理模式

      ipvs (IP Virtual Server) 实现了传输层负载均衡,也就是我们常说的4LAN交换,作为 Linux 内核的一部分。ipvs运行在主机上,在真实服务器集群前充当负载均衡器。ipvs可以将基于TCPUDP的服务请求转发到真实服务器上,并使真实服务器的服务在单个 IP 地址上显示为虚拟服务。

      在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中处于 beta 阶段,在 v1.11 中已经正式可用了。 iptables 模式在 v1.1 中就添加支持了,从 v1.2 版本开始 iptables 就是 kube-proxy 默认的操作模式,ipvs iptables 都是基于netfilter的, ipvs 模式和 iptables 模式之间的差异:

    •  ipvs 为大型集群提供了更好的可扩展性和性能
    •  ipvs 支持比 iptables 更复杂的复制均衡算法(最小负载、最少连接、加权等等)
    •  ipvs 支持服务器健康检查和连接重试等功能

      同时ipvs 也依赖 iptablesipvs 会使用 iptables 进行包过滤、SNATmasquared(伪装)。具体来说,ipvs 将使用ipset来存储需要DROPmasquared的流量的源或目标地址,以确保 iptables 规则的数量是恒定的,这样我们就不需要关心我们有多少服务了

    ipvs虽然在v1.1版本中已经支持,但是想要使用,还需激活ipvs

    修改配置文件

    [root@master ~]# vim /etc/sysconfig/kubelet
    KUBE_PROXY=MODE=ipvs

    编写脚本,让kubelet所在的主机,启动时装入以下几个模块:

    ip_vsip_vs_rrip_vs_wrrip_vs_shnf_conntrack_ipv4

    1.4 service定义资源清单几个字段

    •  apiVersionv1  版本
    •  kindService  类型
    •  metadata  元数据
    •  spec  期望状态
      •  ports:服务公开的端口列表;把哪个端口和后端建立联系
        •  port:此服务将公开的端口
        •  targetPort:要在服务所针对的pod上访问的端口的编号或名称
        •  nodePortK8S 集群节点上的端口
      •  selector:标签选择器;关联到哪些pod资源上
      •  clusterIP:服务的IP地址,通常由主服务器随机分配
      •  type:确定服务的公开方式。 默认为ClusterIP
        •  ClusterIP(默认)
        •  NodePort
        •  LoadBalancer
        •  ExternelName
      •  sessionAffinityservice负载均衡,默认值是None,根据iptables规则随机调度;可使用sessionAffinity保持会话连线;
    •  status  当前状态

    1.5 service4中类型

    •  ClusterIP(默认):仅用于集群内通信,集群内部可达,可以被各pod访问,节点本身可访问;
    •  NodePort:构建在ClusterIP上,并在路由到clusterIP的每个节点上分配一个端口;
      •  client ---> NodeIP:NodePort ---> ClusterIP:ServicePort ---> PodIP:containePort
    •  LoadBalancer:构建在NodePort上,并创建一个外部负载均衡器(如果在当前云中受支持),它将路由到clusterIP
    •  ExternelName:通过CNAMEserviceexternalName的值(比如:foo.bar.example.com)映射起来. 要求kube-dns的版本为1.7或以上.

    2、创建clusterIP类型的service

    1)编写yaml文件并创建名为redisservice

    先创建一个deployment,启动一个redis pod;在使用service绑定这个pod

    [root@master manifests]# vim redis-svc.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: redis
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: redis
          role: logstor
      template:
        metadata:
          labels:
            app: redis
            role: logstor
        spec:
          containers:
          - name: redis
            image: redis:4.0-alpine
            ports:
            - name: redis
              containerPort: 6379
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: redis
      namespace: default
    spec:
      selector:
        app: redis
        role: logstor
      clusterIP: 10.99.99.99
      type: ClusterIP
      ports:
      - port: 6380
        targetPort: 6379
    [root@master manifests]# kubectl apply -f redis-svc.yaml
    deployment.apps/redis created
    service/redis created
    

      

    2)查询验证

    [root@master ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    142d
    redis        ClusterIP   10.99.99.99   <none>        6380/TCP   12s
    ---查询service详细信息,pod绑定成功
    [root@master ~]# kubectl describe svc redis
    Name:              redis
    Namespace:         default
    Labels:            <none>
    Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.99.99.99","ports":[{"por...
    Selector:          app=redis,role=logstor
    Type:              ClusterIP
    IP:                10.99.99.99
    Port:              <unset>  6380/TCP
    TargetPort:        6379/TCP
    Endpoints:         10.244.2.94:6379
    Session Affinity:  None
    Events:            <none>
    

      

    3、创建NodePort类型的service

    3.1 创建service

    1)编写yaml文件并创建名为myappservice

    先创建一个deployment,启动3myapp pod;在使用service绑定这3pod

    [root@master manifests]# vim myapp-svc.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: myapp-deploy
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: myapp
          release: canary
      template:
        metadata:
          labels:
            app: myapp
            release: canary
        spec:
          containers:
          - name: myapp
            image: ikubernetes/myapp:v1
            ports:
            - name: http
              containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: myapp
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      clusterIP: 10.97.97.97
      type: NodePort
      ports:
      - port: 80
        targetPort: 80
        nodePort: 31180
    [root@master manifests]# kubectl apply -f myapp-svc.yaml
    deployment.apps/myapp-deploy unchanged
    service/myapp created
    

      

    2)查询验证

    [root@master ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
    myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   39s
    redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d
    [root@master ~]# kubectl describe svc myapp
    Name:                     myapp
    Namespace:                default
    Labels:                   <none>
    Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","ports":[{"nod...
    Selector:                 app=myapp,release=canary
    Type:                     NodePort
    IP:                       10.97.97.97
    Port:                     <unset>  80/TCP
    TargetPort:               80/TCP
    NodePort:                 <unset>  31180/TCP
    Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
    Session Affinity:         None
    External Traffic Policy:  Cluster
    Events:                   <none>
    

      

    3)在集群外访问服务

    3.2 使用sessionAffinity保持会话连接

    1sessionAffinity默认是None,没有修改前,访问业务是随机调度

    [root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
    myapp-deploy-69b47bc96d-mmb5v
    myapp-deploy-69b47bc96d-wtbx7
    myapp-deploy-69b47bc96d-wtbx7
    myapp-deploy-69b47bc96d-cj48v
    ... ...
    

      

    2)打补丁修改sessionAffinityclientip;实现会话连接

    也可以使用exec修改;或者直接修改yaml文件也可以;

    [root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
    service/myapp patched
    

      

    3)查询验证

    [root@master ~]# kubectl describe svc myapp
    Name:                     myapp
    Namespace:                default
    Labels:                   <none>
    Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","ports":[{"nod...
    Selector:                 app=myapp,release=canary
    Type:                     NodePort
    IP:                       10.97.97.97
    Port:                     <unset>  80/TCP
    TargetPort:               80/TCP
    NodePort:                 <unset>  31180/TCP
    Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
    Session Affinity:         ClientIP
    External Traffic Policy:  Cluster
    Events:                   <none>
    

      

    4)访问业务查询验证;发现同一客户端的请求始终发往同一pod

    [root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
    myapp-deploy-69b47bc96d-cj48v
    myapp-deploy-69b47bc96d-cj48v
    myapp-deploy-69b47bc96d-cj48v
    myapp-deploy-69b47bc96d-cj48v
    ... ...
    

      

    5)重新打补丁修改为None,立即恢复为随机调度

    [root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
    service/myapp patched
    [root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
    myapp-deploy-69b47bc96d-cj48v
    myapp-deploy-69b47bc96d-mmb5v
    myapp-deploy-69b47bc96d-cj48v
    myapp-deploy-69b47bc96d-mmb5v
    

      

    4、创建无头service

    1)编写yaml文件并创建名为myapp-svcservice

    绑定上面创建myapp3pod

    [root@master manifests]# vim myapp-svc-headless.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: myapp-svc
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      clusterIP: None
      ports:
      - port: 80
        targetPort: 80
    [root@master manifests]# kubectl apply -f myapp-svc-headless.yaml
    service/myapp-svc created
    

      

    2)查询验证

    [root@master ~]# kubectl get svc
    NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
    kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
    myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   2h
    myapp-svc    ClusterIP   None          <none>        80/TCP         6s
    redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d
    

      

    3)和有头正常myappservice对比

    无头service的解析:

    [root@master manifests]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
    ... ...
    ;; ANSWER SECTION:
    myapp-svc.default.svc.cluster.local. 5 IN A	10.244.1.96
    myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.101
    myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.102
    ... ...

    有头正常myappservice的解析:

    [root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
    ... ...
    ;; ANSWER SECTION:
    myapp.default.svc.cluster.local. 5 IN	A	10.97.97.97
    ... ...
    

     

  • 相关阅读:
    LeetCode 42. Trapping Rain Water
    LeetCode 209. Minimum Size Subarray Sum
    LeetCode 50. Pow(x, n)
    LeetCode 80. Remove Duplicates from Sorted Array II
    Window10 激活
    Premiere 关键帧缩放
    AE 「酷酷的藤」特效字幕制作方法
    51Talk第一天 培训系列1
    Premiere 视频转场
    Premiere 暴徒生活Thug Life
  • 原文地址:https://www.cnblogs.com/along21/p/10330076.html
Copyright © 2020-2023  润新知