<

一足遅れて Kubernetes を学び始める - 08. discovery&LB その1 -

ストーリー

  1. 一足遅れて Kubernetes を学び始める - 01. 環境選択編 -
  2. 一足遅れて Kubernetes を学び始める - 02. Docker For Mac -
  3. 一足遅れて Kubernetes を学び始める - 03. Raspberry Pi -
  4. 一足遅れて Kubernetes を学び始める - 04. kubectl -
  5. 一足遅れて Kubernetes を学び始める - 05. workloads その 1 -
  6. 一足遅れて Kubernetes を学び始める - 06. workloads その 2 -
  7. 一足遅れて Kubernetes を学び始める - 07. workloads その 3 -
  8. 一足遅れて Kubernetes を学び始める - 08. discovery&LB その 1 -
  9. 一足遅れて Kubernetes を学び始める - 09. discovery&LB その 2 -
  10. 一足遅れて Kubernetes を学び始める - 10. config&storage その 1 -
  11. 一足遅れて Kubernetes を学び始める - 11. config&storage その 2 -
  12. 一足遅れて Kubernetes を学び始める - 12. リソース制限 -
  13. 一足遅れて Kubernetes を学び始める - 13. ヘルスチェックとコンテナライフサイクル -
  14. 一足遅れて Kubernetes を学び始める - 14. スケジューリング -
  15. 一足遅れて Kubernetes を学び始める - 15. セキュリティ -
  16. 一足遅れて Kubernetes を学び始める - 16. コンポーネント -

前回

一足遅れて Kubernetes を学び始める - 07. workloads その 3 -でようやく workloads が終了しました。今回は、discovery&LB を進めようと思います。

discovery&LB

Kubernetes には、下記のようにリソースの種類が存在します。 今回は、discovery&LB を学習します。

リソースの分類内容
Workloads リソースコンテナの実行に関するリソース
Discovery&LB リソースコンテナを外部公開するようなエンドポイントを提供するリソース
Config&Storage リソース設定・機密情報・永続化ボリュームなどに関するリソース
Cluster リソースセキュリティやクォータなどに関するリソース
Metadata リソースリソースを操作する系統のリソース

Kubernetes の Workloads リソース(その 1)

discovery&LB をには、下記 8 つの種類があります。

  • Service
    • ClusterIP
    • ExternalIP
    • NodePort
    • LoadBalancer
    • Headless (None)
    • ExternalName
    • None-Selector
  • Ingress

Service の概要について学びます。

Kubernetes とネットワーク

Kubernetes では、Pod 毎に IP アドレスが割り振られています。 そのため、異なる Pod 間で通信する際は、Pod の IP アドレスが必要になります。逆に同一の Pod 内なら localhost で通信できます。

説明するために、準備します。

# sample-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample-app
  template:
    metadata:
      labels:
        app: sample-app
    spec:
      containers:
        - name: nginx-container
          image: nginx:1.12
          ports:
            - containerPort: 80
        - name: redis-container
          image: redis:3.2
pi@raspi001:~/tmp $ k apply -f sample-deployment.yaml
pi@raspi001:~/tmp $ k get pods -l app=sample-app -o custom-columns="NAME:{metadata.name}, IP:{status.podIP},NODE:{spec.nodeName}"
NAME                                 IP           NODE
sample-deployment-9dc487867-h7lww   10.244.1.72   raspi002
sample-deployment-9dc487867-n8x5w   10.244.2.66   raspi003
sample-deployment-9dc487867-nxbxc   10.244.2.67   raspi003
pod ip adress
pod ip adress

このような状況下で、sample-deployment-9dc487867-n8x5w:redisを中心に見ていきます。

※ nginx は 80 ポートで開放されています。

前準備

pi@raspi001:~/tmp $ k exec -it sample-deployment-9dc487867-n8x5w -c redis-container /bin/bash
root@sample-deployment-9dc487867-n8x5w:/data# apt-get update && apt-get install curl -y
root@sample-deployment-9dc487867-n8x5w:/data# exit

curl がないのでインストールします。

同一 Node,同一 Pod 内のコンテナへ通信

pi@raspi001:~/tmp $ k exec -it sample-deployment-9dc487867-n8x5w -c redis-container /bin/bash
root@sample-deployment-9dc487867-n8x5w:/data# curl localhost:80
<!DOCTYPE html>
...

OK

同一 Node,異なる Pod のコンテナへ通信

pi@raspi001:~/tmp $ k exec -it sample-deployment-9dc487867-n8x5w -c redis-container /bin/bash
root@sample-deployment-9dc487867-n8x5w:/data# curl 10.244.2.66:80
<!DOCTYPE html>
...
root@sample-deployment-9dc487867-n8x5w:/data# curl 10.244.2.67:80
<!DOCTYPE html>
...

OK

異なる Node,異なる Pod のコンテナへ通信

pi@raspi001:~/tmp $ k exec -it sample-deployment-9dc487867-n8x5w -c redis-container /bin/bash
root@sample-deployment-9dc487867-n8x5w:/data# curl 10.244.1.72:80
<!DOCTYPE html>
...

OK

MasterNode から各 Pod へ通信

pi@raspi001:~/tmp $ curl 10.244.1.72:80
<!DOCTYPE html>
...
pi@raspi001:~/tmp $ curl 10.244.2.66:80
<!DOCTYPE html>
...
pi@raspi001:~/tmp $ curl 10.244.2.67:80
<!DOCTYPE html>
...

OK

ここから分かるように、Pod 内部の通信、Pod 間の通信、さらに Node 間の通信までも、Kubernetes によってネットワークが構築されています。

Service

Service は、下記の2つの大きな機能が存在します。

  • pod 宛トラフィックのロードバランシング
  • サービスディスカバリとクラスタ内 DNS

pod 宛トラフィックのロードバランシング

先程の例で、Pod 間を通信することは可能です。しかし、pod を作り直すたびに IP アドレスが変わってしまうため、 自作すると、少し大変です。そこで、Service の出番です。 サービスは、複数存在する Pod に対して自動的にロードバランスしてくれるのと、合わせて外向けの IP アドレス(ExternalIP)や、内向けの IP アドレス(ClusterIP)も提供してくれます。

さっそく、試してみます。

# sample-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: sample-clusterip
spec:
  type: ClusterIP
  ports:
    - name: "http-port"
      protocol: "TCP"
      port: 8080
      targetPort: 80
  selector:
    app: sample-app

これは、app=sample-appにマッチする Pod に対してロードバランスしてくれます。外から 8080 ポートで待ち受けて、80 ポートでコンテナへ通信します。 spec.type が ClusterIP なので、内向けの IP アドレスが提供されています。

pi@raspi001:~/tmp $ k apply -f sample-clusterip.yaml
pi@raspi001:~/tmp $ k get service sample-clusterip
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
sample-clusterip   ClusterIP   10.111.197.69   <none>        8080/TCP   30s
pi@raspi001:~/tmp $ k describe service sample-clusterip
Name:              sample-clusterip
...
Selector:          app=sample-app
Type:              ClusterIP
IP:                10.111.197.69
Port:              http-port  8080/TCP
TargetPort:        80/TCP
Endpoints:         10.244.1.72:80,10.244.2.66:80,10.244.2.67:80
...

内向けに 10.111.197.69 の IP アドレスが振られました。また、ロードバランスする対象 Pod は、先にあげた Pod の IP アドレスです。 Endpints に:80とあるように、port 毎にサービス(clusterIP)を作ることもできます。(service の spec.ports は配列指定)

アクセスできるのか、試します。 せっかくなので、pod 毎に index.html の内容を変化させましょう。

pi@raspi001:~/tmp $ for PODNAME in `k get pods -l app=sample-app -o jsonpath='{.items[*].metadata.name}'`; do
> k exec -it ${PODNAME} -- cp /etc/hostname /usr/share/nginx/html/index.html;
> done
pi@raspi001:~/tmp $ curl 10.111.197.69:8080
sample-deployment-9dc487867-nxbxc
pi@raspi001:~/tmp $ curl 10.111.197.69:8080
sample-deployment-9dc487867-n8x5w
pi@raspi001:~/tmp $ curl 10.111.197.69:8080
sample-deployment-9dc487867-h7lww

確かに、ロードバランシングによって pod に適度なランダム具合でアクセスできています。 もちろん、外からはアクセスできません。

iMac へ移動

~ $ curl 10.111.197.69:8080
# 返答なし

サービスディスカバリとクラスタ内 DNS

サービスディスカバリとは、「問題においての解決策」を指しています。 Kubernetes における問題とは、動的にサービスが生成され続けていることによるサービスを特定することが難しくなる問題です。 そのサービスディスカバリが、Service にあります。 その方法について下記があります。

  • 環境変数を利用したサービスディスカバリ
    • Pod に IP アドレスや port,protocol が設定されている。
  • DNS A レコードを利用したサービスディスカバリ
    • Kubernetes 内のクラスタ内 DNS によって、ドメイン名によるアクセスができる。(ドメイン名の命名規則に従う)
  • DNS SRV レコードを利用したサービスディスカバリ
    • IP アドレスからドメイン名を取得する逆引きもできる。

dnsPolicy による明示的な設定がない限り、Pod 生成時にクラスタ内 DNS へレコード追加されます。 クラスタ内 DNS で名前解決できなかった場合は、クラスタ外 DNS に問い合わせします。

お片付け

pi@raspi001:~/tmp $ k delete -f sample-deployment.yaml -f sample-clusterip.yaml

最後に

今回は、Service についての概要を学びました。Kubernetes の世界では、自動的にネットワーク構築されているため、特段意識することはありませんでした。 もう少し理解が進めれば、ネットワークがどのように構築されているのか、クラスタ内 DNS がどのように動いているのか知りたいと思います。 次回は、こちらです。

※ お絵かきしてアウトプットすると、理解が深まるのでおすすめです。

役立ったら、☕でサポートしてね!

シェアしよう

関連するタグ