こんにちは、Mashです。
本記事は、近年大注目されているコンテナオーケストレーション技術である Kubernetes について、図解と実機確認例を交えて解説するシリーズとなります。
今回は第5回。
前回までで、Pod/ReplicaSet/Deploymentと、コンテナの展開戦略について学びましたので今回からはK8s環境のネットワーク関連リソースをご紹介します。
- PodのIPアドレスを抽象化するリソース「ClusterIP」を理解する
- Podをクラスタ外に公開するリソース「NodePort」を理解する
※本シリーズはLinuxコマンドやネットワーク、Dockerの基礎知識がある方を前提としています。
それではいきましょう!
環境
私の検証環境はこのようになっています。
- 検証環境はUbuntu Server 20.04 LTSのサーバ1台構成(MasterとNodeを兼任)
- 検証マシンへSSH接続済み
- kubectlコマンドでK8sクラスタを操作
- ノードがインターネットに接続していること
- Kubernetesバージョンは1.19.4
イメージはこのような状態↓です。
Deploymentを展開し、NginxのPod(コンテナ)が3つ起動できており、curlコマンドでNginxのWelcomeページにアクセスできることまでを確認しました。

前述の通りPodが3つ展開できている状態ですが、K8s環境ではPodのIPアドレスはバラバラに割り当てられます。そして、有事の際はPodが再起動されることを前提としたコンセプトとなっています。
この状態では、毎回PodのIPアドレスを確認してアクセスする必要があります。
Serviceリソース
そこで登場してくるのが、 ServiceというK8sリソースです。

Serviceは、K8s環境におけるネットワーク経路を管理するリソースで、PodのIPアドレスを抽象化し、複数Podへの通信を分散したりK8sクラスタの外部へ公開したりします。
今回はよく使うものとしては下記2つをご紹介します。(実際には他にも存在します)
- ClusterIP
- NodePort
ClusterIP
まずはClusterIPからみていきましょう。
ClusterIPとは
ClusterIPはK8sクラスター内からアクセスできるL4ロードバランサーです。
K8s環境においてPodは常に起動・削除を繰り返します。そしてその都度PodのIPアドレスが変わります。
ClusterIPはこの「毎回変わるIPアドレス」を抽象化し、代表IPアドレスを提供します。
ClusterIPマニフェストとロードバランシング
ClusterIPを展開してみます。まずはマニフェストの作成から。
vi nginx-clusterip.yaml
apiVersion: v1 kind: Service metadata: name: nginx-clusterip labels: app: nginx spec: type: ClusterIP ports: - port: 80 targetPort: 80 selector: app: nginx
kind を Serviceに、そして spec の type でClusterIP と指定します。
port はClusterIPの待受ポート、targetPortでPod側の待受ポート(今回はNginxの80番)を指定します。
そして最後に selector で、ClusterIPにのバックエンドとなるPodを指定しています。
Deploymentのマニフェストを見返すと、このようにラベルが付与されています。keyが「app」、valueが「nginx」というラベルが付与されているリソースを探して紐付ける ということを自動的にやってくれています。
これが「サービスディスカバリ」機能です。

それではClusterIPを展開します。
# マニフェストからClusterIPリソースを展開
$ kubectl apply -f nginx-clusterip.yaml
service/nginx created
# 展開したClusterIPリソースのIPアドレスを確認
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.43.228.90 <none> 80/TCP 38s
ClusterIPが展開できたので、ClusterIPアドレスにHTTPリクエストを投げてみましょう。
$ watch -n 1 "curl -s http://10.43.228.90/"

毎回表示されるコンテナ名が変化している、つまりアクセス先のPodが変化していることがわかります。
ClusterIPが3つのPodに対するHTTPリクエストを分散してくれているわけですね!
図示するとこのようなイメージ↓です。今回はノードが1台ですが、複数ノードで構成されていても問題ありません。

NodePort
ClusterIPでPodへの通信分散もできるようになりました。
せっかくNginxPodが起動してるんだから、そろそろPCのWebブラウザでアクセスしてみようと思った方、、、
ざんねんですが、この時点ではまだWebブラウザでNginxへアクセスすることはできません(泣)
なぜかというと、、
さきほどClusterIPのIPアドレスを調べたところ、「10.42.228.90」でした。
そしてわたしのPCのIPアドレスは「10.10.1.1/24」です。
PCとK8sは別のネットワークなので通信ができないんです。(このあたりはTCP/IPネットワークの基礎知識が必要ですが割愛します)
そんなときに登場するのが K8s Serviceリソースの NodePort になります。
NodePortとは
NodePort はClusterIPを機能拡張したリソースで、ノードのIPアドレスをつかってPodへの接続経路をクラスタ外部に公開することができます。もちろんPodへの通信分散もしてくれます。
今回、わたしのPCのWebブラウザから(つまりK8sの外の世界から)Podへのアクセスを実現しようとしているので、NodePortが必要になります。
わたしのPCから検証用ノードはネットワーク接続済みなので、あとはいいかんじにアドレス変換してくれてPodへ到達できるようになります。
NodePortとPodの外部公開
NodePortをためしてみましょう。
$ vi nginx-nodeport.yaml
apiVersion: v1 kind: Service metadata: name: nginx-nodeport labels: app: nginx-nodeport spec: type: NodePort ports: - port: 80 targetPort: 80 selector: app: nginx
さきほど登場したClusterIPのマニフェストとほとんど違いはありません。spec.type の指定がNodePort になっているくらいです。
それでは展開しましょう。
$ kubectl apply -f nginx-nodeport.yaml
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.43.0.1 <none> 443/TCP 5d1h
nginx-clusterip ClusterIP 10.43.202.73 <none> 80/TCP 22h
nginx-nodeport NodePort 10.43.133.51 <none> 80:32704/TCP 22h
NodePortが ポート番号32704 で公開されていることが確認できました。
ちなみに、NodePortリソースで公開されるポート番号はデフォルト状態だと30000~32767のいずれかランダムに割り当てられます。
それではわたしのPCからブラウザでアクセスしてみます。。。!

これまで curl コマンドで確認していた内容がブラウザで確認することができました!
これでNodePortによるK8sクラスタ外へのPod公開は完了です。図示するとこのような状況になります。

まとめ
今回はK8sのネットワークリソース Service のうち、ClusterIPとNodePortをご紹介しました。
デモでご覧いただきませんでしたが、ClusterIPについては例えばWebサーバコンテナからPHPアプリコンテナへの通信分散/冗長化に利用したりもしますので、ぜひマスターしてください。
さて、つづいてもネットワークに関するリソースである Ingress をご紹介します。
IngressはL7ロードバランサーになります。
今回ご紹介したServiceと組み合わせることで、より柔軟なK8sネットワークを構築することができるようになる非常に重要なリソースですので、ぜひ次回をおたのしみに。
今回は以上です。
それじゃあまたね。