Service(サービス)とは何ですか?
Service(サービス)は、Kubernetesで最も重要なリソースオブジェクトの1つであり、サービスはアクセスポイントのアドレスを定義し、フロントエンドのアプリケーション(Pod)はこのアクセスポイントを使用してその背後にある一連のPodレプリカで構成されるクラスターインスタンスにアクセスします。 ServiceとそのバックエンドのPodレプリカの間の関係は、ラベルセレクターを使用して “シームレスな接続”を実現します。そして、RCの役割は実際には、Serviceのサービス能力とサービス品質が予想される基準にあることを保証することです。
Kubernetesが提供するマイクロサービスネットワークアーキテクチャ
すべてのサービスを分析、識別し、システム内のすべてのサービスをマイクロサービスとしてモデル化することにより—Kubernetesサービス、最終的には、私たちのシステムは異なるビジネス機能を提供し、お互いに独立している複数のマイクロサービスユニットで構成されます。サービス間の通信はTCP/IPを介して行われ、強力な分散能力、弾力性のある拡張能力、耐障害性を備えています。
各Podには個別のIPアドレスが割り当てられ、各Podはクライアントがアクセスするための独自のエンドポイント(Pod IP+コンテナポート)を提供します。現在、複数のPodレプリカがアクセスを提供するためにクラスターを形成しました。
Kubernetesは、各Nodeにkube-proxyをインストールする必要があります。kube-proxyプロセスは実際にはスマートなソフトウェアロードバランサーであり、Serviceへのリクエストをバックエンドの特定のPodインスタンスに転送し、サービスの負荷分散とセッション維持メカニズムを内部で実装します。
Kubernetesは、非常に巧妙なデザインを考案しました。Serviceは負荷分散器のIPアドレスを共有するのではなく、各Serviceにはグローバルでユニークな仮想IPアドレスが割り当てられます。この仮想IPはCluster IPと呼ばれます。これにより、各サービスは”通信ノード”として一意のIPアドレスを持つことになり、サービス呼び出しは最も基本的なTCPネットワーク通信の問題に変わります。
Podのエンドポイントアドレスは、Podが破棄され、再作成されるたびに変更されます。新しいPodアドレスは以前の古いPodとは異なります。一方、Serviceが作成されると、Kubernetesは自動的に使用可能なCluster IPを割り当て、Serviceのライフサイクル全体でそのCluster IPが変更されないようにします。したがって、Serviceの名前とServiceのCluster IPアドレスをDNSドメインマッピングとして使用するだけで問題が解決します。
Serviceの作成
例:Serviceの手動作成
kind: Service
apiVersion: v1
metadata:
name: mallh5-service
namespace: abcdocker
spec:
selector:
app: mallh5web
type: NodePort
ports:
- protocol: TCP #仅支持TCP和UDP,不写默认TCP
port: 3017
targetPort: 5003
nodePort: 31122
パラメーターの解説
ポート:ポートは、サービスがクラスターIP(サーバーIP)で公開されるポートを表します。 :ポートは、クラスター内のクライアントがサービスにアクセスするための入り口を提供します。
ノードポート:ノードポートは、Kubernetesが外部クライアントがサービスにアクセスするための入り口として提供する方法の1つです(もう1つの方法はLoadBalancerです)。 :ノードポートは、クラスターの外部クライアントがサービスにアクセスするための入り口を提供します。
ターゲットポート:ターゲットポートは非常に理解しやすいです。ターゲットポートは、ポッド上のポートであり、ポートとノードポートを通過するデータが最終的にはkube-proxyを介してバックエンドのポッドのターゲットポートに入るためです。
作成
[root@master test]# kubectl create -f abcdocker-server.yaml
service/mallh5-service created
サーバーの詳細情報を表示
[root@master test]# kubectl get service --namespace=abcdocker
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mallh5-service NodePort 10.254.22.153 <none>
3017:31122/TCP 13m
[root@master test]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 35d
nginx-service NodePort 10.254.200.178 <none> 80:31000/TCP 34d
[root@abcdockeryaml]# kubectl describe svc myserver
Name: myserver #名称
Namespace: default #命名空間
Labels: <none>
Annotations: <none>
Selector: app=nginx #マッチングPodラベル
Type: ClusterIP #svc IPタイプ
IP: 10.254.219.137 #svc IPアドレス
Port: mynginx-http 80/TCP #svcポート(ビジネスに応じてポートを調整できます)
TargetPort: 80/TCP #ポッドポート
Endpoints: 172.30.144.2:80 #一致するポッドIP
Session Affinity: None
Events: <none>
外部システムへのServiceのアクセス問題
Kubernetes内の3種類のIPを理解する必要があります。
- ノードIP:ノードのIPアドレス
- Pod IP:PodのIPアドレス
- クラスターIP:ServiceのIPアドレス
パラメータの説明:
- ノードIPは、Kubernetesクラスター内の各ノードの物理的なネットワークインターフェイスのIPアドレスです。これは実際の物理ネットワークであり、このネットワークに属するすべてのサーバーは、ネットワーク内に存在するかどうかに関係なく、このネットワークを介して直接通信できます。Kubernetes外のノードがKubernetes内のノードまたはTCP/IPサービスにアクセスする場合、ノードIPを介して通信する必要があります。
サーバーへのアクセスグラフ
- Pod IPは、各PodのIPアドレスであり、Docker Engineがdocker0ブリッジのIPアドレス範囲に基づいて割り当てます。通常、これは仮想的なレイヤ2ネットワークです。Kubernetesは、異なるノード上にあるPodがお互いに直接通信できるようにする必要があります。したがって、KubernetesのPod内のコンテナは、Pod IPがある仮想レイヤ2ネットワークを介して通信し、実際のTCP/IPトラフィックは物理ネットワークカードのIPアドレスを通じてフローします。
- クラスターIPは、仮想IPであり、ほとんど偽のIPネットワークです。
- クラスターIPは、Kubernetes Serviceオブジェクトにのみ適用され、KubernetesがIPアドレスを管理および割り当てます(クラスターIPアドレスプールからのソース)。
- クラスターIPにはPingできません。これは “実体ネットワークオブジェクト” がないためです。
- Kubernetesクラスター内では、ノードIP、Pod IP、クラスターIP間の通信には、Kubernetesが独自に設計した特別なルーティング規則が適用されます。
NodePortの実装方法の概要
NodePortの実装方法は、Kubernetesクラスターの各ノードで外部アクセスが必要なServiceに対して対応するTCPリクエストを開始することです。外部システムは、任意のノードのIPアドレス+特定のNodePortポートを使用してサービスにアクセスできます。任意のノード上でnetstatサービスを実行すると、NodePortポートが監視されていることがわかります。
ただし、NodePortは外部からServiceへのアクセスのすべての問題を完全に解決していません。たとえば、クラスターに10個のノードがある場合、外部のリクエストが単一の負荷分散器にアクセスすることが望ましい場合があります。外部のリクエストは、負荷分散器のIPアドレスにのみアクセスすればよく、負荷分散器がトラフィックを後方のNodePortに転送します。負荷分散器は通常、Kubernetesクラスターの外部に独立して存在し、ハードウェアロードバランサーまたはソフトウェア方式(たとえばHaproxyやNginx)で実装されます。各Serviceには、後ろ向きのNodeにトラフィックを転送するための対応する負荷分散器インスタンスが構成されることが一般的です。
例
apiVersion: v1
kind: Service
metadata:
name: myserver
namespace: default
spec:
selector:
app: nginx
type: NodePort
ports:
- name: mynginx-http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30001 #もしnodeportポートを指定しない場合、ランダムポート30000〜32767が生成されます
作成が完了したら、svcを確認します。
[root@abcdocker yaml]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 83d
myserver NodePort 10.254.201.121 <none> 80:30001/TCP 5s
[root@abcdocker yaml]# kubectl describe svc myserver
Name: myserver
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myserver","namespace":"default"},"spec":{"ports":[{"name":"myngin...
Selector: app=nginx
Type: NodePort
IP: 10.254.201.121
Port: mynginx-http 80/TCP
TargetPort: 80/TCP
NodePort: mynginx-http 30001/TCP
Endpoints: 172.30.
144.2:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
次に、ブラウザを使用してアクセスできます。
[root@abcdocker yaml]# netstat -lntup|grep 30001
tcp6 0 0 :::30001 :::* LISTEN 933/kube-proxy
Kube-proxyの動作原理
- Serviceは多くの場合、概念に過ぎません。実際にServiceが機能するのはkube-proxyサービスプロセスです。
- 各ノードノード上でkube-proxyサービスプロセスが実行されます。
- 各TCPタイプのKubernetes Serviceに対して、kube-proxyはローカルノード上にリクエストを受信するためのSocketServerを作成し、それをバックエンドのいずれかのPodのポートに均等に送信します。このプロセスはデフォルトでラウンドロビン(rr)ロードバランシングアルゴリズムを使用します。
- kube-proxyは、Api Server内のServiceとEndpointsの変更をクエリおよびリッスンし、各Serviceに対して “サービスプロキシオブジェクト” を作成し、自動的に同期します。サービスプロキシオブジェクトは、kube-proxyプログラム内の一種のアーキテクチャであり、このサービスに対するリクエストをリッスンするためのSocketServerを含みます。 SocketServerのポートは、ローカルの空いているポートをランダムに選択します。さらに、kube-proxy内部でロードバランサーLoadBalancerが作成されます。
- 変更されたServiceのリストに対して、kube-proxyは個別に処理します。
- クラスターIPが設定されていない場合、何もしません。そうでなければ、そのServiceのすべてのポート定義リストを取得します。
- Serviceポートにサービスプロキシオブジェクトを割り当て、そのServiceに関連するiptablesルールを作成します。
- 負荷分散コンポーネントの対応するServiceに対する転送アドレスリストを更新します。
- kube-proxyは、起動時とServiceまたはEndpointの変更を検出すると、ローカルのIptablesのNATテーブルに4つのルールチェーンを追加します。
- KUBE-PORTABLS-CONTAINER:Cluster IPおよびポート番号を使用してコンテナからServiceにアクセスします。
- KUBE-PORTALS-HOST:Cluster IPおよびポート番号を使用してホストからServiceにアクセスします。
- KUBE-NODEPORT-CONTAINER:Node IPおよびポート番号を使用してコンテナからServiceにアクセスします。
- KUBE-NODEPORT-HOST:ホストからNode IPおよびポート番号を使用してServiceにアクセスします。
注意:kube-proxyには、ポッドをランダムに選択するデフォルトのポリシーを設定することもできます。クライアントIPに基づくセッションアフィニティを実現することもできます。これには、service.spec.sessionAffinityの値を “ClientIP” に設定します(デフォルト値は “None” です)。