サービス


このページでは、Google Kubernetes Engine(GKE)における Kubernetes Service とその使用方法について説明します。Service には、さまざまなタイプがあり、一連の Pod エンドポイントを 1 つのリソースにグループ化するために使用できます。Service の作成方法については、Service を使用したアプリケーションの公開をご覧ください。

Kubernetes Service とは

Service の目的は、一連の Pod エンドポイントを 1 つのリソースにグループ化することです。このグループにアクセスするさまざまな方法を構成できます。デフォルトでは固定クラスタ IP アドレスを取得し、クラスタ内のクライアントはそれを使って Service 内の Pod と通信できます。クライアントがこの IP アドレスにリクエストを送信すると、リクエストが Service 内のポッドの 1 つにルーティングされます。

Service は、セレクタを使用してメンバーの Pod を識別します。Pod が Service のメンバーとして識別されるには、セレクタで指定されたすべてのラベルが Pod に設定されている必要があります。ラベルは、オブジェクトに関連する任意の Key-Value ペアです。

次の Service マニフェストのセレクタには 2 つのラベルが指定されています。selector フィールドでは、app: metrics ラベルと department:engineering ラベルの両方を持つ Pod がこの Service のメンバーであることを示しています。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

Kubernetes Service を使用する理由

Kubernetes クラスタの各 Pod は内部 IP アドレスを持ちます。しかし、Deployment 内の Pod が稼働して停止すると、IP アドレスが変わります。このため、Pod IP アドレスを直接使用しても意味はありません。Service を使用すると、メンバー Pod の IP アドレスが変更されても、Service の存続期間中に固定の IP アドレスを取得できます。

Service はロード バランシングも提供します。クライアントは単一の固定 IP アドレスを呼び出しますが、リクエストは Service のメンバーである Pod 全体で負荷分散されます。

Kubernetes Services のタイプ

Service には、次の 5 つのタイプがあります。

  • ClusterIP(デフォルト): 内部クライアントが内部の固定 IP アドレスにリクエストを送信します。

  • NodePort: クライアントは、Service が指定した 1 つ以上の nodePort 値を使用して、ノードの IP アドレスにリクエストを送信します。

  • LoadBalancer: クライアントがネットワーク ロードバランサの IP アドレスにリクエストを送信します。

  • ExternalName: 内部クライアントが、外部 DNS 名のエイリアスとして Service の DNS 名を使用します。

  • Headless: headless Service は、Pod のグループ化を行うものの、固定 IP アドレスは必要ない場合に使用します。

NodePort タイプは ClusterIP の拡張タイプです。したがって、NodePort タイプの Service はクラスタ IP アドレスを使用します。

LoadBalancer タイプは NodePort の拡張タイプです。したがって、LoadBalancer タイプの Service は、クラスタ IP アドレスと 1 つ以上の nodePort 値を使用します。

ClusterIP タイプの Service

ClusterIP タイプの Service を作成すると、Kubernetes が、クラスタ内のノードからアクセス可能な固定の IP アドレスを作成します。

ClusterIP タイプの Service のマニフェストは次のとおりです。

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

kubectl apply -f [MANIFEST_FILE] を使用して Service を作成できます。Service を作成したら、kubectl get service を使用して固定の IP アドレスを確認できます。

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

クラスタ内のクライアントが Service を呼び出すときに、クラスタの IP アドレスと、Service マニフェストの port フィールドで指定された TCP ポートが使用されます。リクエストは、いずれかのメンバー Pod の、targetPort フィールドに指定された TCP ポートに転送されます。前の例で、クライアントは 10.11.247.213 の TCP ポート 80 で Service を呼び出します。リクエストは、いずれかのメンバー Pod の TCP ポート 8080 に転送されます。メンバー Pod には、TCP ポート 8080 をリッスンするコンテナが必要です。ポート 8080 でリッスンするコンテナがない場合、「接続失敗」、「このサイトにアクセスできません」などのメッセージがクライアントに表示されます。

NodePort タイプの Service

NodePort タイプの Service を作成すると、Kubernetes が nodePort 値を割り当てます。この nodePort 値と任意のノードの IP アドレスを使用して Service にアクセスします。

NodePort タイプの Service のマニフェストは次のとおりです。

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

Service を作成したら、kubectl get service -o yaml を使用して仕様を表示し、nodePort 値を確認します。

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

外部クライアントは、nodePort で指定された TCP ポートとノードの外部 IP アドレスを使用して Service を呼び出します。リクエストは、いずれかのメンバー Pod の、targetPort フィールドに指定された TCP ポートに転送されます。

たとえば、1 つのクラスタノードの外部 IP アドレスが 203.0.113.2 とします。前の例では、外部クライアントは 203.0.113.2 の TCP ポート 32675 で Service を呼び出しています。リクエストは、いずれかのメンバー Pod の TCP ポート 8080 に転送されます。メンバー Pod には、TCP ポート 8080 でリッスンするコンテナが必要です。

NodePort Service タイプは ClusterIP Service タイプの拡張です。したがって、内部クライアントはこの Service を次の 2 つの方法で呼び出すことができます。

  • clusterIPport を使用する。
  • ノードの IP アドレスと nodePort を使用する。

一部のクラスタ構成では、外部アプリケーション ロードバランサNodePort タイプの Service が使用されます。

外部アプリケーション ロードバランサはプロキシ サーバーであり、このトピックの LoadBalancer タイプの Service で説明されている外部パススルー ネットワーク ロードバランサとは根本的に異なります。

LoadBalancer タイプの Service

LoadBalancer タイプの Service の詳細については、LoadBalancer Service のコンセプトをご覧ください。

ExternalName タイプの Service

ExternalName タイプの Service は、外部 DNS 名のための内部エイリアスを提供します。内部クライアントは、内部 DNS 名を使用してリクエストを行い、そのリクエストは外部名にリダイレクトされます。

ExternalName タイプの Service のマニフェストは次のとおりです。

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

Service を作成すると、Kubernetes は内部クライアントが Service の呼び出しで使用する DNS 名を作成します。上記の例では、DNS 名は my-xn-service.default.svc.cluster.local です。内部クライアントが my-xn-service.default.svc.cluster.local にリクエストを送ると、そのリクエストは example.com にリダイレクトされます。

ExternalName タイプは、根本的に他の Service タイプと異なります。ExternalName タイプの Service は、このトピックの冒頭で説明した Service の定義に該当しません。ExternalName タイプの Service は、一連の Pod に関連付けられておらず、固定の IP アドレスがありません。ExternalName タイプの Service は、内部 DNS 名から外部 DNS 名へのマッピングです。

ヘッドレス Service

ヘッドレス Service は、クラスタ IP アドレスを割り振らない Kubernetes Service の一種です。代わりに、ヘッドレス Service は DNS を使用して Service に関連付けられた Pod の IP アドレスを公開します。これにより、プロキシを経由することなく Pod に直接接続できるようになります。

ヘッドレス Service は、以下のようなさまざまなシナリオで役立ちます。

  • Pod 間のロード バランシング: ヘッドレス Service を使用して Pod 間で負荷を分散できます。これを実装するには、負荷を分散させる Pod に一致するセレクタを含む Service を作成します。すると、その Service は、セレクタに一致するすべての Pod にトラフィックを均等に分散します。

  • Service ディスカバリ: ヘッドレス Service を使用して Service ディスカバリを実装できます。これを実装するには、名前とセレクタを含む Service を作成します。ヘッドレス Service の DNS レコードには、セレクタに一致する Service の背後にある Pod のすべての IP が含まれます。クライアントはこれらの DNS レコードを使用して、Service に関連付けられた Pod の IP アドレスを見つけることができます。

  • Pod への直接アクセス: クライアントは、ヘッドレス Service に関連付けられた Pod に直接接続できます。これは、ロードバランサや DNS サーバーなど、基盤となる Pod に直接アクセスする必要がある Service に役立ちます。

  • 柔軟性: ヘッドレス Service は、ロードバランサ、DNS サーバー、分散データベースなど、さまざまな異なるトポロジを作成するために使用できます。

セレクタがあるヘッドレス Service では解決できない特別なネットワーク要件がワークロードにある場合は、セレクタなしのヘッドレス Service を使用することもできます。ヘッドレス Service は、コントロール プレーンが EndpointSlice オブジェクトを作成しないため、Kubernetes クラスタ自体に配置されていない Service へのアクセスに便利なツールです。この詳細については、セレクタなしの Service をご覧ください。

ヘッドレス Service のマニフェストの例を次に示します。

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

ヘッドレス Service を作成したら、DNS をクエリすることで Service に関連付けられている Pod の IP アドレスを見つけることができます。たとえば、次のコマンドは nginx Service に関連付けられている Pod の IP アドレスを一覧表示します。

dig +short nginx.default.svc.cluster.local

Kubernetes のクエリ拡張を使用するもう一つの例:

dig +short +search nginx

1 つのコマンドで 1 つのヘッドレス Service を作成できます。また、ヘッドレス Service は更新やスケールが簡単です。

kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]

Service の抽象化

一部のネットワーク インターフェースでリッスンするプロセスではないという点では、Service は抽象的な概念です。抽象化の一部は、クラスタノードの iptables ルールで実装されます。抽象化の他の部分は、Service のタイプに応じて、外部パススルー ネットワーク ロードバランサまたは外部アプリケーション ロードバランサで実装されます。

任意の Service ポート

Service マニフェストの port フィールドの値は任意ですが、targetPort の値は任意ではありません。メンバー Pod には、targetPort でリッスンするコンテナが必要です。

次の例は LoadBalancer タイプの Service で、port の値は 50000 に設定されています。

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

クライアントは、203.0.113.200 の TCP ポート 50000 で Service を呼び出します。リクエストは、いずれかのメンバー Pod の TCP ポート 8080 に転送されます。

複数のポート

Service の ports フィールドは、ServicePort オブジェクトの配列です。ServicePort オブジェクトには次のフィールドがあります。

  • name
  • protocol
  • port
  • targetPort
  • nodePort

複数の ServicePort がある場合、それぞれの ServicePort に一意の名前が必要です。

次の例は LoadBalancer タイプの Service で、ServicePort オブジェクトが 2 つあります。

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

前の例で、クライアントは 203.0.113.201 の TCP ポート 60000 で Service を呼び出します。リクエストは、メンバー Pod の TCP ポート 50000 に転送されます。クライアントが 203.0.113.201 の TCP ポート 60001 で Service を呼び出すと、リクエストはメンバー Pod の TCP ポート 8080 に転送されます。

メンバー Pod には、TCP ポート 50000 でリッスンするコンテナと TCP ポート 8080 でリッスンするコンテナが必要です。2 つのスレッドを持つ 1 つのコンテナにすることも、同じ Pod で実行される 2 つのコンテナにすることもできます。

Service エンドポイント

Service を作成すると、Kubernetes は Service と同じ名前の Endpoints オブジェクトを作成します。Kubernetes は、Endpoints オブジェクトを使用して、どの Pod が Service のメンバーかを記録します。

シングルスタック Service とデュアルスタック Service

IPv6 Service は、ClusterIP タイプまたは NodePort タイプを作成できます。GKE では、プレビュー期間中、LoadBalancer タイプのデュアルスタック Service がサポートされます。これに SLA やテクニカル サポートは付属しません。

これらの Service タイプごとに、IPv4、IPv6、デュアルスタックのいずれかの Service として、ipFamilies フィールドと ipFamilyPolicy フィールドを定義できます。

次のステップ