Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@silverbirder

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

More than 1 year has passed since last update.

ストーリー

  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

Kubernetes_learning-Page-2 (1).png

このような状況下で、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がどのように動いているのか知りたいと思います。
次回は、こちらです。

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

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
silverbirder
EC site programmer. Love node.js. Fx trader. twitter: @silver_birder

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?