Kubernetes Serviceを利用したクラスタ外部公開
ここではServiceを利用して、クラスタ内部および外部へ公開する方法について説明する。
クラスタ内部から接続する
まずクラスタ内で接続を確認する。クラスタにcurlコンテナが入ったPodを作成し、Shellへ接続したあと、helloworld Podへのcurlアクセスをテストする。
まず、テスト用Podを作成して実行する。
% kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
Pod一覧をIP付きで表示する(-o wideを付ける)。
% kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
helloworld 1/1 Running 0 3m44s 172.17.0.3 minikube <none> <none>
クラスタ内部に入り、curlを実行する。
% kubectl run --image curlimages/curl:latest -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $ curl 172.17.0.3:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
この結果から、curlからhelloworldのIPである172.17.0.3を指定し、ポート8080で開かれているため、curlコンテナからhelloworldコンテナへ接続できたことが分かる。
内部にあることを確認するため、curlコンテナを動作させたまま、別のターミナルを開いてPod一覧をIP付きで表示してみよう。
% kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curl 1/1 Running 0 23s 172.17.0.4 minikube <none> <none>
helloworld 1/1 Running 0 12m 172.17.0.3 minikube <none> <none>
コンテナが同じネットワーク内に存在していることを確認できる。
クラスタ外部から接続する
次にクラスタ外部から接続しようとしても、そのままでは接続できない。これはDockerの場合と同じで、ホストIPとPodのIP範囲が異なるためである。したがってアクセスできるようにするには、Serviceを作成してPodを外部に公開する必要がある。
Serviceは、Podをクラスタ内外へ公開する静的IPアドレスを持つL4ロードバランサを意味する。Pod自体はいつ停止するか分からないため、分配先をServiceとして公開する。
Serviceには3種類あり、それぞれ次のような特徴を持つ。
- ClusterIP Service(クラスタ内接続)
いつ消滅するか分からないPodのIPを抽象化し、静的IPを持つプロキシを置くことで、次の利点がある。- PodへアクセスするときにPodのIPを知る必要がない。
- Podへアクセスするときにロードバランスしてくれる。
- NodePort Service(クラスタ内外接続)
ClusterIPではできなかったクラスタ外部へのPod公開を、Node IPとNodePort経由で可能にできる点が利点である。
ただし、次のような欠点もある。- Node IPを知っている必要がある。
- Node Portを知っている必要がある。
- LoadBalancer Service(クラスタ内外接続)
プロバイダのL4ロードバランサのDNSから、各ノードの特定ポートへRoutingしてPodへアクセスする。
したがって、Node IPおよびNodeポートを知る必要がない。ただし、次のような欠点もある。- 1つのServiceごとに1つのロードバランサが作成されるため高コストになる。
- L4ロードバランサなので、L7のHTTPホストやパスによるLB振り分けはできない。
上記の各Serviceについて内容を確認していこう。
ClusterIP Service
HelloWorld PodをClusterIP Serviceとしてクラスタ内部へ公開し、同じクラスタの別Podからアクセスできることを確認する。
次のように起動中のPodに--type ClusterIPオプションを指定することで、ClusterIPのServiceとして公開できる。
kubectl expose pod [Pod名] --type ClusterIP [Service名]
まず、テスト用Podを作成して実行する。*(既に同じ名前のPodがある場合は、kubectl delete pod helloworldコマンドで削除する。)
% kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
helloworld Podをhelloworld-clusteripというService名で公開する。
% kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip
service/helloworld-clusterip exposed
次のコマンドを使用してService一覧を取得する。
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-clusterip ClusterIP 10.98.60.0 <none> 8080/TCP 25s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
結果の1行目にTypeがClusterIPのServiceが作成されたことを確認できる。
次にcurlコンテナを再度起動し、そのコンテナ内からhelloworld-clusteripを通じてhelloworldへアクセスしてみる。
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
開いたShellでcurlコマンドを使って接続する。
/ $ curl 10.98.60.0:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
接続結果から、helloworldへアクセスできることを確認できる。この結果は、上で説明した「クラスタ内部から接続する」の結果と同じである。
ただし、上で行ったのはcurlコンテナから直接helloworldコンテナへ接続したものであり、今回の実行結果はcurlコンテナからServiceであるhelloworld-clusteripへアクセスし、ロードバランス機能(Podは1つだけ作成しているため特定のPodにはなる)によってServiceがhelloworldへ接続するという流れである。したがって意味が異なるため注意が必要である。
NodePort Service
HelloWorld PodをNodePort Serviceとしてクラスタ内部と外部へ公開し、同じクラスタの別Podからアクセスできることを確認する。
次のように起動中のPodに対して--type NodePortオプションを指定するだけで、NodePortのServiceとして公開できる。
kubectl expose pod [Pod名] --type NodePort [Service名]
helloworld Podをhelloworld-nodeportというService名で公開する。
% kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport
service/helloworld-nodeport exposed
次のコマンドを使用してService一覧を取得する。
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-nodeport NodePort 10.110.238.186 <none> 8080:31942/TCP 38s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
その結果、1行目にTypeがNodePortのServiceが作成されたことを確認できる。
次に、同じクラスタ内から接続できるか確認する。手順はClusterIPの場合と同じである。
まず既存のcurlコンテナを削除し、再作成する。
% kubectl delete pod curl
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
そして、そのコンテナ内からhelloworld-nodeportを通じてhelloworldへアクセスしてみる。
/ $ curl 10.110.238.186:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
その結果、helloworld-nodeportを通じてhelloworldへ接続できることを確認できる。
では次に、クラスタ外部(ローカル環境)から接続できるか確認する。接続にはminikubeのIPが必要なので、次のコマンドを実行してIPを取得する。
% minikube ip
192.168.49.2
このIPに対して、ローカル環境からcurlコマンドを実行して接続してみる。このときポートはPodの31942を指定する。
/ $ curl 192.168.49.2:31942
Hello, world!
Version: 1.0.0
Hostname: helloworld
接続結果から、helloworldへ接続できることを確認できる。
(minikube起動時の設定によってはアクセスできない場合がある。この場合はminikube service --url helloworld-nodeportコマンドを実行し、出力されたURLに対してcurlコマンドを実行する。)
ロードバランサService
HelloWorld PodをLoadBalancer Serviceとしてクラスタ内部と外部へ公開し、同じクラスタの別Podからアクセスできることを確認する。
次のように起動中のPodに--type LoadBalancerオプションを指定することで、LoadBalancerのServiceとして公開できる。
kubectl expose pod [Pod名] --type LoadBalancer [Service名]
helloworld Podをhelloworld-loadbalancerというService名で公開する。
% kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-loadbalancer
service/helloworld-loadbalancer exposed
次のコマンドを使用してService一覧を取得する。
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-loadbalancer LoadBalancer 10.104.176.59 <pending> 8080:30100/TCP 27s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
その結果、1行目にTypeがLoadBalancerのServiceが作成されたことを確認できる。
まず同じクラスタ内からアクセスできるか確認する。手順はClusterIPの場合と同じである。
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
開いたShellでcurlコマンドを使って接続する。
/ $ curl 10.104.176.59:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
接続結果から、helloworld-LoadBalancerを通じてhelloworldへアクセスできることを確認できる。
次にクラスタ外部(ローカル環境)からアクセスできるか確認する。
% minikube service helloworld-loadbalancer --url
http://127.0.0.1:53240
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
コンソールをそのまま開いた状態にし、別のコンソールを開いて次のコマンドで接続を確認する。
% curl http://127.0.0.1:53240
Hello, world!
Version: 1.0.0
Hostname: helloworld
実行すると、helloworldへアクセスできることを確認できる。