- ライター:奈良 昌紀
- 通信事業者のデータセンターにおいてネットワーク・サーバー運用を経験した後、ネットワンシステムズに入社。帯域制御やWAN高速化製品担当を経て、2008年から仮想化関連製品を担当。現在は主にクラウド、仮想インフラの管理、自動化、ネットワーク仮想化を担当。
目次
はじめに
以前、こちらのBlogで「Kubernetesネットワーク入門」を掲載させていただきました。今回はKubernetesクラスターにおいて、外部ロードバランサーがどの様に利用されるのかご紹介します。
Kubernetesクラスター内で起動するPodをクラスター外部に公開する方法として、Service (type: LoadBalancer)リソースを利用する方法と、Ingressリソースを利用する方法があります。いずれの方法も、クラスター外のロードバランサーを利用して、クラスター内のPodにリクエストを届ける必要があります。
クラウド環境でKubernetesを利用する場合、クラウドサービスが提供するロードバランサーを利用することが可能です。たとえばAWSであればElastic Load Balancer、AzureであればAzure Load Balancerが利用され、Amazon EKSやAKS等を構成すると利用可能になるため、ロードバランサーをあまり意識する必要は有りません。しかし、オンプレミス環境ではKubernetesクラスターの外部にロードバランサーを用意する必要があるため、ロードバランサーがどの様に利用されるのかを理解する必要があります。
Serviceリソースの役割
Serviceリソースは、クラスター内で起動するPodに対するL4負荷分散と名前解決を提供します。Kubernetesクラスター内部では、Podが動的に作成、削除されます。Serviceリソースがない場合、アクセス先のPod名やPodのIPアドレスを知らなければ、アクセスすることができません。また、PodのIPアドレスを認識できた場合も、多くのCNIではクラスター外部から直接Podに対して到達することができません。
そこで、Serviceリソースは負荷分散用の仮想IPアドレスを構成し、Kubernetes APIを参照して特定のラベルが付与されたPodを負荷分散対象として、動的に更新します。更に、クラスター内のDNSでこの仮想IPアドレスの名前解決を可能にします。
こうすることで、クラスター内のPodはService名を利用してPodにアクセスすることが可能になり、動的に作成・削除されるアクセス先のPodの情報を意識する必要がなくなります。クラスター外部からPodにアクセスしたい場合も、Serviceリソースが外部からアクセス可能なノード上のポート番号や、仮想IPアドレスを用意することで、クラスター内のPodに対してアクセスすることを実現します。
Serviceリソースのタイプ
このように、Serviceリソースを利用することによりPodに対するアクセスを抽象化し、Podとして実行されるアプリケーション同士を疎結合化することが容易になります。Serviceリソースには4種類のタイプがあり、用途に応じて使い分けます。今回は4種類のServiceのうち、ExternalNameを除く3種類をご説明します (ExternalNameは、Kubernetesクラスター内のPodから外部サービスの参照に利用されるServiceです) 。
ClusterIP
デフォルトのServiceタイプです。クラスター内のPodから、Podグループにアクセスするために利用されます。クラスター内でのみ利用されるIPアドレスが仮想IPとして利用され、各ノードはこのIPアドレス宛の通信をService配下のPodに負荷分散します。この負荷分散機能は各Linuxノード内のiptablesやIPVSによって実現され、VIPに対するアクセスをNATしてPodに負荷分散します。
負荷分散対象が異なるノードにも存在する場合、必ずしもノード内で通信は完結せず、CNI(Container Network Interface)によりノード間通信を介して、他ノード上のPodに負荷分散される可能性があります。
NodePort
クラスター外のクライアントから、Podグループにアクセスするために利用されます。クラスター外からアクセスするため、各ノード上のポート(デフォルトは30000-32767)を利用してServiceを公開します。クラスター内のいずれかのノードのこのポートにアクセスすると、Service配下のPodに負荷分散されます。
アクセス先のノード内にはClusterIPの設定が存在し、ノード内でClusterIPと同じ方法でPodに負荷分散を行います。従ってClusterIPと同様に、Node1で受信したトラフィックが、内部でNode2上のPodに負荷分散される可能性があります。また、クライアントがNode1のポートにアクセスしていて、Node1で障害が発生した場合、クライアントはアクセス先をNode2の同じポートに変更する必要があります。
LoadBalancer
クラスター外のクライアントから、Podグループにアクセスするために利用されます。NodePortと異なり外部のロードバランサーを利用してServiceを公開するため、ノードのIPアドレスやポート番号を意識する必要はなく、外部ロードバランサーに構成された仮想IPアドレスでアクセスすることが可能です。ロードバランサーに登録される負荷分散対象は、利用するCNIによって異なります。
ロードバランサーの負荷分散対象としてNodePortが利用される場合、ロードバランサーは受信したトラフィックをクラスターのNodePortに転送します。NodePortは受信したトラフィックを負荷分散してPodに届けます。この構成では、外部ロードバランサーで負荷分散が行われた後、クラスター内のiptablesによって再度負荷分散が行われることになります。
ロードバランサーがPodに対して直接アクセスできる場合、負荷分散対象としてPodのIPアドレスが直接登録されます。クラスター内にClusterIPが構成されますが、クラスター内で利用するためだけに利用され、クラスター外部からのアクセスに対しては介入しません。NodePortを利用する場合と比べてシンプルな構成になりますが、ロードバランサーとPodが直接通信できるようCNIが構成されている必要があります。
Ingressリソース
Ingressリソースは、クラスター内で起動するPodに対するL7負荷分散を提供します。Ingressに登録される負荷分散対象は前述のServiceが利用されます。ルーティングルールを作成することができるため、アクセス先のFQDNやパスに応じて異なるサービスにルーティングすることが可能です。
以下のマニフェストではwww.example.com
というFQDN向けのアクセスの中で、www.example.com/web1
に対するアクセスをweb1
サービスリソースに、www.example.com/web2
に対するアクセスをweb2
サービスリソースにルーティングします。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: website spec: rules: - host: www.example.com http: paths: - backend: service: name: web1 port: number: 80 path: /web1 pathType: Prefix - backend: service: name: web2 port: number: 80 path: /web2 pathType: Prefix
Ingressは、Kubernetes上にIngress Controllerを構成することで利用可能になります。Ingress Controllerは多数開発されており、これらを利用することでIngressリソースのマニフェストに基づいてロードバランサーの構成が可能になります。
Ingress Controllerにはいくつかの実装方法がありますが、オンプレミス環境で一般的なのは、Ingress機能を提供するL7ロードバランサーがPod(LB pod)として起動し、このPodをService (type: LoadBalancer)として外部に公開する方法です。Service type:LoadBalancerとして公開され、L4ロードバランサーによって処理された通信がNodePortやClusterIPによって、L7ロードバランサーPodに転送し、L7ロードバランサーPodがHTTP/HTTPSのリクエスト内容を認識し、トラフィックを宛先のServiceに転送します(以下のイメージではtype:LoadBalancerを可能にするためにNodePortを利用しています)。
まとめ
Kubernetes環境で、クラスター外部にPodを公開する方法であるServiceとIngressの実装に関してご紹介しました。オンプレミス環境において、これらの機能を柔軟に利用するには、Kubernetes環境の外部にロードバランサーを配置する必要があります。ネットワンシステムズでは、複数のロードバランサー製品を取り扱っており、すでにKubernetesと組み合わせた検証を実施しております。今回ご紹介した機能を、弊社取扱製品でどの様に実装するのかをご紹介していく予定です。
※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。