zoukankan      html  css  js  c++  java
  • Kubernetes之十九: Service服务

    认识Service

    1)为什么要使用service

    kubernetes pod是有生命周期的,可以被创建,也可以被销毁;一旦被销毁,通过控制器能够动态创建新的pod,每次pod都会获取自己的IP地址会变动

    2)service介绍


    Kubernetes Service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们不同的策略—通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Sekector实现的;

    对Kubernetes集群中的应用,Kubernetes提供了简单的Endpoints API,只要service中的一组Pod发生变更,应用程序就会被更新。

    对非Kubernetes集群中的应用,Kubernetes提供了基本VIP的网桥的方式访问Service,再由Service重定向到backend Pod


    3)三种代理模式
    userspace 代理模式
    iptables 代理模式
    ipvs 代理模式

    (下图为iptables代理模式)

     (下图为ipvs的代理模式)

    iptables:

    客户端IP请求时,直接请求本地内核service ip,根据iptables的规则直接将请求转发到到各pod上,因为使用iptable NAT来完成转发,也存在不可忽视的性能损耗。

    另外,如果集群中存在上万的Service/Endpoint,那么Node上的iptables rules将会非常庞大,性能还会再打折扣。

    ipvs:

    客户端IP请求时到达内核空间时,根据ipvs的规则直接分发到各pod上。kube-proxy会监视Kubernetes Service对象和Endpoints,调用netlink接口以相应地创建ipvs规则并定期与Kubernetes Service对象和Endpoints对象同步ipvs规则,

    以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。

    Service类型

    • ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType
    • NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。
    • LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。
    • ExternalName:通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容(例如, foo.bar.example.com)。 没有任何类型代理被创建,这只有 Kubernetes 1.7 或更高版本的 kube-dns 才支持
    •  无 selector 的Services  (需要手工配置Endpoints)
    • 无 ClusterIP的Service (headless service)

    第二部分: 案例

    1)创建clusterIP类型的service

    #定义deployment和svc
    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
       type: ClusterIP
       ports:
       - port: 6380
         targetPort: 6379
    
    #kubectl apply -f redis-svc.yaml
    验证
    [root@master01 mainfest]# kubectl get pods
    NAME READY STATUS RESTARTS AGE
    redis-85b846ff9c-x2f48 1/1 Running 0 35s
    [root@master01 mainfest]# kubectl get svc
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    redis ClusterIP 10.20.227.191 <none> 6380/TCP 38s
    [root@master01 mainfest]# redis-cli -h 10.20.227.191 -p 6380
    10.20.227.191:6380> keys *
    (empty list or set)
    10.20.227.191:6380> set name aaa
    OK
    

      

    2)创建NodePort类型的Service

    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
      type: NodePort
      ports:
      - port: 80
        targetPort: 80
        nodePort: 31180
    
    #kubectl apply -f myapp-svc.yaml
    验证
    [root@master01 mainfest]# kubectl get pods
    NAME READY STATUS RESTARTS AGE
    myapp-deploy-65df64765c-27gj6 1/1 Running 0 23s
    myapp-deploy-65df64765c-2wv2t 1/1 Running 0 23s
    myapp-deploy-65df64765c-9nmwb 1/1 Running 0 23s
    [root@master01 mainfest]# kubectl get svc
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    kubernetes ClusterIP 10.20.0.1 <none> 443/TCP 4d14h
    myapp NodePort 10.20.44.7 <none> 80:31180/TCP 31s
    
    #打补丁修改sessionAffinity为clientip;实现会话连接
    [root@master01 mainfest]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
    service/myapp patched
    
    [root@master01 mainfest]# 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":{"ports":[{"nodePort":31180,...
    Selector: app=myapp,release=canary
    Type: NodePort
    IP: 10.20.44.7
    Port: <unset> 80/TCP
    TargetPort: 80/TCP
    NodePort: <unset> 31180/TCP
    Endpoints: 172.31.219.219:80,172.31.67.144:80,172.31.67.145:80
    Session Affinity: ClientIP
    External Traffic Policy: Cluster
    Events: <none>
    [root@master01 mainfest]# while true;do curl 192.168.10.211:31180/hostname.html;sleep 1;done
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-2wv2t
    [root@master01 mainfest]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
    service/myapp patched
    [root@master01 mainfest]# while true;do curl 192.168.10.211:31180/hostname.html;sleep 1;done
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-9nmwb
    myapp-deploy-65df64765c-27gj6
    myapp-deploy-65df64765c-9nmwb
    myapp-deploy-65df64765c-2wv2t
    myapp-deploy-65df64765c-9nmwb
    

      

    3)创建无头service(headless)

    apiVersion: v1
    kind: Service
    metadata:
      name: myapp-svc
      namespace: default
    spec:
      selector:
        app: myapp
        release: canary
      clusterIP: None
      ports:
      - port: 80
        targetPort: 80
    
    返回后端所有pod的地址
    [root@master01 mainfest]# dig -t A myapp-svc.default.svc.ziioffice.com. @10.20.254.254
    ; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -t A myapp-svc.default.svc.ziioffice.com. @10.20.254.254
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6273
    ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
    ;; QUESTION SECTION:
    ;myapp-svc.default.svc.ziioffice.com. IN A
    ;; ANSWER SECTION:
    myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.67.146
    myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.219.220
    myapp-svc.default.svc.ziioffice.com. 5 IN A 172.31.67.147
    

     

    4)没有selector的service(指定外部)
    Service抽象了该如何访问Kubernetes Pod,但也能抽象其他类型的backend,例如:

    希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。
    希望服务指向另一个Namespace中或其他集群中的服务。

    apiVersion: v1
    kind: Endpoints
    metadata:
      name: mysql-service
      namespace: default
    subsets:
      - addresses:
        - ip: 192.168.10.204
        ports:
        - port: 3306
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: mysql-service
      namespace: default
    spec:
      ports:
      - protocol: TCP
        port: 3336
        targetPort: 3306
                        
    
    
    #测试pod内部,通过service,访问外部的数据库
    [root@web-55fff97c7-gsrl5 /]# mysql -h mysql-service.default.svc.ziioffice.com -u aa -p -P 3336
    Enter password:
    Welcome to the MySQL monitor. Commands end with ; or g.
    Your MySQL connection id is 249
    Server version: 5.6.40 MySQL Community Server (GPL)
    Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    mysql>
    

     

    apiVersion: v1
    kind: Endpoints
    metadata:
      name: redis-service
      namespace: default
    subsets:
      - addresses:
        - ip: 192.168.10.204
        ports:
        - port: 6379
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: redis-service
    spec:
      ports:
       - port: 6380
         targetPort: 6379
    
    
    #kubectl apply -f redis-svc.yaml
    
    [root@web-55fff97c7-7mdf9 /]# redis-cli -h redis-service.default.svc.ziioffice.com -p 6380
    redis-service.default.svc.ziioffice.com:6380>
    

      

    5) externalname

    引入rds数据库到集群内部

    apiVersion: v1
    kind: Service
    metadata:
      name: prod-mysql-service
      namespace: default
    spec:
      type: ExternalName
      externalName: rm-uf665jsp7111111.mysql.rds.aliyuncs.com
    
    测试:
    [root@master03-171 mainfest]# kubectl get svc
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    prod-mysql-service ExternalName <none> rm-uf665jsp7vwk4lz83.mysql.rds.aliyuncs.com <none> 20m
    
    [root@master03-171 mainfest]# kubectl exec -it pod test-centos-6979f6bc4c-clbz7 -- /bin/bash
    [root@test-centos-6979f6bc4c-clbz7 /]# yum -y install mysql
    [root@test-centos-6979f6bc4c-clbz7 /]# mysql -h prod-mysql-service.default.svc.ziioffice.com -u xionghh -p
    Enter password:
    Welcome to the MySQL monitor. Commands end with ; or g.
    Your MySQL connection id is 60
    Server version: 5.7.26-log Source distribution
    Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
    mysql>
    

    连接阿里云redis

    apiVersion: v1
    kind: Service
    metadata:
       name: prod-redis-service
       namespace: default
    spec:
      type: ExternalName
      externalName: r-uf6d6wb8111111.redis.rds.aliyuncs.com
    
    验证:
    [root@master03-171 mainfest]# kubectl describe svc prod-redis-service
    Name: prod-redis-service
    Namespace: default
    Labels: <none>
    Annotations: kubectl.kubernetes.io/last-applied-configuration:
    {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"prod-redis-service","namespace":"default"},"spec":{"externalName"...
    Selector: <none>
    Type: ExternalName
    IP:
    External Name: r-uf6d6wb8wj63ru7vtm.redis.rds.aliyuncs.com
    Session Affinity: None
    Events: <none>
    [root@test-centos-6979f6bc4c-clbz7 /]# redis-cli -h prod-redis-service.default.svc.ziioffice.com -p 6379 prod-redis-service.default.svc.ziioffice.com:6379> keys * (error) NOAUTH Authentication required.

      

     连接mongodb服务

    apiVersion: v1
    kind: Service
    metadata:
      name: prod-mongodb-service
      namespace: defalut
    spec:
      type: ExternalName
      externalName: dds-uf618b111111.mongodb.rds.aliyuncs.com
    

      

  • 相关阅读:
    LeetCode:25 K个一组翻转链表
    LeetCode:3 无重复字符的最长子串(双指针)
    Java——参数问题与final实例域
    Java——对象的构造
    配置远程服务器 安装iis 远程服务器网络无法连接
    未能找到元数据文件
    ef 设计model 标签
    visualsvn for vs2017 初始化错误
    resharper 2018.2.3破解
    C# winform 自定义函数中找不到Form中的控件和定义的全局变量
  • 原文地址:https://www.cnblogs.com/louis2008/p/kubernetes-service.html
Copyright © 2011-2022 走看看