【入門編】Kubernetesのサービス公開とルーティング:ClusterIP, NodePort, LoadBalancerの違いとIngress徹底活用 – インフラ構成管理(IaC)活用バイブル

Kubernetesのサービス公開とルーティング:ClusterIP, NodePort, LoadBalancerの違いとIngress徹底活用

やあ、みんな! 今日はKubernetes(k8s)の世界に足を踏み入れたばかりの君たちに、アプリケーションを外部に公開するための超重要トピック、「サービス公開とルーティング」について、僕が現場で培ってきた経験を惜しみなく伝授しようと思う。

「k8sって、コンテナを色々動かせるのはわかったけど、どうやって外からアクセスさせるの?」って疑問、きっと持ってるよね? 実は、k8sにはいくつかサービスを公開する方法があって、それぞれに得意なこと、苦手なことがあるんだ。それを理解しないまま進むと、思わぬところでハマってしまうことも……。

でも、心配しないで! この記事を読み終わる頃には、君も自信を持ってk8sのサービス公開ができるようになるはず。しかも、ただ「動く」だけじゃなくて、「なぜそう動くのか」までしっかり理解できるようになるから、応用力も格段にアップするはずだよ。

この記事では、以下の内容を、まるで隣で一緒に作業しているかのように、優しく丁寧に解説していくね。

1. Kubernetes内部ネットワークの仕組み:これが全ての基本!
2. サービスタイプの違い(ClusterIP / NodePort / LoadBalancer):それぞれの特徴と使い分け
3. Ingressコントローラー(Nginx等)の導入とルーティング設定:本番運用で必須の強力な武器
4. TLS/SSL証明書の導入手順:安全な通信を実現しよう

さあ、君たちのk8sライフが劇的に変わる、このエキサイティングな旅に、早速出発しよう!

—

1. Kubernetes内部ネットワークの仕組み:これが全ての基本!

まず、k8sのサービス公開を理解するには、その内部ネットワークの仕組みを知ることが不可欠なんだ。これは、k8sの「サービス」という概念の根幹に関わる部分だから、じっくりと腰を据えて見ていこう。

コンテナ間の通信:PodのIPアドレス

k8sでは、アプリケーションの最小単位は「Pod」と呼ばれる。そして、各PodにはユニークなIPアドレスが割り当てられるんだ。まるで、それぞれのPodが独立した小さなコンピューターみたいだね。

  • Podは独立したネットワークを持つ: 各Podは、それぞれ独自のIPアドレスを持ち、他のPodとはこのIPアドレスを通じて直接通信できる。
  • PodのIPアドレスは一時的: Podは、再起動やスケールアウト/インによって、IPアドレスが変わることがある。これは、Podが「使い捨て」のコンテナであるというk8sの思想とも合致している。

Pod間の通信を抽象化する「Service」

ここで、登場するのがk8sの「Service」というリソースだ。PodのIPアドレスは変動するから、直接PodのIPアドレスを指定して通信するのは現実的じゃない。そこで、Serviceが「PodのIPアドレスの変動を吸収し、固定されたIPアドレスとDNS名を提供する」という役割を担うんだ。

Serviceは、ラベルセレクターを使って、どのPod群にトラフィックをルーティングするかを定義する。

apiVersion: v1
kind: Service
metadata:
name: my-app-service # Serviceの名前
spec:
selector:
app: my-app # このラベルを持つPodにトラフィックをルーティングする
ports:

  • protocol: TCP

port: 80 # Serviceが公開するポート
targetPort: 8080 # Podがリッスンしているポート

このService定義を見ると、`my-app-service` という名前で、`app: my-app` というラベルを持つPod群に対して、Serviceのポート`80`へのアクセスを、Podのポート`8080`へ転送してくれることがわかるね。

ServiceのIPアドレス:ClusterIP

Serviceにデフォルトで割り当てられるIPアドレスのことを「ClusterIP」と呼ぶ。このClusterIPは、k8sクラスタ内部からのみアクセス可能な、仮想的なIPアドレスなんだ。

  • クラスタ内部専用: ClusterIPは、k8sクラスタの外からは直接アクセスできない。
  • 固定のIPアドレスとDNS名: ClusterIPを持つServiceは、クラスタ内で固定のIPアドレスとDNS名(例: `my-app-service.default.svc.cluster.local`)を持つ。これにより、クラスタ内の他のPodから、常に安定してこのServiceへアクセスできるようになる。

ここまでが、k8s内部ネットワークの基本的な仕組みだ。この「Pod」「Service」「ClusterIP」の関係性をしっかり理解することが、次のステップへの確実な一歩となるよ。

—

2. サービスタイプの違い(ClusterIP / NodePort / LoadBalancer):それぞれの特徴と使い分け

さて、k8s内部の通信の基本がわかったところで、いよいよアプリケーションを「外部」に公開する方法について見ていこう。Serviceには、その公開方法を決定する「Type」という属性があるんだ。ここでは、代表的な3つのTypeを見ていくよ。

1. ClusterIP: クラスタ内部からのアクセスのみ(デフォルト)

これは、先ほども説明した、ServiceのデフォルトのTypeだ。

  • 特徴:
  • クラスタ内部でのみアクセス可能な仮想IPアドレス(ClusterIP)を割り当てる。
  • クラスタ外からは直接アクセスできない。
  • ユースケース:
  • マイクロサービス間の通信(例: フロントエンドからバックエンドAPIへのアクセス)。
  • データベースやキャッシュなど、クラスタ内部で完結するサービス。
  • メリット: セキュリティが高く、クラスタ内部の連携に最適。
  • デメリット: 外部からのアクセスには使えない。

2. NodePort: 各ノードのIPアドレスとポートで公開

NodePortは、k8sクラスタの各ノード(Worker Node)に、指定したポートを公開し、そのポートにアクセスがあった場合に、Serviceへトラフィックを転送するTypeだ。

  • 特徴:
  • k8sクラスタの各ノードのIPアドレスと、指定された「NodePort」(通常30000~32767の範囲)でサービスが公開される。
  • 外部から `[ノードIPアドレス]:[NodePort]` でアクセスできる。
  • 設定例:

apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
type: NodePort # TypeをNodePortに指定
selector:
app: my-app
ports:

  • protocol: TCP

port: 80 # Serviceのポート(クラスタ内部で使われる)
targetPort: 8080 # Podがリッスンしているポート
# nodePort: 30080 # 省略すると自動で割り当てられる

  • ユースケース:
  • 開発環境での手軽な公開。
  • 小規模なサービスで、外部ロードバランサーを導入するほどではない場合。
  • メリット: 外部ロードバランサーなしで、手軽に外部公開できる。
  • デメリット:
  • 各ノードのIPアドレスとNodePortを管理する必要があり、運用が煩雑になる。
  • ノード障害が発生した場合、そのノードにアクセスできなくなる(単一障害点になりやすい)。
  • IPアドレスが長くなりがちで、覚えにくい。
  • ポート番号の範囲が限られている。

3. LoadBalancer: クラウドプロバイダーのロードバランサーを利用

LoadBalancer Typeは、k8sが動作しているクラウド環境(AWS, GCP, Azureなど)のマネージドロードバランサーを利用して、サービスを公開する最も一般的な方法だ。

  • 特徴:
  • クラウドプロバイダーが提供するロードバランサー(例: AWS ELB, GCP Load Balancer)が自動的にプロビジョニングされる。
  • ロードバランサーには、グローバルにアクセス可能なIPアドレスが割り当てられる。
  • ロードバランサーは、クラスタ内の複数のノードにトラフィックを分散してくれる。
  • 設定例:

apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
type: LoadBalancer # TypeをLoadBalancerに指定
selector:
app: my-app
ports:

  • protocol: TCP

port: 80 # Serviceのポート
targetPort: 8080 # Podがリッスンしているポート

  • ユースケース:
  • 本番環境で、可用性の高い外部公開が必要な場合。
  • スケーラブルなサービスを公開したい場合。
  • メリット:
  • クラウドプロバイダーのロードバランサー機能(ヘルスチェック、SSL終端など)を利用できる。
  • 可用性が高く、単一障害点になりにくい。
  • グローバルIPアドレスでアクセスできるため、管理が容易。
  • デメリット:
  • クラウドプロバイダーごとに課金が発生する。
  • プロビジョニングに時間がかかる場合がある。
  • IPアドレスの数が限られる場合がある(特にIPv4)。

どれを選ぶ?:使い分けのポイント

  • クラスタ内部でのみ使うなら: `ClusterIP` (デフォルト)
  • 手軽に試したい、開発環境なら: `NodePort`
  • 本番環境で安定した公開をしたいなら: `LoadBalancer`

しかし、`LoadBalancer` Typeにも、いくつか課題がある。それは、「1つのServiceで1つのロードバランサーがプロビジョニングされる」という点だ。つまり、多数のアプリケーションを公開しようとすると、その数だけロードバランサーが作られ、コストがかさんでしまう可能性があるんだ。

そこで、登場するのが、次の「Ingress」という強力な仕組みなんだ!

—

3. Ingressコントローラー(Nginx等)の導入とルーティング設定:本番運用で必須の強力な武器

「Ingress」は、k8sクラスタへの外部トラフィックを管理するためのAPIリソースだ。Service Typeの`LoadBalancer`が「1 Service = 1 LoadBalancer」だったのに対し、Ingressは「1つのロードバランサーで、複数のServiceへトラフィックをルーティングする」ことを可能にする。まるで、巨大なビルの一つの入り口から、様々なテナント(Service)へ案内してくれるコンシェルジュのような存在だね。

Ingressの仕組み:コントロールプレーンとデータプレーン

Ingressを理解するには、まず「Ingressコントローラー」の存在が重要になる。

  • Ingressリソース: どのホスト名やパスへのアクセスを、どのServiceに転送するか、といったルーティングルールを定義するYAMLファイル。
  • Ingressコントローラー: Ingressリソースの設定を読み取り、実際にトラフィックのルーティングを行うソフトウェア。一般的には、Nginx、HAProxy、Traefikなどが使われる。Ingressコントローラーは、通常、`LoadBalancer` TypeのServiceとしてデプロイされることが多い。

つまり、

1. ユーザーが `example.com/app1` にアクセス。
2. 外部ロードバランサー(IngressコントローラーがデプロイされたService Type)がトラフィックを受け取る。
3. Ingressコントローラーが、Ingressリソースの設定を見て、`example.com/app1` へのアクセスは `app1-service` に転送すべきだと判断。
4. Ingressコントローラーが、`app1-service` にトラフィックを転送。

という流れになる。

Nginx Ingress Controllerの導入

ここでは、最もポピュラーなNginx Ingress Controllerを例に、導入手順を見ていこう。

前提:

  • `kubectl` コマンドが使えること。
  • `k8s` クラスタが構築済みであること。

1. Namespaceの作成:
まず、Ingress Controller用のNamespaceを作成する。

kubectl create namespace ingress-nginx

2. Nginx Ingress Controllerのインストール:
Helm(k8sのパッケージマネージャー)を使うのが一番簡単で一般的だ。Helmがインストールされていない場合は、先にインストールしておこう。

Helmリポジトリの更新
helm repo update

Nginx Ingress Controllerのインストール
helm install ingress-nginx ingress-nginx/ingress-nginx \
–namespace ingress-nginx \
–set controller.replicaCount=2 \ # 冗長化のためレプリカ数を2に
–set controller.nodeSelector.”kubernetes\.io/os”=linux \ # Linuxノードで動かす場合
–set controller.metrics.enabled=true # メトリクスを有効にする場合

インストールが完了すると、`ingress-nginx` NamespaceにPodやServiceが作成される。

インストールされたか確認
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx

`ingress-nginx-controller` という名前のServiceが、`LoadBalancer` Typeで作成されているはずだ。このServiceのExternal IPアドレスが、外部からのアクセスポイントになる。

3. サンプルアプリケーションのデプロイ:
テスト用に、簡単なWebアプリケーションを2つデプロイしてみよう。

`app1.yaml`:

apiVersion: apps/v1
kind: Deployment
metadata:
name: app1-deployment
spec:
replicas: 2
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:

  • name: app1

image: nginxdemos/hello # 簡単なWebサーバーイメージ
ports:

  • containerPort: 80

`app1-service.yaml`:

apiVersion: v1
kind: Service
metadata:
name: app1-service
spec:
selector:
app: app1
ports:

  • protocol: TCP

port: 80
targetPort: 80

`app2.yaml`:

apiVersion: apps/v1
kind: Deployment
metadata:
name: app2-deployment
spec:
replicas: 2
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:

  • name: app2

image: nginxdemos/hello
ports:

  • containerPort: 80

`app2-service.yaml`:

apiVersion: v1
kind: Service
metadata:
name: app2-service
spec:
selector:
app: app2
ports:

  • protocol: TCP

port: 80
targetPort: 80

これらのファイルを適用する。

kubectl apply -f app1.yaml
kubectl apply -f app1-service.yaml
kubectl apply -f app2.yaml
kubectl apply -f app2-service.yaml

4. Ingressリソースの作成:
いよいよ、Ingressリソースを作成して、ルーティングルールを定義する。

`my-ingress.yaml`:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
# Nginx Ingress Controllerを使うことを明示
# kubernetes.io/ingress.class: “nginx” # 古いバージョン用
# nginx.ingress.kubernetes.io/rewrite-target: / # 必要に応じてリライト設定
spec:
rules:
# app1.example.com へのアクセスを app1-service にルーティング

  • host: app1.example.com

http:
paths:

  • path: /

pathType: Prefix # Prefixマッチング
backend:
service:
name: app1-service # 転送先のService名
port:
number: 80 # 転送先のServiceポート番号

# app2.example.com へのアクセスを app2-service にルーティング

  • host: app2.example.com

http:
paths:

  • path: /

pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80

このIngressリソースを適用する。

kubectl apply -f my-ingress.yaml

5. 動作確認:
IngressコントローラーのServiceのExternal IPアドレスを確認しよう。

kubectl get svc -n ingress-nginx

ここで取得したIPアドレスを、ローカルの`/etc/hosts`ファイルに追記するか、DNS設定で `app1.example.com` および `app2.example.com` をそのIPアドレスに紐づける。

ローカルでのhostsファイル編集例:
(Linux/macOSの場合)

/etc/hosts ファイルに以下を追加 (IPアドレスは実際の値に置き換える)
app1.example.com
app2.example.com

これで、ブラウザで `http://app1.example.com` にアクセスするとapp1の、`http://app2.example.com` にアクセスするとapp2のWebサーバーが表示されるはずだ!

Ingressを使うことで、一つの外部IPアドレスで複数のアプリケーションを、ホスト名やパスごとに柔軟にルーティングできるようになった。これは、本番環境で多くのサービスを公開する際に、コスト効率と管理効率を劇的に改善してくれる、まさに必須の技術なんだ。

—

4. TLS/SSL証明書の導入手順:安全な通信を実現しよう

現代のWebサービスでは、HTTPSによる暗号化通信は必須だ。k8sでIngressを使ってアプリケーションを公開している場合、TLS/SSL証明書を導入してHTTPS化するのは、Ingressコントローラーの得意技の一つなんだ。

TLS/SSL証明書の管理:Secretリソース

k8sでは、証明書のような機密情報を「Secret」というリソースで管理する。TLS/SSL証明書をSecretとして保存することで、アプリケーションやIngressコントローラーが安全にそれを利用できるようになるんだ。

1. 証明書の準備:
まずは、利用したいTLS/SSL証明書(公開鍵証明書ファイル `tls.crt` と秘密鍵ファイル `tls.key`)を用意する。

  • 本番環境: Let’s Encryptなどの認証局から取得した正規の証明書を使う。
  • 開発/テスト環境: 自己署名証明書や、ローカル開発用の証明書(mkcertなど)でもOK。

2. Secretリソースの作成:
証明書ファイルをk8sのSecretとして作成する。`tls` というキーで証明書と秘密鍵を格納するのが一般的だ。

証明書ファイル (tls.crt) と秘密鍵ファイル (tls.key) がカレントディレクトリにあるとする
kubectl create secret tls my-tls-secret \
–namespace <アプリケーションをデプロイしているNamespace> \
–cert=tls.crt \
–key=tls.key

3. IngressリソースでのTLS設定:
作成したSecretをIngressリソースで参照するように設定する。

`my-ingress-tls.yaml` (先ほどのIngress設定にTLS部分を追加):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress-tls
annotations:
# Nginx Ingress Controllerを使用
nginx.ingress.kubernetes.io/ssl-redirect: “true” # HTTPリクエストをHTTPSにリダイレクトする場合
spec:
tls:
# TLS設定を適用するホスト名とSecret名を指定

  • hosts:
  • app1.example.com # TLSを適用したいホスト名
  • app2.example.com

secretName: my-tls-secret # 作成したSecretリソースの名前
rules:

  • host: app1.example.com

http:
paths:

  • path: /

pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80

  • host: app2.example.com

http:
paths:

  • path: /

pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80

このIngressリソースを適用する。

kubectl apply -f my-ingress-tls.yaml

4. 動作確認:
再度、ブラウザで `https://app1.example.com` や `https://app2.example.com` にアクセスしてみよう。

  • 正規の証明書の場合: ブラウザのアドレスバーに鍵マークが表示され、安全なHTTPS通信ができていることが確認できるはずだ。
  • 自己署名証明書の場合: ブラウザで「安全ではありません」といった警告が表示されるが、これは証明書が信頼されていないためであり、通信自体は暗号化されている。開発環境でのテストとしては十分だ。

Let’s Encrypt との連携 (cert-manager)
本番環境では、Let’s Encryptのような無料の証明書を自動で取得・更新するのが一般的だ。k8sでは、`cert-manager` というツールを導入することで、このプロセスを完全に自動化できる。

1. `cert-manager` をk8sクラスタにインストールする。
2. `Issuer` または `ClusterIssuer` リソースを作成し、Let’s EncryptのACMEチャレンジ設定を行う。
3. IngressリソースのAnnotationで `cert-manager.io/cluster-issuer` などを指定する。

これで、Ingressリソースを適用するだけで、証明書の取得、更新、そしてIngressへの適用まで、全て自動で行ってくれるようになるんだ。これは、運用負荷を劇的に減らしてくれる、まさに魔法のような仕組みだよ。

—

まとめ:k8sのサービス公開はIngressで決まり!

お疲れ様! 今日は、Kubernetesでアプリケーションを外部に公開するための、ClusterIP、NodePort、LoadBalancerといった基本的なサービスタイプから、本番運用で必須となるIngressの活用、そしてTLS/SSL証明書の導入まで、じっくりと解説してきたよ。

  • ClusterIP: クラスタ内部通信の基本。
  • NodePort: 手軽だが、本番には向かない。
  • LoadBalancer: シンプルだが、コストや管理の課題も。
  • Ingress: 複数のServiceを効率的に公開する、本番運用のデファクトスタンダード。
  • TLS/SSL: cert-managerと組み合わせることで、HTTPS化も自動化できる。

特にIngressは、ルーティングの柔軟性、コスト効率、そしてTLS証明書の自動管理といった多くのメリットをもたらしてくれる。これをマスターすれば、君のk8sでのサービス公開スキルは、一気にプロフェッショナルレベルに引き上げられるはずだ。

最初は少し複雑に感じるかもしれないけれど、一つずつ試していけば、きっと理解できるはず。この知識を活かして、君のアプリケーションを世界に羽ばたかせてあげよう!

もし、もっと深く知りたいことや、疑問に思ったことがあれば、いつでも気軽に聞いてくれ。君のk8sエンジニアとしての成長を、心から応援しているよ!

タイトルとURLをコピーしました