zoukankan      html  css  js  c++  java
  • KubernetesService

    1. 简介

    kubernets service 是将运行一组pods上的应用程序公开为网络服务的抽象方法。

    有了 kubernets service,你就无需修改应用程序即可使用服务发现机制,kubernets 为 pods 提供自己的ip地址,并为一组pod提供相同的DNS名,并且可以在它们之间进行负载均衡。

    2. 为什么要用services

    创建和销毁 kubernets pod 以匹配集群状态。pod 是非永久性资源。如果你使用 Deployment 来运行你的应用程序,则它可以动态创建和销毁 Pod。

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

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

    3. quick start

    3.1 创建svc

    资源模板 svc-deploy-nginx.yaml信息如下:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: nginx-deploy-test
      name: nginx-test-1
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx-test
      template:
        metadata:
          labels:
            app: nginx-test
        spec:
          containers:
          - image: nginx:latest
            name: nginx
            imagePullPolicy: IfNotPresent
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: my-service
    spec:
      selector:
        # must be match pod template .spec.template.labels
        app: nginx-test
      ports:
        - protocol: TCP
          port: 8000
          targetPort: 80
    

    创建一个deploy,和一个 svc

    注意 svc selector 对应的是 deploy 的 .spec.template.labels

    创建资源

    $ kubectl create -f svc-deploy-nginx.yaml
    

    3.2 查看svc

    1. 使用资源文件查看

      $ kubectl get  -f svc-deploy-nginx.yaml -o wide
      # 输出内容如下
      # deploy 信息
      NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
      deployment.apps/nginx-test-1   3/3     3            3           42m   nginx        nginx:latest   app=nginx-test
      # svc 信息
      NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE   SELECTOR
      service/my-service   ClusterIP   10.96.112.5   <none>        8000/TCP   42m   app=nginx-test
      
    2. 使用命令查看

      查看svc 信息

      $ kubectl get svc/my-service -owide
      NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE   SELECTOR
      my-service   ClusterIP   10.96.112.5   <none>        8000/TCP   45m   app=nginx-test
      

      查看endpoints信息

      可以看到成功的绑定了三个pod endpoint

      $ kubectl get ep/my-service
      NAME         ENDPOINTS                                               AGE
      my-service   10.100.132.133:80,10.100.132.139:80,10.100.132.140:80   46m
      

      查看svc 详细信息

      $ kubectl describe svc/my-service
      Name:              my-service
      Namespace:         default
      Labels:            <none>
      Annotations:       <none>
      Selector:          app=nginx-test
      Type:              ClusterIP
      IP:                10.96.112.5
      Port:              <unset>  8000/TCP
      TargetPort:        80/TCP
      Endpoints:         10.100.132.133:80,10.100.132.139:80,10.100.132.140:80
      Session Affinity:  None
      Events:            <none>
      

    3.3 访问svc

    在上面的实例中svc 并没有指定 svc type,其默认为ClusterIP类型(从上面的详情信息中也能看出)。

    我们现在访问下实例中的svc

    1. 在集群内部访问

      在集群机器上可以使用ClusterIp 访问服务,但是无法通过 svc name访问

      在集群pod中可以使用任意方式访问服务

    2. 在集群外部访问

      集群外部 没有办法直接访问 svc type=ClusterIp 的svc

    4. svc type

    svc 有以下的几种类型:

    • ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType

    • NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。

    • LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。

    • ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。

      说明: 需使用 kube-dns 1.7 及以上版本或者 CoreDNS 0.0.8 及以上版本才能使用 ExternalName 类型。

    4.1 ClusterIp

    1. ClusterIp是默认的svc类型,在创建该资源时,kubernetes会默认分配一个 cluster ip。
    2. svc端口为.spec.ports.port,其代理的后端服务的目标端口为.spec.ports.targetPort
    3. 其cluster ip 只能在集群内部访问,如果想通过svc name 访问其代理的服务,只能在pod中访问。其验证过程可参考3.3 访问svc
    4. 集群外部的资源无法访问ClusterIp类型的svc。

    4.2 NodePort

    node(节点)port(端口),顾名思义 NodePort类型的svc是通过在集群的宿主机上开放访问的端口,并通过 <节点 IP>:<节点端口>(集群任意节点ip:nodeport 都可以访问)来实现从集群外部访问其svc的。

    nodePort 的原理在于在 node 上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的 pod。(能够将内部服务暴露给外部的一种方式)

    1. 创建资源

      一个deploy 和 一个 nodeport svc,且指定了node 端口为30007(如果不指定,k8s会默认分配一个)

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: nginx-deploy-test
        name: nginx-test-2
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: nginx-test-02
        template:
          metadata:
            labels:
              app: nginx-test-02
          spec:
            containers:
            - image: nginx:latest
              name: nginx
              imagePullPolicy: IfNotPresent
      
      ---
      
      apiVersion: v1
      kind: Service
      metadata:
        name: my-service-2
      spec:
        type: NodePort
        selector:
          app: nginx-test-02
        ports:
          - protocol: TCP
            port: 8000
            targetPort: 80
            # 可选字段
            # 默认情况下,为了方便起见,Kubernetes 会从范围内分配一个端口号(默认:30000-32767)
            nodePort: 30007
      
    2. 访问svc

    4.3 LoadBalancer

    使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。

    4.4 ExternalName

    类型为 ExternalName 的服务将服务映射到 DNS 名称,而不是典型的选择器,例如 其他svc 或者 公网域名。 你可以使用 spec.externalName 参数指定这些服务。

    1. 创建服务

      例如,以下 Service 定义将 default 名称空间中的 my-service-2 服务映射到 my-service-1.test.svc.cluster.local(test 名称空间中的 my-service-1 service):

      apiVersion: v1
      kind: Service
      metadata:
        name: my-service-2
      spec:
        type: ExternalName
        externalName: my-service-1.test.svc.cluster.local
      

      服务信息如下:

      服务是在default namespace 下

      没有分配CLUSTER-IP,但是有我们指定的 EXTERNAL-IP

      $ kubectl get svc -owide
      
      NAME           TYPE           CLUSTER-IP   EXTERNAL-IP                           PORT(S)   AGE    SELECTOR
      kubernetes     ClusterIP      10.96.0.1    <none>                                443/TCP   170d   <none>
      my-service-2   ExternalName   <none>       my-service-1.test.svc.cluster.local   <none>    41s    <none>
      

      为了验证映射效果,我们再创建一个my-service-1.test service

      注意 服务都是在test namespace 下

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        labels:
          app: nginx-deploy-test
        name: nginx-test-1
        namespace: test
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: nginx-test
        template:
          metadata:
            labels:
              app: nginx-test
          spec:
            containers:
            - image: nginx:latest
              name: nginx
              imagePullPolicy: IfNotPresent
      
      ---
      
      apiVersion: v1
      kind: Service
      metadata:
        name: my-service-1
        namespace: test
      spec:
        selector:
          app: nginx-test
        ports:
          - protocol: TCP
            port: 8000
            targetPort: 80
      

      服务信息如下:

      $ kubectl get -f app-nginx.yaml -owide
      
      NAME                           READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
      deployment.apps/nginx-test-1   3/3     3            3           48s   nginx        nginx:latest   app=nginx-test
      
      NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
      service/my-service-1   ClusterIP   10.96.188.235   <none>        8000/TCP   47s   app=nginx-test
      
    2. 访问svc

      首先我们创建一个pod 用来访问 验证 svc

      服务信息如下:

      $ kubectl get po -owide
      NAME         READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
      helloworld   1/1     Running   0          7d23h   10.100.132.161   k8s-woker-01   <none>           <none>
      

      ok,到这里 资源都以就绪,如果我们进入到 pod/helloworld 去访问 svc/my-service-2,如果能成功访问到naginx 服务,则证明ExternalName svc这种方式是可行的:

    4.5 Headless Services

    准确来说 Headless Services 并不属于svc的type,而是 clusterip类型的变种

    有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service。

    对这无头 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

    无选择算符的服务

    对没有定义选择算符的无头服务,Endpoint 控制器不会创建 Endpoints 记录。 然而 DNS 系统会查找和配置,无论是:

    • 对于 ExternalName类型的服务,查找其 CNAME 记录
    • 对所有其他类型的服务,查找与 Service 名称相同的任何 Endpoints 的记录

    关于Headless Services 在k8s-statefulset博文中 有详细的记录,感兴趣的可以访问了解下。

    5. externalIPs

    Service 的 externalIPs(spec.externalIPs)可以设置一组外部的 IP 地址,并且将流量导入到集群内部。

    如图:

    启动一个springboot项目 并初始化一个接口,访问后返回 Hello World~

    在本机上访问:

    接下来我们就使用externalIPs192.168.0.101流量导入到集群内部

    目标:集群pod中访问192.168.0.101:8080时不是访问此时的这个springboot项目,而是访问集群内的externalIPs svc

    1. 首先到集群master节点访问一下springboot项目

      访问成功

      $ curl 192.168.0.101:8080
      Hello World~
      
    2. 创建externalIPs svc,和想导入到集群的目标pod

      本实例主要是为了展示流量的切换,但其实spec.externalIPs 可以指定符合ip 规则的任意地址(即使设置的ip不可达),k8s都会帮你 在访问设置地址的服务时,将流量导入到spec.selector的服务中去

      实际上就是 如果你把spec.externalIPs地址设置成123.123.123.123,当你在服务中访问123.123.123.123时,其实访问的是spec.selector指定的服务

      其实更像是 给spec.selector到服务指定了一个 ipv4 的别名

      apiVersion: v1
      kind: Service
      metadata:
        name: nginx
        labels:
          app: nginx
      spec:
        ports:
        - port: 8080
          targetPort: 80
          name: web
        externalIPs:
        - "192.168.0.101"
        # 将 192.168.0.101 流量导入到 下面的Deployment中
        selector:
          app: nginx
          
      ---
      
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: web
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: nginx
        template:
          metadata:
            labels:
              app: nginx
          spec:
            containers:
            - name: nginx
              image: nginx
              ports:
              - containerPort: 80
                name: web
      

      服务信息如下:

      $ kubectl get deploy -owide
      NAME   READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES   SELECTOR
      web    2/2     2            2           3h25m   nginx        nginx    app=nginx
      
      $ kubectl get svc/nginx -owide
      NAME         TYPE        CLUSTER-IP     EXTERNAL-IP     PORT(S)    AGE    SELECTOR
      nginx        ClusterIP   10.96.41.170   192.168.0.101   8080/TCP   4m     app=nginx
      
    3. 创建一个pod 并进入pod ,在pod中访问192.168.0.101:8080查看访问的是外部的springboot项目还是集群内的deploy/web

      很显然:k8s成功的将流量导入到了集群内部

      如果在集群节点上访问192.168.0.101:8080,是不能将结果导入到deploy上的,只有在集群服务内部访问才有效

    4. 此时我们将svc/nginx 删除掉,看下访问的结果

      符合预期

    6. 管理外部的服务

    场景:如果我们的中间件或者数据库服务不是在k8s集群内的,而是在其他的服务器上,但是我们还是想通过访问svc的方式去访问这些外部的服务,我们应该怎么做呢?

    1. 声明一个没有选择符的svc
    2. 创建一个同名(和第一步中的svc name 相同)的 endpoints 服务去管理这些外部的服务地址

    实例:

    实例通过创建svc 和 endpoints,实现访问svc-name,svc 将流量导出到外部的springboot(项目信息如5.0中提到的)项目中

    1. 创建服务

      apiVersion: v1
      kind: Service
      metadata:
        name: my-service
      spec:
        ports:
          - protocol: TCP
            port: 80
            targetPort: 8080
      
      ---
      
      apiVersion: v1
      kind: Endpoints
      metadata:
        # must be match svc-name
        name: my-service
      subsets:
        - addresses:
            # 指向外部的springboot 服务
            - ip: 192.168.0.101
          ports:
            - port: 8080
      
    2. 访问测试

    7. 选择自己的 IP 地址

    Service 创建的请求中,可以通过设置 spec.clusterIP 字段来指定自己的集群 IP 地址。

  • 相关阅读:
    9.对话框
    8.布局管理器
    7.对象模型
    6.添加动作
    5.Qt模块简介
    4.自定义信号槽
    3.信号槽
    2.Helloworld
    1.Qt简介
    Problem E: 成绩排序
  • 原文地址:https://www.cnblogs.com/ludangxin/p/15760914.html
Copyright © 2011-2022 走看看