このページでは Kubernetes Services について説明します。また、Service を Google Kubernetes Engine で使用する方法についても説明します。Service の作成方法については、Service を使用したアプリケーションの公開をご覧ください。
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: ...
Service を利用する理由
Kubernetes クラスタでは、各 Pod に内部 IP アドレスがあります。しかし、Deployment 内の Pod が稼働して停止すると、IP アドレスが変わります。このため、Pod IP アドレスを直接使用しても意味はありません。Service を使用すると、メンバー Pod の IP アドレスが変更されても、Service の存続期間中に固定の IP アドレスを取得できます。
Service は負荷分散としても機能します。クライアントは単一の固定 IP アドレスを呼び出しますが、リクエストは Service のメンバーである Pod 全体で負荷分散されます。
Service のタイプ
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 つの方法で呼び出すことができます。
clusterIP
とport
を使用する。- ノードの内部 IP アドレスと
nodePort
を使用する。
クラスタ構成によっては、Google Cloud HTTP(S) ロードバランサで NodePort
タイプの Service が使用されることがあります。詳細については、Ingress での HTTP 負荷分散の設定をご覧ください。
HTTP(S) ロードバランサはプロキシ サーバーで、このトピックの LoadBalancer タイプの Service で説明するネットワーク ロードバランサとは根本的に異なります。
LoadBalancer タイプの Service
LoadBalancer
タイプの Service を作成すると、Google Cloud コントローラが起動し、プロジェクト内にネットワーク ロードバランサが構成されます。ロードバランサには、プロジェクトの外部からアクセス可能な固定の IP アドレスが設定されます。
ネットワーク ロードバランサはプロキシ サーバーではありません。パケットを送信元 IP アドレスと宛先 IP アドレスを変更せずにそのまま転送します。
LoadBalancer
タイプの Service のマニフェストは次のとおりです。
apiVersion: v1 kind: Service metadata: name: my-nlb-service spec: selector: app: metrics department: engineering type: LoadBalancer ports: - port: 80 targetPort: 8080
Service を作成したら、kubectl get service -o yaml
を使用して仕様を表示し、固定の外部 IP アドレスを確認します。
spec: clusterIP: 10.11.242.115 externalTrafficPolicy: Cluster ports: - nodePort: 32676 port: 80 protocol: TCP targetPort: 8080 selector: app: metrics department: engineering sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 203.0.113.100
上の出力では、ネットワーク ロードバランサの IP アドレスが loadBalancer:ingress:
の下に表示されています。外部クライアントは、ロードバランサの IP アドレスと port
で指定された TCP ポートを使用して Service を呼び出します。リクエストは、いずれかのメンバー Pod の、targetPort
で指定された TCP ポートに転送されます。前の例では、クライアントは 203.0.113.100 の TCP ポート 80 で Service を呼び出します。リクエストは、いずれかのメンバー Pod の TCP ポート 8080 に転送されます。メンバー Pod には、TCP ポート 8080 でリッスンするコンテナが必要です。
LoadBalancer Service タイプは NodePort タイプの拡張で、このタイプは ClusterIP タイプの拡張です。
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 は抽象的な概念です。抽象化の一部は、クラスタノードの iptables ルールで実装されます。Service のタイプによっては、抽象化の他の部分がネットワーク負荷分散または HTTP(S) 負荷分散で実装されます。
任意の 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 のメンバーかを記録します。
次のステップ
- Kubernetes Services
- Service を使用したアプリケーションの公開
- Deployment
- StatefulSet
- Pod
- Ingress
- Ingress を使用した HTTP 負荷分散