Opensourcetechブログ

OpensourcetechによるNGINX/Kubernetes/Zabbix/Neo4j/Linuxなどオープンソース技術に関するブログです。

kubernetesにおけるPodへの負荷分散状況の確認(Service/Deployment経由)


LinuCエヴァンジェリストの鯨井貴博@opensourcetechです。


はじめに
今回は、kubernetesでPod(コンテナ)へのアクセスってどのような分散がされるのか確認してみます。

具体的には、こんな環境で実施します。



環境構築
まず、以下の記事を参考に"Deployment1"と"Deployment2"を作成します。
nginxコンテナ(Pod)のコンテンツ(index.html)をConfigMapで提供・更新する(kubernetes)
https://www.opensourcetech.tokyo/?page=1679832639

kubeuser@master01:~/variable_deploy$ kubectl get deployments
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
nginx    2/2     2            2           3d
nginx2   1/1     1            1           3d
kubeuser@master01:~/variable_deploy$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6cbc9bb4f5-jm8mr   1/1     Running   0          2d8h
nginx-6cbc9bb4f5-pfhfz   1/1     Running   0          3d
nginx2-f96cfc57b-vnsfm   1/1     Running   0          3d


以下に使ったyamlファイルやindex.htmlを格納しています。
https://github.com/kujiraitakahiro/kubernetes/tree/master/kanarya_release

そして、Serviceを使ってクライアントがアクセスするIPアドレス&ポート番号を作成します。

kubeuser@master01:~/variable_deploy$ kubectl expose deployment nginx --port=80 --type=LoadBalancer

kubeuser@master01:~/variable_deploy$ kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
kubernetes   ClusterIP      10.1.0.1      <none>         443/TCP        11d
nginx        LoadBalancer   10.1.55.116   192.168.1.51   80:30267/TCP   3d



負荷分散状況の測定
まず、クライアント(Webブラウザ)からアクセスできるかの確認。
大丈夫ですね!
※F5(再読み込み)を実施すると、Version1/Version2いずれかのコンテンツが表示されます。



では、分散状況のチェック。
Apache Benchを使って1,000アクセスしてみます。
※今回は、windowsでXAMPPを使っています。

c:\xampp\apache\bin>ab.exe -n 1000 -c 1000 http://192.168.1.51/
This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.1.51 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.23.0
Server Hostname:        192.168.1.51
Server Port:            80

Document Path:          /
Document Length:        256 bytes

Concurrency Level:      1000
Time taken for tests:   3.817 seconds
Complete requests:      1000
Failed requests:        325
   (Connect: 0, Receive: 0, Length: 325, Exceptions: 0)
Total transferred:      489325 bytes
HTML transferred:       256325 bytes
Requests per second:    261.97 [#/sec] (mean)
Time per request:       3817.165 [ms] (mean)
Time per request:       3.817 [ms] (mean, across all concurrent requests)
Transfer rate:          125.19 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        1    3   2.5      3      44
Processing:   217 1931 968.8   1935    3618
Waiting:        5 1831 1015.0   1841    3588
Total:        222 1934 968.7   1938    3620

Percentage of the requests served within a certain time (ms)
  50%   1938
  66%   2456
  75%   2723
  80%   2927
  90%   3290
  95%   3452
  98%   3553
  99%   3582
 100%   3620 (longest request)


アクセス状況はwiresharkを使います。
1,000アクセスに対して、200OKが返されています。


では、そのうちVersion2のコンテンツはどれくらい表示されるのか確認します。
すると、325回であることが分かります。


「均等にならないものなの?」という疑問が沸いたので、何度か試してみました。
結果は、339回・306回・353回・ 342回。
きっちりではないですが、だいたい均等に分散していま https://kubernetes.io/ja/docs/concepts/services-networking/service/#proxy-mode-iptablesすね。


おわりに
実施する前はきれいに分散するのかなと思っていたのですが、
実際にはだいたい均等でした。

なんとなくリソースの負荷見ながら(least-connection) 均等分散(round-robin)しているのかなというように見えるのですが、合ってるんだろうか。。。
もうちょっと調べてみよう。


追記
Serviceのトラフィック分散について、追記。
kube-proxyが関連しており、ipvsモード・iptablesモードがあるが、
デフォルトは後者(iptablesモード)。
https://kubernetes.io/ja/docs/concepts/services-networking/service/#proxy-mode-iptables

kube-proxyの設定(configmap)のmode ""のデフォルトがiptablesモード、
ipvsとすればipvsモードとなる。
また、ipvsモードだと、scheduler:でrr(ラウンドロビン)など選択可能。

kubeuser@master01:~$ kubectl get cm -n kube-system
NAME                                 DATA   AGE
calico-config                        4      12d
coredns                              1      12d
extension-apiserver-authentication   6      12d
kube-proxy                           2      12d
kube-root-ca.crt                     1      12d
kubeadm-config                       1      12d
kubelet-config                       1      12d
kubeuser@master01:~$ kubectl get cm -n kube-system kube-proxy -o yaml
apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    bindAddressHardFail: false
    clientConnection:
      acceptContentTypes: ""
      burst: 0
      contentType: ""
      kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
      qps: 0
    clusterCIDR: 10.0.0.0/16,fd12:b5e0:383e::/64
    configSyncPeriod: 0s
    conntrack:
      maxPerCore: null
      min: null
      tcpCloseWaitTimeout: null
      tcpEstablishedTimeout: null
    detectLocal:
      bridgeInterface: ""
      interfaceNamePrefix: ""
    detectLocalMode: ""
    enableProfiling: false
    healthzBindAddress: ""
    hostnameOverride: ""
    iptables:
      localhostNodePorts: null
      masqueradeAll: false
      masqueradeBit: null
      minSyncPeriod: 0s
      syncPeriod: 0s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      strictARP: false
      syncPeriod: 0s
      tcpFinTimeout: 0s
      tcpTimeout: 0s
      udpTimeout: 0s
    kind: KubeProxyConfiguration
    metricsBindAddress: ""
    mode: ""
    nodePortAddresses: null
    oomScoreAdj: null
    portRange: ""
    showHiddenMetricsForVersion: ""
    winkernel:
      enableDSR: false
      forwardHealthCheckVip: false
      networkName: ""
      rootHnsEndpointName: ""
      sourceVip: ""
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://master01:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
  annotations:
    kubeadm.kubernetes.io/component-config.hash: sha256:e1193cefc1046d8fe6dbffed62d04e546bd4142781cc28f632adfe72f499e4be
  creationTimestamp: "2023-03-14T13:45:56Z"
  labels:
    app: kube-proxy
  name: kube-proxy
  namespace: kube-system
  resourceVersion: "271"
  uid: 687e9c38-9699-46dc-9fbb-5de6bf270781


kube-proxyの設定について
https://kubernetes.io/docs/reference/config-api/kube-proxy-config.v1alpha1/#kubeproxy-config-k8s-io-v1alpha1-ProxyMode

ipvsモードのDeep Dive
https://kubernetes.io/docs/reference/config-api/kube-proxy-config.v1alpha1/#kubeproxy-config-k8s-io-v1alpha1-ProxyMode

Opensourcetech by Takahiro Kujirai