MicroAd Developers Blog

マイクロアドのエンジニアブログです。インフラ、開発、分析について発信していきます。

HAProxy で提供する Rancher × Kubernetes エンドポイント

はじめに

プラットフォームエンジニアリングユニットの齊藤(id:saitoperf)です。 マイクロアドでは、複数の Kubernetes (K8s) クラスタを Rancher から構築・管理しています。

Rancher は、OSS の K8s クラスタ管理ツールで、クラスタの状況確認や UI 上からのバージョンアップなど、運用を効率化する様々な機能を提供しています。

今回は、Rancher で構築した複数の Downstream cluster1 のエンドポイントを、HAProxy を用いて提供・集約する方法を紹介します。

対象読者

  • K8s を運用しているインフラエンジニア
  • Rancher で複数クラスタを管理している方
  • 特定の FQDN で K8s API エンドポイントを公開したい方

前提知識

  • Rancher および K8s の基礎知識
  • HAProxy の基本的な設定ファイルが読める

HAProxy が必要になった背景

マイクロアドでは、以前のデータ基盤環境から K8s への移行を進めてきました。詳細は以下の過去記事をご参照ください。

developers.microad.co.jp developers.microad.co.jp

K8s 化を進める中で重要となったのが シークレット管理 です。 K8s には Secret という暗号情報を保持するリソースがありますが、セキュリティの観点から Git 上で直接管理するわけにはいきません。 そこで、マイクロアドでは Hashicorp Vault2(以下 Vault)でシークレットを中央管理することにしました3

そこで発生したのが、Vault と K8s 間の通信に関する問題でした。 Vault と K8s を通信させるためには、Vault が Master ノードの kube-apiserver に対して JWT 認証をする必要があり、Master ノードは API のエンドポイントを適切に公開しなければなりません。 これを実現する方法として「Rancher をプロキシにする方法」と「HAProxy をプロキシにする方法」の 2つを検討しました。

まず、Rancher をプロキシにする方法ですが、 Rancher 2.9 からは Rancher 自体をプロキシにして JWT 認証をする機能が追加されましたが(該当Issue)、以下の懸念がありました。

  • 可用性: Rancher がメンテナンスや障害で停止した際、全クラスタの認証に影響が出る
  • 拡張性: 通信量が増大した際、Rancher サーバ自体のスケールアウト作業が比較的重い
  • 管理性: エンドポイントが https://<hostname>/k8s/clusters/<ClusterID> となり、ランダムな文字列(ClusterID)が含まれるため識別しづらい

これらの理由から、Rancher を介さずに HAProxy をプロキシとしてエンドポイントを提供する構成を採用しました。

構築の手順

「ACE の有効化」と「HAProxy の構築」の 2ステップで進めます。

  • システム構成イメージ

  • 環境情報

プロダクト バージョン
Rancher 2.12.1
HAProxy 3.0.12

ACE (Authorized Cluster Endpoint) の有効化

Rancher には ACE (Authorized Cluster Endpoint) という、Rancher Server を経由せずに Downstream cluster の Master ノードへ直接通信できる機能があります。

Rancher UI から「Cluster Management → 該当クラスタの Edit config → Networking」を設定します。

  • TLS Alternate Names: cluster01.internal
  • Authorized Endpoint
    • Authorized Endpoint: Enabled
    • FQDN: cluster01.internal:6443
    • CA Certificates: 対象クラスタの Master ノード(例:cluster01-master01)にログインし /var/lib/rancher/rke2/server/tls/server-ca.crt の内容を貼り付け

ACE を有効化すると、Rancher UI からダウンロードできる該当クラスタの Kubeconfig に FQDN のエンドポイントが追加されます。

  apiVersion: v1
  kind: Config
  clusters:
  - name: "cluster01"
    cluster:
      server: "https://rancher.internal/k8s/clusters/xxx" # xxx はランダム文字列
+ - name: "cluster01-fqdn"
+   cluster:
+     server: "https://cluster01.internal:6443"
+     certificate-authority-data: "xxx"
  users:
  - name: "cluster01"
    user:
      token: "xxx"
  contexts:
  - name: "cluster01"
    context:
      user: "cluster01"
      cluster: "cluster01"
+ - name: "cluster01-fqdn"
+   context:
+     user: "cluster01"
+     cluster: "cluster01-fqdn"

HAProxyの構築

HAProxy は L4モードで構築します。 HAProxy では、リクエストの SNI (Server Name Indication) を使って L4 でバックエンドを振り分けることができます。 L4 モードでは TLS パススルーができるので、HAProxy が TLS をほどく必要がなく軽量に動作させることができます。

1つの K8s クラスタに対して 1つの HAProxy を用意する構成がよく見られますが、マイクロアドでは複数のクラスタを 1つの HAProxy で集約しています。

...
frontend https_frontend
  bind *:6443
  mode tcp

  tcp-request inspect-delay 3s ## TCP リクエストを解析するときの最大許容時間
  tcp-request content capture req.ssl_sni len 100 ## SNI を必ず取得する

  # req.ssl_sni が rancher.internal なら、rancher の master に振り分ける
  use_backend backend_rancher if { req.ssl_sni -i rancher.internal }
  # req.ssl_sni が cluster01.internal なら、cluster01 の master に振り分ける
  use_backend backend_cluster01 if { req.ssl_sni -i cluster01.internal }
  # req.ssl_sni が cluster02.internal なら、cluster02 の master に振り分ける
  use_backend backend_cluster02 if { req.ssl_sni -i cluster02.internal }

backend backend_rancher
  server rancher-master01 rancher-master01.internal:6443
  server rancher-master02 rancher-master02.internal:6443
  ...

backend backend_cluster01
  server cluster01-master01 cluster01-master01.internal:6443
  server cluster01-master02 cluster01-master02.internal:6443
  ...

backend backend_cluster02
  server cluster02-master01 cluster02-master01.internal:6443
  server cluster02-master02 cluster02-master02.internal:6443
  ...

...

設定のポイント

ここで重要なのが tcp-request inspect-delaytcp-request content capture です。 今回のように HAProxy を TCP リレーとして利用する場合、これらを適切に設定しないと TCP パケットから SNI を抽出する前に振り分け処理が走ってしまうことがあります。 その結果、バックエンドの選択に失敗する事象が発生しました。

おわりに

今回は、HAProxy を活用し、Rancher から構築した K8s クラスタのエンドポイントを提供・集約する方法を紹介しました。 HAProxy を L4 モードで動作させて SNI で振り分ける構成をとることで、以下のメリットを享受できました。

  • Vault 等の外部システムからの API リクエスト増減に対して、容易にスケールアウト・インが可能になった。
  • Rancher Server 自体の負荷や稼働状況に左右されないエンドポイントを構築できた。
  • FQDN による直感的なエンドポイント管理が可能になった。

今回連携させた Hashicorp Vault の具体的な活用事例についてもそのうち記事にしたいと思っていますので、どうぞご期待ください!

新卒インフラエンジニア絶賛採用中

マイクロアドでは技術への探究心があり、最新の技術・動向について積極的に学び活かす意欲を持った仲間を募集しています! またインフラエンジニアだけでなく、サーバサイド、機械学習エンジニアなど幅広く募集しています! 気になった方は以下からご応募ください!

recruit.microad.co.jp


  1. Rancher では、Rancher が管理するクラスタを Downstream cluster、Rancher 自体が動作するクラスタを Local Cluster と呼びます(Rancher のアーキテクチャ)。
  2. Hashicorp Vault は、機密情報の中央管理や動的生成ができるプロダクトです。
  3. Secret を安全に管理する方法として、他にも Sealed Secret という方法があります。