IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    K8S Service 多种类型 Types 测试手记

    nieyong发表于 2023-09-13 02:13:00
    love 0

    前言

    这里基于whoami示范服务,部署3个实例,分别一一验证各种类型的K8S Service服务范畴。

    大致逐一从下面列表逐一验证每种类型的Service访问方式:

    • Service Name
    • 域名解析结果等
    • CLUSTER-IP
    • EXTERNAL-IP

    一些设定如下:

    • 测试环境K8S版本号为v1.27.3
    • K8S集群Node节点IP地址段范围:10.0.1.0/24
    • K8S集群自动生成Pod网段为10.43.0.0/24
    • 本书所列代码皆可拷贝直接粘贴到终端界面直接运行

    首先,部署whoami服务

    先部署包含3个实例的whoami:

    # cat << 'EOF' | kubectl apply -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: whoami
      labels:
        app: whoami
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: whoami
      template:
        metadata:
          labels:
            app: whoami
        spec:
          containers:
          - name: whoami
            image: containous/whoami
            ports:
            - containerPort: 80
              name: web
    EOF
    

    查看一下:

    # kubectl get all
    NAME                                                      READY   STATUS      RESTARTS         AGE
    pod/whoami-767d459f67-qffqw                               1/1     Running     0                23m
    pod/whoami-767d459f67-xdv9p                               1/1     Running     0                23m
    pod/whoami-767d459f67-gwpgx                               1/1     Running     0                23m
    
    NAME                                                  READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/whoami                                3/3     3            3           23m
    
    NAME                                                            DESIRED   CURRENT   READY   AGE
    replicaset.apps/whoami-767d459f67                               3         3         3       23m
    

    其次,安装busybox进行调试

    安装一个包含有curl的busybox方便后续调试:

    kubectl run busybox-curl --image=yauritux/busybox-curl --command -- sleep 3600
    

    另起一个终端,输入下面命令进入:

    kubectl exec -ti busybox-curl -n default -- sh
    

    环境准备好之后,下面逐一测试各种类型:

    默认Cluster IP模式

    K8S默认Service为Cluster IP模式,面向内部Pod以及通过Ingress对外提供服务。

    下面一张图很清晰解释清楚了Port和TargetPort适用情景,Port为Service对外输出的端口,TargetPort为服务后端Pod的端口,两者之间有一个转换:port -> targetPort -> containerPort。

    创建一个Service:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-clusterip
      name: whoami-clusterip
    spec:
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: whoami
    EOF
    

    部署后可以查看一下:

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-clusterip      ClusterIP      10.43.247.74    <none>        80/TCP         57s
    

    下面就需要逐一测试了。

    域名形式:

    # curl whoami-clusterip
    Hostname: whoami-767d459f67-gwpgx
    IP: 127.0.0.1
    IP: 10.42.8.35
    RemoteAddr: 10.42.9.32:35968
    GET / HTTP/1.1
    Host: whoami-clusterip
    User-Agent: curl/7.81.0
    Accept: */*
    

    Cluster IP形式:

    # curl 10.43.247.74
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.73
    RemoteAddr: 10.42.9.32:42398
    GET / HTTP/1.1
    Host: 10.43.247.74
    User-Agent: curl/7.81.0
    Accept: */*
    

    域名解析,只解析到Cluster IP上:

    # nslookup whoami-clusterip
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    Name:	whoami-clusterip.default.svc.cluster.local
    Address: 10.43.247.74
    

    External IP模式

    原理同Cluster IP模式,为指定服务绑定一个额外的一个IP地址。当终端访问该IP地址,将流量一样转发到Service。

    当访问external IP,其端口转换过程:port -> targetPort -> containerPort。

    与默认Service相比,端口转换流程没有增加,但好处对外暴露了一个可访问的IP地址,不过可能需要在交换机/路由器层面提供动静态路由支持。

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-externalip
      name: whoami-externalip
    spec:
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: whoami
      externalIPs:
      - 10.10.10.10
    EOF
    

    服务显示如下,绑定了指定的扩展IP地址10.10.10.10。

    # NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-externalip     ClusterIP      10.43.192.118   10.10.10.10   80/TCP         57s
    

    kube-proxy 将在每一个Node节点为10.10.10.10上建立一个转发规则,该IP地址的80端口将直接转发到对应的后端三个whoami Pod 上。

    -A KUBE-SERVICES -d 10.10.10.10/32 -p tcp -m comment --comment "default/whoami-externalip external IP" -m tcp --dport 80 -j KUBE-EXT-QN5HIEVYUPDP6UNK
    
    ......
    -A KUBE-EXT-QN5HIEVYUPDP6UNK -j KUBE-SVC-QN5HIEVYUPDP6UNK
    ......
    
    -A KUBE-SVC-QN5HIEVYUPDP6UNK ! -s 10.42.0.0/16 -d 10.43.192.118/32 -p tcp -m comment --comment "default/whoami-externalip cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
    -A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.2.79:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-JSAT6D2KFCSF4YLF
    -A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.3.77:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-2R66UI3G2AY2IMNM
    -A KUBE-SVC-QN5HIEVYUPDP6UNK -m comment --comment "default/whoami-externalip -> 10.42.8.42:80" -j KUBE-SEP-ZHHIL2SAN2G37GCM
    

    访问域名:

    # curl whoami-externalip
    Hostname: whoami-767d459f67-gwpgx
    IP: 127.0.0.1
    IP: 10.42.8.35
    RemoteAddr: 10.42.9.32:46746
    GET / HTTP/1.1
    Host: whoami-externalip
    User-Agent: curl/7.81.0
    Accept: */*
    

    访问ClusterIP形式:

    # curl 10.43.192.118
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.73
    RemoteAddr: 10.42.9.32:47516
    GET / HTTP/1.1
    Host: 10.43.192.118
    User-Agent: curl/7.81.0
    Accept: */*
    

    访问暴露的External IP:

    # curl 10.10.10.10
    Hostname: whoami-767d459f67-gwpgx
    IP: 127.0.0.1
    IP: 10.42.8.35
    RemoteAddr: 10.42.9.0:38477
    GET / HTTP/1.1
    Host: 10.10.10.10
    User-Agent: curl/7.81.0
    Accept: */*
    

    域名解析结果只解析到其对应的Cluster IP:

    # nslookup whoami-externalip
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    Name:	whoami-externalip.default.svc.cluster.local
    Address: 10.43.192.118
    

    NodePort 模式

    与Cluster IP相比,多了一个nodePort,这个NodePort会在K8S所有Node节点上都会开放。

    这里有一个端口转换过程:nodePort -> port -> targetPort -> containerPort,多了一层数据转换过程。

    服务定义如下:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-nodeport
      name: whoami-nodeport
    spec:
      type: NodePort
      ports:
      - port: 80
        targetPort: 80
        nodePort: 30080
        protocol: TCP
      selector:
        app: whoami
    EOF
    

    查看一下服务分配地址:

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-nodeport       NodePort       10.43.215.233   <none>        80:30080/TCP   57s
    

    访问域名:

    # curl whoami-nodeport
    Hostname: whoami-767d459f67-xdv9p
    IP: 127.0.0.1
    IP: 10.42.2.75
    RemoteAddr: 10.42.9.32:36878
    GET / HTTP/1.1
    Host: whoami-nodeport
    User-Agent: curl/7.81.0
    Accept: */*
    

    测试 CLUSTER IP :

    # curl 10.43.215.233
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.73
    RemoteAddr: 10.42.9.32:40552
    GET / HTTP/1.1
    Host: 10.43.215.233
    User-Agent: curl/7.81.0
    Accept: */*
    

    因为是在每一个K8S Node节点上都会开放一个30080端口,因此可以这样访问 {Node IP}:{nodePort},如下Node IP地址为10.0.1.11

    # curl 10.0.1.11:30080
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.73
    RemoteAddr: 10.42.1.0:1880
    GET / HTTP/1.1
    Host: 10.0.1.11:30080
    User-Agent: curl/7.81.0
    Accept: */*
    

    域名还是只解析到对应Cluster IP:

    # nslookup whoami-nodeport
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    Name:	whoami-nodeport.default.svc.cluster.local
    Address: 10.43.215.233
    

    LoadBalancer 模式

    LoadBalancer模式,会强制K8S Service自动开启nodePort。

    这里有一张图,详细解析数据流向。

    服务数据端口转换过程:port -> nodePort -> port -> targetPort -> containerPort:

    • 与默认Cluster IP相比,多了两层数据转换过程
    • 与nodePort相比,对了一层数据转换过程
    • 与externalIP相比,在小流量场景下就没有什么优势了

    具体服务定义:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-clusterip-none
      name: whoami-clusterip-none
    spec:
      clusterIP: None
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: whoami
    EOF
    

    查看一下部署结果:

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-loadbalancer   LoadBalancer   10.43.63.92     <pending>     80:30906/TCP   57s
    

    服务域名形式:

    # curl whoami-loadbalancer
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.73
    RemoteAddr: 10.42.9.32:57844
    GET / HTTP/1.1
    Host: whoami-loadbalancer
    User-Agent: curl/7.81.0
    Accept: */*
    

    测试 CLUSTER-IP

    # curl 10.43.63.92
    Hostname: whoami-767d459f67-xdv9p
    IP: 127.0.0.1
    IP: 10.42.2.75
    RemoteAddr: 10.42.9.32:42400
    GET / HTTP/1.1
    Host: 10.43.63.92
    User-Agent: curl/7.81.0
    Accept: */*
    

    域名解析到Cluster IP:

    #  nslookup whoami-loadbalancer
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    Name:	whoami-loadbalancer.default.svc.cluster.local
    Address: 10.43.63.92
    

    安装LoadBalancer

    此时whoami-loadbalancer服务对应的EXTERNAL-IP 为 <pending>,我们需要安装一个负载均衡器,可以选择MetalLB作为负载均衡器。

    # kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.11/config/manifests/metallb-native.yaml
    

    稍后分配可用的LoadBalaner可分配的地址池:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: metallb.io/v1beta1
    kind: IPAddressPool
    metadata:
      name: default-pool
      namespace: metallb-system
    spec:
      addresses:
      - 10.0.1.100-10.0.1.200
    ---
    apiVersion: metallb.io/v1beta1
    kind: L2Advertisement
    metadata:
      name: default
      namespace: metallb-system
    spec:
      ipAddressPools:
      - default-pool
    EOF
    

    等安装完成之后,可以看到服务whoami-loadbalancer分配的IP地址为 10.0.1.101 :

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    ......
    service/whoami-loadbalancer LoadBalancer   10.43.63.92     10.0.1.101         80:30906/TCP   27h
    ......
    

    测试负载均衡IP地址

    测试一下:

    # curl 10.0.1.101
    Hostname: whoami-767d459f67-xdv9p
    IP: 127.0.0.1
    IP: 10.42.2.78
    RemoteAddr: 10.42.8.0:33658
    GET / HTTP/1.1
    Host: 10.0.1.101
    User-Agent: curl/7.79.1
    Accept: */*
    

    我们看到该服务分配的端口为80:30906/TCP,30906为K8S为该服务自动生成的NodePort类型端口。

    可以找任一K8S Node节点IP地址测试一下:

    # curl 10.0.1.12:30906
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.77
    RemoteAddr: 10.42.2.0:9717
    GET / HTTP/1.1
    Host: 10.0.1.12:30906
    User-Agent: curl/7.81.0
    Accept: */*
    

    分析一下路由表,可以分析到该负载均衡的External_IP:80的打流量到NodePort:30906上,然后走Service对应{Pod:80}流量分发逻辑。

    -A KUBE-NODEPORTS -p tcp -m comment --comment "default/whoami-loadbalancer" -m tcp --dport 30906 -j KUBE-EXT-NBTYBEEXACZI7DPC
    
    ......
    
    -A KUBE-SERVICES -d 10.0.1.101/32 -p tcp -m comment --comment "default/whoami-loadbalancer loadbalancer IP" -m tcp --dport 80 -j KUBE-EXT-NBTYBEEXACZI7DPC
    
    ......
    
    -A KUBE-EXT-NBTYBEEXACZI7DPC -m comment --comment "masquerade traffic for default/whoami-loadbalancer external destinations" -j KUBE-MARK-MASQ
    -A KUBE-EXT-NBTYBEEXACZI7DPC -j KUBE-SVC-NBTYBEEXACZI7DPC
    
    ......
    
    -A KUBE-SVC-NBTYBEEXACZI7DPC ! -s 10.42.0.0/16 -d 10.43.63.92/32 -p tcp -m comment --comment "default/whoami-loadbalancer cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
    -A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.2.79:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-E3K3SUYNFWT2VICE
    -A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.3.77:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-HG5MYVVID7GJOZA7
    -A KUBE-SVC-NBTYBEEXACZI7DPC -m comment --comment "default/whoami-loadbalancer -> 10.42.8.42:80" -j KUBE-SEP-GFJH72YCBKBFB6OG
    

    Headless 无头模式

    一般应用在有状态的服务,或需要终端调用者自己实现负载均衡,等一些特定场景。

    通过调用者从端口角度分析,数据转换流程:targetPort -> containerPort。

    在意服务性能的场景,不妨试试无头模式。


    服务定义:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-clusterip-none
      name: whoami-clusterip-none
    spec:
      clusterIP: None
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: whoami
    EOF
    

    查看服务部署情况:

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-clusterip-none   ClusterIP      None            <none>                     80/TCP         9h
    

    通过service域名访问,K8S会自动根据服务域名whoami-clusterip-none进行pick后端对应Pod IP地址。

    # curl whoami-clusterip-none
    Hostname: whoami-767d459f67-xdv9p
    IP: 127.0.0.1
    IP: 10.42.2.75
    RemoteAddr: 10.42.9.32:34998
    GET / HTTP/1.1
    Host: whoami-clusterip-none
    User-Agent: curl/7.81.0
    Accept: */*
    

    查询DNS会把所有节点都列出来。

    # nslookup whoami-clusterip-none
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    Name:	whoami-clusterip-none.default.svc.cluster.local
    Address: 10.42.3.73
    Name:	whoami-clusterip-none.default.svc.cluster.local
    Address: 10.42.2.75
    Name:	whoami-clusterip-none.default.svc.cluster.local
    Address: 10.42.8.35
    

    External Name模式

    用于引进带域名的外部服务,这里引入内部服务作为测试。

    多了一层域名解析过程,端口转换流程依赖于所引入服务的服务设定。

    服务定义:

    cat << 'EOF' | kubectl apply -f -
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        name: whoami-externalname
      name: whoami-externalname
    spec:
      type: ExternalName
      externalName: whoami-clusterip.default.svc.cluster.local
    EOF
    

    这里外联的是whoami-clusterip服务的完整访问域名。

    查看服务部署情况:

    NAME                          TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    service/whoami-externalname     ExternalName   <none>          whoami-clusterip.default   <none>         9h
    

    根据域名访问测试:

    # curl whoami-externalname
    Hostname: whoami-767d459f67-qffqw
    IP: 127.0.0.1
    IP: 10.42.3.77
    RemoteAddr: 10.42.9.35:36756
    GET / HTTP/1.1
    Host: whoami-externalname
    User-Agent: curl/7.81.0
    Accept: */*
    

    DNS解析结果:

    # nslookup whoami-externalname
    Server:		10.43.0.10
    Address:	10.43.0.10:53
    
    whoami-externalname.default.svc.cluster.local	canonical name = whoami-clusterip.default.svc.cluster.local
    Name:	whoami-clusterip.default.svc.cluster.local
    Address: 10.43.247.74
    

    小结

    简要分析了各种类型Service定义、服务引用场景以及测试流程等,整理清楚了,也方便在具体业务场景中进行抉择选择具体服务类型。



    nieyong 2023-09-13 10:13 发表评论


沪ICP备19023445号-2号
友情链接