kubernetes service

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
全局流量管理 GTM,标准版 1个月
简介: kubernetes service

概念介绍

1.pod的生命周期

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


2.什么是service

Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。这一组Pod能够被Service访问到,通常是通过 Label Selector实现的。举个例子,考虑一个图片处理backend,它运行了3个副本。这些副本是可互换的 —— frontend 不需要关心它们调用了哪个 backend 副本。然而组成这一组 backend程序的Pod实际上可能会发生变化,frontend客户端不应该也没必要知道,而且也不需要跟踪这一组 backend 的状态。Service 定义的抽象能够解耦这种关联。


3.service代理pod

例如想要用nginx反向代理tomcat,那么tomcat如果是通过pod部署的,pod的ip可能会随时变化,那么我们就需要在所有这些部署tomcat的pod前面加上一个固定接入层,我们nginx反向代理只需要写service地址,就会代理到后端的pod,那么pod就算ip怎么变化,通过service都可以找到

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

service是一个固定接入层,客户端可以通过访问service来访问到后端pod,kube-proxy为service生成一个iptables规则


案例演示

通过Service访问pod


1.创建pod

cat  pod_test.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 80

(2)执行yaml文件

    kubectl apply -f pod_test.yaml

    这使得可以从集群中任何一个节点来访问它。检查节点,通过如下命令查看Pod是否正在运行:


      kubectl get pods -l run=my-nginx -o wide

      看到的pod是running说明创建成功

      (3)检查 Pod 的 IP 地址:


        kubectl get pods -l run=my-nginx -o yaml | grep podIP

        显示如下:

        podIP: 10.244.3.40
         cni.projectcalico.org/podIP: 10.244.3.42/32
         podIP: 10.244.3.42

        应该能够通过ssh登录到集群中的任何一个节点上,使用curl也能调通所有IP地址。需要注意的是,容器不会使用该节点上的80端口,也不会使用任何特定的 NAT规则去路由流量到Pod上。这意味着可以在同一个节点上运行多个Pod,使用相同的容器端口,并且可以从集群中任何其他的 Pod 或节点上使用 IP 的方式访问到它们。像Docker 一样,端口能够被发布到主机节点的接口上,但是出于网络模型的原因应该从根本上减少这种用法。


        2.创建service


        我们所有Pod在一个扁平的、集群范围的地址空间中运行Nginx服务,可以直接连接到这些Pod,但如果某个节点死掉了会发生什么呢?Pod会终止,Deployment 将创建新的 Pod,且使用不同的 IP。这正是 Service 要解决的问题。Kubernetes Service从逻辑上定义了运行在集群中的一组 Pod,这些 Pod 提供了相同的功能。当每个Service 创建时,会被分配一个唯一的IP地址(也称为 clusterIP)。这个 IP 地址与一个Service 的生命周期绑定在一起,当Service存在的时候它也不会改变。可以配置 Pod 使它与 Service 进行通信,Pod 知道与Service通信将被自动地负载均衡到该Service中的某些 Pod 上。

        (1)创建service

        cat service.yaml

        apiVersion: v1
        kind: Service
        metadata:
          name: my-nginx
          labels:
            run: my-nginx
        spec:
          ports:
          - port: 80
            protocol: TCP
          selector:
            run: my-nginx

        (2)执行service的yaml文件

          kubectl  apply -f service.yaml

          上述yaml将创建一个Service,对应具有标签run: my-nginx的Pod,目标TCP 端口80,并且在一个抽象的Service端口(targetPort:容器接收流量的端口;port:抽象的Service 端口,可以使任何其它Pod访问该Service的端口)上暴露。查看 Service API 对象了解 Service 定义支持的字段列表。

            kubectl get svc my-nginx

            显示如下:

            NAME       CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
            my-nginx   10.104.137.147   <none>      80/TCP    10m


            正如前面所提到的,一个Service由一组backend Pod组成。这些Pod通过 endpoints暴露出来。Service Selector将持续评估,结果被POST到一个名称为 my-nginx 的 Endpoint 对象上。当Pod 终止后,它会自动从Endpoint中移除,新的能够匹配上Service Selector 的 Pod 将自动地被添加到Endpoint中。检查该Endpoint,注意到IP地址与在第一步创建的 Pod 是相同的。

            kubectl describe svc my-nginx

            显示如下:

            Name:              my-nginx
            Namespace:         default
            Labels:            run=my-nginx
            Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                                 {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"run":"my-nginx"},"name":"my-nginx","namespace":"default"},"spe...
            Selector:          run=my-nginx
            Type:              ClusterIP
            IP:                10.104.137.147
            Port:              <unset>  80/TCP
            TargetPort:        80/TCP
            Endpoints:         10.244.3.40:80,10.244.3.42:80,10.244.3.43:80
            Session Affinity:  None
            Events:            <none>

            kubectl get ep my-nginx

            显示如下:

            NAME       ENDPOINTS                     AGE
            my-nginx   10.244.2.5:80,10.244.3.4:80   1m

            现在,能够从集群中任意节点上使用curl 命令请求Nginx Service <CLUSTER-IP>:<PORT>

            curl 10.104.137.147:80  通过访问service ip:port可以路由到后端的pod

            注:把上面的ClusterIP类型变成NodePort类型,供集群外部访问

            在原有的基础上,增加一个字段type,如下所示

            cat service.yaml

            apiVersion: v1
            kind: Service
            metadata:
              name: my-nginx
              labels:
                run: my-nginx
            spec:
              ports:
              - port: 80
                protocol: TCP
              type:
                NodePort
              selector:
                run: my-nginx

            kubectl  apply  -f service.yaml

            kubectl  get  svc

            显示如下:

            上面截图可以发现my-nginx这个service 的TYPE类型变成了NodePort

            service type类型介

            1.没有selector的Service,type类型是ExternalName,k8s集群内到外的访问

            Servcie抽象了该如何访问Kubernetes Pod,但也能够抽象其它类型的backend,例如:

            希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
            希望服务指向另一个Namespace中或其它集群中的服务。
            正在将工作负载转移到Kubernetes集群,和运行在Kubernetes集群之外的backend。

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

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

            由于这个Service没有selector,就不会创建相关的Endpoints对象。可以手动将 Service 映射到指定的 Endpoints

              kind: Endpoints
              apiVersion: v1
              metadata:
                name: my-service
              subsets:
                - addresses:
                    - ip: 1.2.3.4  #这个地址可以是集群外部的地址,如mysql等
                  ports:
                    - port: 3306
              

              注意:

              Endpoint IP地址不能是loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。

              访问没有selector的 Service,与有 selector 的 Service 的原理相同。请求将被路由到用户定义的Endpoint(该示例中为 1.2.3.4:3306)ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和Endpoint。相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

              kind: Service
              apiVersion: v1
              metadata:
                name: my-service
                namespace: prod
              spec:
                type: ExternalName
                externalName: my.database.example.com

              当查询主机my-service.prod.svc.CLUSTER时,集群的DNS服务将返回一个值为 my.database.example.com 的 CNAME 记录。访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在DNS层,而且不会进行代理或转发。如果后续决定要将数据库迁移到Kubernetes集群中,可以启动对应的 Pod,增加合适的Selector或Endpoint,修改Service的type。


              2.Headless Service

              有时不需要或不想要负载均衡,以及单独的Service IP。遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。这个选项允许开发人员自由寻找他们自己的方式,从而降低与Kubernetes系统的耦合性。应用仍然可以使用一种自注册的模式和适配器,对其它需要发现机制的系统能够很容易地基于这个API来构建。对这类 Service 并不会分配Cluster IP,kube-proxy不会处理它们,而且平台也不会为它们进行负载均衡和路由。DNS 如何实现自动配置,依赖于Service是否定义了selector

              (1)配置 Selector

              对定义了selector的Headless Service,Endpoint控制器在API中创建了Endpoints记录,并且修改DNS配置返回A记录(地址),通过这个地址直接到达 Service 的后端 Pod 上

              (2)不配置 Selector

              对没有定义 selector 的Headless Service,Endpoint控制器不会创建 Endpoints记录。然而DNS系统会查找和配置,无论是:ExternalName 类型 Service 的CNAME记录,以及所有其它类型。

              记录:与 Service 共享一个名称的任何 Endpoints


              3.NodePort 类型

              如果设置type的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个Node将从该端口(每个 Node 上的同一端口)代理到 Service。该端口将通过 Service的spec.ports[*].nodePort 字段被指定。如果需要指定的端口号,可以配置nodePort的值,系统将分配这个端口,否则调用API将会失败(比如,需要关心端口冲突的可能性)。这可以让开发人员自由地安装他们自己的负载均衡器,并配置 Kubernetes 不能完全支持的环境参数,或者直接暴露一个或多个 Node 的 IP 地址。需要注意的是,Service 将能够通过 <NodeIP>:spec.ports[*].nodePort 和 spec.clusterIp:spec.ports[*].port 而对外可见。


              4.LoadBalancer 类型

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

              kind: Service
              apiVersion: v1
              metadata:
                name: my-service
              spec:
                selector:
                  app: MyApp
                ports:
                  - protocol: TCP
                    port: 80
                    targetPort: 9376
                    nodePort: 30061
                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值将会被忽略掉。


              5.AWS 内部负载均衡器

              在混合云环境中,有时从虚拟私有云(VPC)环境中的服务路由流量是非常有必要的。可以通过在 Service 中增加 annotation 来实现,如下所示:

              [...]metadata: 
                  name: my-service
                  annotations: 
                      service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0[...]

              在水平分割的 DNS 环境中,需要两个 Service 来将外部和内部的流量路由到 Endpoint 上。


              6.externalIP

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

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

              kind: Service
              apiVersion: v1
              metadata:
                name: my-service
              spec:
                selector:
                  app: MyApp
                ports:
                  - name: http
                    protocol: TCP
                    port: 80
                    targetPort: 3306
                externalIPs: 
                  - 80.11.12.10
              相关实践学习
              通过Ingress进行灰度发布
              本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
              容器应用与集群管理
              欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
              相关文章
              |
              2月前
              |
              Kubernetes 容器
              K8S的Service的LoadBanlance之Metallb解决方案
              本文介绍了如何在Kubernetes中使用MetalLB来实现Service的LoadBalancer功能,包括MetalLB的部署、配置、以及通过创建地址池和部署服务来测试MetalLB的过程。
              121 1
              K8S的Service的LoadBanlance之Metallb解决方案
              |
              3月前
              |
              Kubernetes 网络安全 容器
              在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?
              在K8S中,有个服务使用service的nodeport进行暴露,发现访问不到如何排查?
              |
              3月前
              |
              Kubernetes 负载均衡 网络协议
              在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
              在K8S中,Service的类型有哪几种,请说⼀下他们的用途?
              |
              3月前
              |
              Kubernetes 监控 API
              在k8S中,Metric Service是什么?
              在k8S中,Metric Service是什么?
              |
              3月前
              |
              Kubernetes 负载均衡 网络协议
              在k8S中,Headless Service是什么?
              在k8S中,Headless Service是什么?
              |
              3月前
              |
              Kubernetes 负载均衡 网络协议
              在K8S中,Service的类型有哪些?
              在K8S中,Service的类型有哪些?
              |
              3月前
              |
              Kubernetes API 容器
              在K8S中,Service的Nodeport端口范围?
              在K8S中,Service的Nodeport端口范围?
              |
              3月前
              |
              Kubernetes 网络协议 网络安全
              在K8S中,k8s中service访问有问题,该如何排查?
              在K8S中,k8s中service访问有问题,该如何排查?
              |
              3月前
              |
              Kubernetes Perl 容器
              在k8S中,Service怎么关联Pod的?
              在k8S中,Service怎么关联Pod的?
              |
              3月前
              |
              Kubernetes 负载均衡 算法
              在k8S中,Service分发后端的策略是什么?
              在k8S中,Service分发后端的策略是什么?