えいのうにっき

a-knowの日記です

Kubernetes でのサービスディスカバリ (入門k8s 読書メモ)

入門 Kubernetes の読書メモ、第3弾。

入門 Kubernetes

入門 Kubernetes

Kubernetes でのサービスディスカバリ

Kubernetes は、ノードへの Pod の配置を制御し、Pod が間違いなく起動して動き続けているようにし、必要に応じて別のノードに割り当て直す・負荷に応じて Pod の数を自動的に変更する、など、ダイナミックなシステムである。

このダイナミックな性質により、Kubernetes 上でたくさんのサービスを同時に実行することができるが、同時に、動いているサービスを見つけることが難しくなる。「稼働しているサービスを見つけることが難しくなること」「その解決策」を、サービスディスカバリと呼ぶ。(DNSも伝統的なサービスディスカバリの一種。)

Service オブジェクト

  • Kubernetes オブジェクトのうちのひとつ。名前の付いた Label セレクタを作る仕組み
  • kubectl expose で Service を作成することが可能。
    • kubectl expose することにより、対象(ここでは Deployment)の定義から、「Label セレクタ」と「関連するポート情報」を引用してくる。
$ kubectl expose deployment hoge-prod
$ kubectl get services -o wide
NAME          TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE       SELECTOR
kubernetes    ClusterIP      10.43.xxx.x    <none>          443/TCP        32d       <none>
hoge-prod     LoadBalancer   10.43.xxx.xx   35.230.xx.xxx   80:31000/TCP   32d       app=hoge,env=prod,ver=2
  • さらに Service は、クラスタIPと呼ばれる新しいタイプの仮想IPアドレスを割り当てる。
    • 同じ Label セレクタがつけられたすべてのPodにロードバランスするために使用する、特別なIPアドレス

クラスタIPと Service DNS

  • クラスタIPは仮想IPのため、Service オブジェクトを再作成しない限りは変更されない
  • そのため、DNSアドレスとして使用するのにも適している
  • 同一 Namespace 内において、Service によって識別される Pod に接続する際、Service 名を使ってしまうことができる
$ dig hoge-prod A

;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 45113
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 4

;; QUESTION SECTION:
;hoge-prod.default.svc.cluster.local.     IN  A

;; ANSWER SECTION:
hoge-prod.default.svc.cluster.local.  30  IN  A   10.43.xxx.xx
  • Kubernetes DNS Service は、クラスタIPのDNS名を返す。
    • 完全な DNS 名は hoge-prod.default.svc.cluster.local.10.43.xxx.xx は Service のクラスタIPと一致している。

外部からのアクセスを受け入れる

  • 外部からのアクセスを受け入れる際、Service を拡張する NodePort を使う。
    • クラスタIPに加え、システムがポートを選択する/ユーザーがポートを指定することもできるようになる
    • クラスタ内の各ノードは、そのポートにトラフィックをフォワードできるようになり、それにより、クラスタ内のノードにアクセスさえできれば、Serviceと通信できるようになる
    • NodePort をハードウェア、もしくはソフトウェアのロードバランサと連携させて Service を公開することも可能。
$ kubectl describe service hoge-prod
Name:                     hoge-prod
Namespace:                default
Labels:                   app=hoge-prod
                          env=prod
                          ver=2
Annotations:              <none>
Selector:                 app=hoge-prod,env=prod,ver=2
Type:                     LoadBalancer
IP:                       10.43.xxx.xx
LoadBalancer Ingress:     35.230.xx.xxx
Port:                     <unset>  80/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31000/TCP
Endpoints:                10.40.xx.x:8080,10.40.xx.x:8080,10.40.xx.x:8080 + 1 more...
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

システムが、ポート31000をこの service に割り当てたことがわかる・クラスタ内のどのノードからも、Service へのアクセスにこのポートを使えるようになった。Service に対して送信されたリクエストは、Service で定義されている Pod のどれかにランダムで送られる。

クラウドとの統合

  • クラスタを動かしているクラウドでサポートされており、なおかつクラスタが使用できるよう設定されていれば、LoadBalancer タイプを使用できる(ここまでのコマンド実行結果はすべて LoadBalancer タイプの Service への実行結果)。
    • この機能により、クラウド上に新しいロードバランサが自動的に作成され、そのロードバランサ配下にクラスタ内のノードが入れられる
    • Service を拡張する NodePort の、さらなる拡張と考えてもよいかもしれない?LoadBalancer タイプを使用した場合でも、NodePort を使って通信することにはなる。

その他応用機能など

Endpoints

  • クラスタIPを使わずに Service を使用したい場合に用いる。
  • Kubernetes は、各 Service オブジェクトに対応する Endpoints オブジェクトを作成する
  • Endpoints オブジェクトには、対応する Service オブジェクトの Label セレクタに合致する Pod の IP アドレスが入れられている。
$ kubectl describe endpoints hoge-prod
Name:         hoge-prod
Namespace:    default
Labels:       app=hoge-prod
              env=prod
              ver=2
Annotations:  <none>
Subsets:
  Addresses:          10.40.xx.x,10.40.xx.x,10.40.xx.x,10.40.xx.x
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    <unset>  8080  TCP

Events:  <none>
  • Pod が再作成されるなどして IP アドレスが変わった場合、Endpoints も合わせて変更する必要があるが、Kubernetes API には、オブジェクトを監視し変更があると通知する機能が備わっているため、すぐに反応できる

kube-proxy とクラスタIP

  • クラスタIPは、上述の通り、同じ Label セレクタがつけられたすべてのPodにロードバランスするために使用する、特別なIPアドレス。
    • 言い換えると、Service内の各Endpointsにトラフィックをロードバランスするための仮想IP
  • この仕組みは、クラスタ内の各ノードで動いている kube-proxy コンポーネントが実現している。
    • 新しい Service が作られると、kube-proxy は iptables のルールをホストのカーネルに設定する。これにより、パケットの宛先が Service の Endpoints に書き換えられる。

クラスタIP関連の環境変数

  • 通常、クラスタIPの特定にはDNSサービスを使用すればよいが、起動時に Pod に設定されている環境変数を用いる方法もある。
    • HOGE_PROD_SERVICE_HOST HOGE_PROD_SERVICE_PORT などがある。
  • 問題点としては、リソース(オブジェクト)を作る順番。
    • Service が Pod よりも先に作られる必要がある
    • 大きなアプリケーションを構成する Service をデプロイするときには複雑さが増してしまう