🏗️

オンプレミスKubernetesクラスタのススメ~または私は如何にして心配するのをやめてTalos Linuxを愛するようになったのか~

に公開

はじめに

僕はここ10年くらい AWS をはじめとするパブリッククラウドを触ってきた。
たしかにパブリッククラウドにはさまざまな利点があるんだけれども、一方で色々と欠点もある。
最近ではインフラは全て Kubernetes に統一し、しかもある程度はオンプレミスのクラスタを持っていたほうが色々良いのではないかと思うようになった。
そこで少し前から Talos linux で構築した Kubernetes クラスタを運用している。
自分でクラスタを運用するようになって、細かい部分まで自分で制御できるというのは快適だし、また色々な実験をコストを気にせず出来るようになって非常に楽しい

オンプレミス Kubernetes クラスタを運用する選択は、知識の蓄積、運用費用両面からの判断で、技術者個人でもそうだし、ある程度インフラ技術者を抱える企業にも当てはまるように思う。
またこれから AI の活用を進めるにあたってデータの蓄積がますます重要になるから、 SaaS でデータを分散させるのではなく、同等のシステムをセルフホストして手元にデータを蓄積していくという目的でオンプレミス運用が必要になってくるように思う。
残念ながらまだまだエコシステムが固まっていない部分も多いので広く勧められるわけではないけれど、遠からず多くの人の手の届く所に降りてくる気がしているので、やる気があるインフラエンジニアであれば、ホームラボやあまり重要でない社内サービスなどでぼちぼち試して初めても良いのではないだろうか。

以下ではオンプレミス Kubernetes クラスタを勧める理由をクラウドとの比較だけではなく、根本から説明していきたい。

なぜ kubernetes か

なぜ kubernetes というと、突き詰めればエコシステムが成熟してきており今後も継続して開発が進められるだろうと思えるからだが、それだけでは言葉足らずだろう。

まずなぜ Kubernetes を選択するかを一つ一つ説明していく。

コンテナによる再現性の高い環境構築と可搬環境を基礎にしている

まず最初の理由は Kubernetes がコンテナによる半決定的な自動環境構築と可搬環境を基礎にしているということだ。
今時OSからインストールをしてシステムを立ち上げる人も少ないだろうから敢えて指摘する必要もないのかもしれないが、
オンプレミスとなるとOSのセットアップは必要で、そういった選択肢もあるから述べておく必要があるだろう。

この環境構築の決定性と可搬性はインフラを効率的に構築するために極めて重要だ。
コンテナやそういった関連の製品を使わず、素の OS 上に何らかのシステムを構築した経験があるなら、
上手くいかず誰かに助けを求めたときに「おかしいね、僕の環境では動いているんだけれども」という言い回しを聞いたことがあるはずで、
多分自分自身そう言った事もあるはずだ。

こういったことが起こるのは、OS上でのインストールプロセスが実行タイミングにより結果が異なる操作で(非決定的という)あって、かつ出来上がった環境が持ち運べないという事が原因だ。
OS上でのインストールプロセスが非決定的であることは、インストールプロセスをスクリプトにする事である程度は解決できるものの、
いちいちディスクイメージから立ち上げたノードにインストールスクリプトを走らせるのは大変に時間がかかる。
だからコンテナイメージで「動いている環境」をそのまま持ってこれるという可搬性はシステムの構築において非常に重要な要素だ[1]

Ansible などの構成管理ツールを使うという選択肢もあるが、やはり動作する事が確認済みの環境をそのまま持ってくることが出来るコンテナと比較すると、時間もかかるし予期せぬトラブルの可能性があり弱い。
そういうわけでコンテナを使えるという事は非常に重要な要素だ。

クラスタでのマシン管理

さてコンテナを使うと決めても、じゃあコンテナを動かすインフラを構築しなければならない。
ここで昔ながらのノードごとに個別に環境を構築するやりかたは、たとえ一台のマシンであってもやめた方がいいだろう。
Talos Linux であればノードの構成を宣言的に記述することができて、ほぼ全ての設定を自動化できるからだ。

Talos Linux は SSH 等のコンソールからの操作を廃し、全てを API によって管理出来るように設計された Kubernetes 専用の Linux ディストリビューションだ。
PodSecurity AdmissionやSeccompなどのセキュリティ機能がデフォルトで有効になっており、セキュアなクラスタを簡単に立ち上げる事ができる。
この Talos の全ノード共通のイメージをノードのディスクに書き込んでブートしたり、 PXE ブートで起動すれば、あとはネットワーク経由で全ての設定が可能になる。
そのためノードがどんなに増えても Mac アドレスとネットワークアドレスと Talos のノード構成(talos では machine config などと言ったりする)の対応を用意すれば、ほとんど手をかけずにクラスタの立ち上げが可能で、それ以降の構成は全て Kubernetes 上で操作が可能だ。

はじめからまず Kubernetes クラスタとしてまとめて、その上でコンテナを動かすやり方にすることで、構築時の手間はもちろん、その後の運用の手間も大きく減らすことができる。

真に宣言的な IaC

ここまではクラスタ構築までの話をしてきた。ここからはクラスタ構築後の話をしていく。
僕ば Kubernetes に強い興味を持つようになった理由は Kubernetes の IaC が真に宣言的であるという点だ。
IaC というと Terraform(今は OpenTofu) が有名だ。
僕は5年くらい前までは Terraform 職人をやっていたが、結局好きにはなれなかった。
これらは一見宣言的に見えるものの、抽象化が弱くすぐに手続的な性質が表に出て来てしまう。
Terraform で増築を繰り返しながら構築した場合、かなりの頻度でそのコードは一からデプロイ出来なくなってしまう。
これは依存関係を宣言的な記述から解決出来なくなるためで、これを解決するため明示的に依存関係を記述しなければならなくなる。
この場合依存関係が正しいかどうかは最終的には実行して確認する必要があり、恐ろしく手間がかかることになっていた。

なぜこうなってしまうのかというと、 Terraform がコードが実行されたときにのみ操作が行われる作りになっているからだ。
一方で Kubernetes はコントローラがリソースの状態を常に監視しており、マニフェストに記述された状態と実際の状態が異なっている場合に自動的に修正を行う。
依存するリソースが無くて作成できない、あるいは作成に失敗する場合は、そのリソースが出来上がれば次の試行の際に立ち上がる。
基本的にこの原則があるため、Kubernetes の IaC は真に宣言的であり、増築を続けても安心していつでもそれが一からデプロイできると信じることができる。
このことはインフラの構成を試行錯誤しながら組み上げていく場合に極めて重要な性質で、
毎日の少しづつの改善が確実に将来に向かって積み上がっていくという確信を持って開発を進められる。

このアプローチも問題がないわけではない。
まず最大の問題はこのまま待っていればデプロイが終わるのか、それとも何か問題が起きているのか分かりにくいという点だ。
また、残念ながら一部のCRDでこの原則が守られていないケースがある。
やたらと時間がかかっているのでおかしいなと思って手を出すと却って自体を悪化させてしまうケースもあるので落ち着いて待つ必要がある。
とはいえ何か変更をするたびに一からデプロイしなおして検証しなければならないのと比べれば、遥かに開発の際のストレスは少ない。
何かおかしいと感じた時の調査は、これまではどこを見なければわからない、分かったとしても大量のログを掘るのがつらい、という問題があったけれど、これも LLM を使う事で大幅に楽になってきている。

オペレータと Helm Chart を使えば高度な運用も簡単にはじめられる

前述のように Kubernetes はコントローラを使ってリソースの状態を監視している。
このコントローラの考え方を特定のアプリケーションやサービスにまで拡張したものがオペレータだ。
オペレータは単純な Pod や Deployment などのリソースを超えた様々なアプリケーションを Kubernetes リソースとして管理できるようにしてくれる。
たとえば CloudNativePGPostgreSQL クラスタの構築と運用を可能にしてくれる。
リードレプリカ、 WAL バックアップ、スケジュールバックアップ、クラスタのクローン作製などのパブリッククラウド品質の機能を SQL データベースを自前で運用できるようにしてくれる。

さっき述べたように Kubernetes のクラスタの立ち上げ自体はそれほど難しくなくなっているけれど、現状ではストレージ、メトリクス、ログ等の基本的な機能についてはまだ明確に固まったものがない状況だ。
しかしそれでも近いうちに解決するだろうという期待があるのは、これらの機能についても Piraeus Operator, Prometheus Operator, Logging Operator などの様々なオペレータが出て来ているためだ。

また、 Kubernetes のパッケージマネージャとして Helm がある。
様々なパッケージが Helm Chart として公開されており、これを使うことで簡単にアプリケーションをインストールすることができる。
公式で配布されている Helm Chart に不足がある、自分の環境に合わないというような事もよくあるが、僕はこれを HelmfileKustomize を使う事で解決している。
Helmfile は helm と kustomize のラッパーで、複数の Helm Chart や Kustomize のマニフェストを一つのファイルで管理してデプロイできる。
Helmfile には Kustomize と同様の方法でマニフェストにパッチを当てるなどの機能があるので、これを使う事で Helm Chart の不足を補うことができる。

オペレータや Helm を使う事で、OpenSearchApache SparkApache Pulsar など、これまでは自前で構築するにはなかなか手が出なかったようなシステムを簡単に構築して運用できるようになるため、アーキテクチャ選択の幅が大きく広がるだろう。

なぜオンプレミスか

さて次になぜわざわざオンプレミスかということを説明する。
これは一言で言うと、コストと自由度だ。
以下ではなぜパブリッククラウドではないのか、なぜオンプレミスなのかという両面から説明しよう。

クラウドは多くのケースで高コスト

パブリッククラウドのわかりやすい欠点は日常的な多くの用途に対してオーバースペックで高コストだということだ。
この代表格がマネージド SQL だろう。
SQL サーバはほとんどのシステムで必要となり、マネージド SQL はクリティカルな業務のためには必要な機能と性能を備えている。
しかし多くのケースでそこまでの機能は必要ない。
さらに小規模なインスタンスでさえ月額約1万からで、クラウドを利用し始めた場合のコストの大半を占める。
これは Kubernetes クラスタも同様で、割引があればこそ比較的安価なものの、コントロールプレーン毎に月額1万程度は取られる。
それでは EC2 などのコンピューティングインスタンスを使って自前でインストールすれば良いのではないか、あるいはコンテナで、という意見もあるだろう。
しかしクラウドを利用する一つの理由が IaC にあるはずで、これらの解決策は多くの面でその利点を損なってしまう。

クラウドを利用する際の財務的な利点としては、固定費を変動費に出来るということがあるが、身近な多くのケースではむしろ流動的にすることによるコストの方が高くつく。
そもそも大半のシステムは規模が変動しない、つまりスケールしない。だからいくら任意のタイミングでスケール出来るから変動費だといっても実質的に固定費だ。
そしてスケールしないのであれば、買い切りの方がはるかに安く上がる。

サーバレスは初期コストを抑えるための有力な選択肢であるが、一方で制約もかなり多く、やはり根本的に高単価であるためスケールしだすと高くつく。
制約とコストの出方について割り切りが出来るならばよいが、そうでないならば第一の選択肢ではない。

またパブリッククラウドは各ベンダ毎に癖があるほか、トラブル時に取れる手段が限られており、費用をかけていない場合サポートを受けるにもかなりの待ち時間が発生するし、結局解決しないという事もおおい。
色々なベンダ固有の知識を蓄積して固有の対応方法を憶えるくらいなら、ベンダ横断で利用できてオンプレミスも可能な Kubernetes を選択した方が、知識を蓄積する上でも、トラブル時の対応を考える上でも遥かに楽だろう。

オンプレミス Kubernetes クラスタの構築と管理は意外と楽

さて翻ってオンプレミスの Kubernetes クラスタの構築と管理は意外と楽だ。
既に述べたように Talos Linux を使えば殆ど手間をかけずにクラスタを立ち上げて管理できる。
OS や Kubernetes のアップデートも実質コマンド一発で完了する。
ストレージ、メトリクス、ログ等の基本的な機能についても入れる一度構成を決めてしまえば、あとは同じマニフェスト群を使い回すことができる。

オンプレミスクラスタは可用性、信頼性、スケールなどの問題はあるものの、これも必要に応じてクラウドのリソースを組み合わせることである程度解決できる。
可用性、信頼性に関しては、多分データベースとストレージのバックアップに取っておけば十分なケースがほとんどなのではないだろうか。
スケールに関しては必要に応じてクラウドのインスタンスをワーカとして組み込むことで解決されそうだと考えている。

運用費用面で見ても定常的に使用するリソースは買い切りの方が安く上がるので、将来的にはまずオンプレミスで構築して、必要に応じてクラウドのリソースを組み合わせるというスタイルが一般的になるのではないかと思う。

オンプレミスkubernetesの展開(ホームラボの場合)

さて以下ではホームラボクラスのオンプレミス Kubernetes クラスタの場合の構成例を簡単に説明していく。

基本的にはまずは余っているノートPCやシングルボードコンピュータなどを使って、まずは Talos Linux でシングルノードのクラスタを立ち上げるのが良いのではないかと思う。
あまり欲張ったことをしなければ Kubernetes がどの様なものか体験するにはシングルノードでも十分だ。
ただしどんなノードを使うにせよ、メモリは多めな方がよい。

ある程度触ると、そんなにPCが余っているわけでもないだろうから、ノードを買い足したいと思うだろう。
この時は現時点ではミニPCが良いと思う。
N100 などの N シリーズプロセッサのミニPCなら2~3万円程度で入手可能で、電力消費量も概ね15Wh以下と少なく、これだと年間5000円程度の電気代で済む。
メモリは可能であれば 16GiB 以上のものを選んだほうが余裕を持って色々と実験できると思う。
ラズパイは 16GiB が品薄で高いので、同じか安い位の金額で Intel アーキテクチャでガワと電源アダプタとディスクも付いてくるミニPCの方が良いだろう。

Talos のインストールはドキュメントに従えばそこまで難しくないが、一点注意する事は、公式で配布されているイメージはインストーラではないということだ。
Ubuntu 等のライブイメージを使ってブートして、そこから dd 等で talos のイメージをディスクに書き込み、その上でマシンをブートしよう。

Talos での各ノードの設定はボイラープレートだらけなので、ある程度慣れてきたら talm を使うのがよいと思う。
複数のノードがあってもあっという間に設定を終えて立ち上げられるだろう。

その上で基本的なサービスを立ち上げて行く必要がある。僕は今は以下のような構成で運用している。

  • ネットワーク: Cilium
  • ストレージ: Rook/Ceph
  • メトリクス: Prometheus
  • ドキュメントストア: OpenSearch
    • ログ等のストレージとして使用予定

これらは全部 helmfile を使ってインストールしている。
この辺のスタックはまだ模索中なので、良さそうなものがあれば教えてほしい。

それとは別に Tailscale を Subnet Router として使う事でクラスタ内部ネットワークにアクセスできるようにしている。
また、Cloudflare Tunnel を使う事で、外部にサービスを公開できるようにしている。

Kubernetes に関しては、将来的には以下の構成に取り組んでみたい。

  • GPU ノードの導入
  • PXE ブートによるノードプールの構築
  • コントロールプレーンマネージャの導入
    • Kamaji を使用してコントロールプレーンをサーブ
    • これとノードプールを構築できれば、クラスタレベルでのサンドボックスの構成が出来るようになる
    • サンドボックスクラスタがつくれるようになると、 AI が安全に作業できる環境を構築できるようになる
  • 仮想マシンインリソースの導入
    • KubeVirt などで仮想マシンを運用できるようになると、プライベート IaaS への道が開ける。

おわりに

オンプレミスkubernetesクラスタはノードがある程度揃うまでは少し大きめの費用がかかるがそれ以降はコストを気にせず色々な実験したり、サービスを公開したり出来る。
最初は3ノードくらいまで増やして、その後は matchbox を使った PXE ブートや UPS を入れるなどして、徐々にノードやネットワークを整えて行くとよさそうだ。
なによりオンプレミスkubernetesは楽しい。
みんなオンプレミスkubernetesやろう。

脚注
  1. OS上でのインストールプロセスが非決定的であるという問題は、残念ながら Dockerfile のようなインストールスクリプトによる構成では、apt 等のパッケージマネージャなどが非決定的であるために完全には解決できない。これに関しては NixOS を利用することで完全に解決できるけれど、コンテナイメージになった時点で大半の問題は解決できているのでここでは触れない。でも NixOS は非常に面白いから時間があれば見てみてほしい。 Nix であれば極めてサイズの小さいコンテナイメージを作ることができる。 ↩︎

Discussion