# はじめに
どうも、わたしです。
最近、安価なVPS上で複数のワークロードをいい感じに収容する方法について考えています。
こんなツイートが伸びるくらいなので、もしかしたら多くの人が気になっているのではないでしょうか。

どうも、わたしです。
最近、安価なVPS上で複数のワークロードをいい感じに収容する方法について考えています。
こんなツイートが伸びるくらいなので、もしかしたら多くの人が気になっているのではないでしょうか。
このような用途の多くは既にサーバレスへ代替されてしまっているのでしょうが、私がやりたいのは、常時起動する小リソースでステートフルなワークロードをデプロイすることです。
そもそも、リクエスト単位で起動して終了するようなものであればCloudflareのWorkersが一番安くていい感じなんじゃないでしょうか。
基本的に、私しか使わないようなものは自宅のKubernetesクラスタにデプロイしているのですが、Misskeyのように外向きのトラヒックが大半を占めるワークロードを自宅に置くのには抵抗があります。
そこで活躍するのが安価なVPSです。帯域こそ微妙なものの、安価で、国内ベンダとしては比較的まともなKAGOYA CLOUD VPSを私は愛用しています。
VPSなんて必要になったらその都度1台生やせばいいじゃん、という話ではあるのですが、数が増えてくるとそう単純でもありません。例えば、2GiB程度のVPSをアプリケーション単位を収容境界として個別に割り当てていけば、当然ながら管理するホストの数も増えていきます。
では大きなVPSを1台借りて、そこへDocker Composeで全部詰め込めばいいのかというと、それも段々と辛くなってきます。どのホストに何が載っているのか、あとどれくらいメモリが空いているのか、新しいワークロードをどこに置くべきなのか。そういうことは機械にやらせてしまいたいわけです。
もっと言えば、負荷に応じていい感じにスケールアウトもしてほしいですし、クレデンシャルを含めて綺麗にIaCしたい気持ちがあります。
私が思いつく限り、このような用途で一番有用なのがKubernetesです。
Argo CDなりFluxなりを使えばGitOpsできますし、Terraformなどとは違い、コントローラによる継続的なreconciliationを前提とした宣言的な構成管理ができます。クレデンシャルについてもExternal Secrets Operatorなどを利用すれば、外部のSecret Managerへ管理を寄せられます。
至れり尽くせりなわけです。
しかし、Kubernetesには致命的な欠点があります。
よく言われるものでは、エコシステムが無駄に大きいとか、学習コストが高いとかいう話もありますが、現に私は使っているので本質的な問題ではありません。
単純にオーバーヘッドが大きいんです。
もちろん、何をもって重いとするかにもよるでしょし、数十GiB、数百GiBのメモリを積んだノードを大量に抱えている環境なら、kubeletやcontainer runtimeが数百MiB食っていたところで誤差でしょう。
しかし、今回考えているのは、安価に契約できるVPSです。4GiB、8GiBあたりの小さい仮想マシンを10何台か契約して、その上へ1-2GiB程度のワークロードを効率よく詰めることを目的としています。
こういう用途に限れば、ノード単位で数百MiBから1GiB近いメモリを基盤側に持っていかれるのは結構しんどいですし、まともに運用しようとすると追加で監視基盤も必要になります。
node-exporterが生え、ログを集めようとするとAlloyやFluent Bitが生え、Ingress Controllerが生え、metrics-serverが生え、cert-managerが生えてきます。
もちろん全部が必須というわけではありません。が、Kubernetesをちゃんと運用しようとすると、周辺コンポーネントはどうしても増えてしまいます。結果として、ワークロードを収容するために用意したリソースのうち、それなりの割合を基盤そのものが消費することになります。
OS本体の消費リソースも考える必要がありますし、キャパシティの小さいVPSではこのオーバーヘッドを無視することができません。
そもそもの発端は、VPSの料金体系を眺めていたことでした。
これが不思議なもので、キャパシティの大きいプランを1台契約する場合と比較して、小さいプランを複数台契約した方が安いことがあります。(KAGOYAの場合だと、2GiBのプランがいちばんコスト効率が高そう)
であれば、「小さいVPSを大量に借りればよくない?」と思うわけです。
しかし当然、VPSを増やすたびにOSも増えます。
OS本体のオーバーヘッドもそうですが、Linuxをbootして、SSHできるようにして、Dockerなりcontainerdなりを入れて、監視を入れて、アップデートして、という作業を10台、20台やりたいかというと、全然やりたくありません。
私はアプリケーションを動かす基盤がほしいのであって、Ubuntuのお世話をしたいわけではないんです。
極端な話、ホストなんて壊れたら捨てて作り直せればいいし、普段SSHで入る必要すらない形が理想です。
その点においてはTalos Linuxがかなり好きです。Immutableで、SSHもshellもなく、APIから管理できますしね。ホストOSを意識する場面を大きく減らせるという意味ではとても理想的です。
ただし、TalosはKubernetesを動かすためのOSです。
私はKubernetesを前提にしないTalosがほしい。
この手の話をすると、大体Nomadがおすすめされます。実際、使ってみるまでは結構良さそうに見えました。
Task Groupで複数のコンテナを同じノードに置けますし、CPUやメモリを見てスケジューリングしてくれます。Rolling Updateもできます。Kubernetesより構成要素も少なく、かなり軽量です。
もうこれでいいのでは、と思えてきます。
しかし、使っていく中で微妙な部分がかなりあります。
Nomad自体は単一バイナリでシンプルなのですが、当然それを実行するOSは必要です。OCIコンテナを動かすのであればDockerやPodmanなどのruntimeも必要になりますし、ネットワークをちゃんとやろうとするとCNIが出てきます。service discoveryをどうするかという話もあります。
Consulもあります、Vaultもあります、とHashiCorpのエコシステムで補っていくことはできます。が、それらを積み上げた結果できるものに、Kubernetesとの本質的な違いがどれほどあると言えるのでしょうか。
別にHashiCorpスタックを愛しているわけではないのですが、気がつくと、
という、Kubernetesで既に統合されているものを自分で組み直す必要が出てきました。
どう考えても無駄なのでなかったことにします。
IncusOSなんかは特に好みで、immutableでshellもSSHもなく、APIから管理するという、Talosに近いものです。OCI application containerも直接実行できます。
ただ、特性上、複数のコンテナを1つのワークロードとして扱う振る舞いをしてしまう問題がありました。
例えば、
を1セットとして、必ず同じホストへ配置したいとします。
KubernetesであればPodがありますし、NomadならTask Groupがあります。
Incusの場合、基本的にはそれぞれが独立したinstanceになり、同じノードに置くのであれば、その配置をこちらで管理する必要があります。
では、それらを1つの単位として扱って、CPUやメモリの空きを見ながら自動配置してほしい。となると、結局schedulerが欲しくなりました。
というわけでIncusもなかったことにします。
じゃあ、世の中の人たちは複数のホストを一体どう管理しているのか気になります。Redditを見てみました。思ったよりつまらなかったです。
大きめのマシンを1台用意してDocker Composeをそのまま導入している場合や、複数台をそれぞれ独立したDocker hostとして管理する。PortainerやKomodo、Dokployのようなもので疑似的に中央管理する人もいるようでした。
あとはNixOS。これは結構魅力的でした。というか既に私はこれを普段使いのクライアント環境で使っています。
OSの状態自体を宣言的に管理できますし、再現もロールバックもできます。サーバを手作業で育てていく必要がありません。Talosに求めているものの大部分を備えています。
ただ、NixOSはあくまで「このマシンをどういう状態にするか」を管理するものです。
複数のホストを1つのリソースプールとして見て、「このワークロードは空きメモリが多いnode-hogeへ」みたいな配置をしてくれるわけではありません。
それらは別途考える必要があります。
ここでまたschedulerです。
どうも私が欲しいものの大半はschedulerの周辺に集約されているようです。
ここまで色々使ってみて、ようやく気づくことがあります。
私が欲しいものを並べると、
という感じになります。
すごくKubernetesですね。
Kubernetesを避けるために代替を探していたのに、代替できるものも結局はKubernetesになってしまいます。
Kubernetesは無駄に複雑で、実際私が使わない機能も大量にありますが、NomadやIncusの節で書いたとおり、小さなソフトウェアを組み合わせて同じ要件を満たそうとすると、runtimeやCNI、service discovery、schedulerの選定と統合が今度は自分の責務になってしまいます。
Kubernetesの中で済んでいた統合作業を自分でやり直しているだけで、複雑さの総量は減っていませんよね。Kubernetesがあの大きさなのにも、相応の理由があるということなのかもしれません。
では素直にマネージドKubernetesを使えばいいのかというと、あれはあれで高すぎて使えません。
workerもcontrolもパブクラの価格水準で、格安VPSをよしなにしようねという今回の話とは前提の金額が異なります。
結局のところ、Kubernetesは潤沢な計算資源を前提にした、富豪向けのソリューションなのかもしれません。
まだ決めていません。
ここまで書いておいて何なんだという話ですが、本当に決めていません。
Kubernetesを使えば、欲しいものは一通りそれなりに揃います。が、VPSで小規模なワークロードを高密度に詰めたいという用途では、やっぱりオーバーヘッドが気になります。
軽量化という意味ではK3sがあります。K3sはKubernetes自体を大幅に軽量化していますが、その下には普通のLinux distributionが必要になります。
一方のTalosは、別にK3sより軽いわけではなく、ホストOSとして綺麗なのであって、upstream Kubernetesそのものを軽量化してくれるものではないからです。
Talosのような運用モデルで、K3sくらい軽量なKubernetesが動けばかなり嬉しいのですが、どうも都合よく存在してくれることはありませんでした。
何かしらが足りない近しいものはいくつか見つけられたのですが、足りない部分を自分で補おうとすると、またKubernetesに近づいてしまいます。
Docker Composeで困らない規模なら、Docker Composeを使えばいいと思いますし、単一ホストで収まるなら、無理にクラスタを作る必要もありません。
ただ、要求を増やしていくと、最終的には「それKubernetesでできるよ」という話になってしまいます。
そんなことはとっくの昔から知っています。
それを避けたくて色々試していたわけですが、どうもこれらの要件を満たしたいのであれば、Kubernetesを使うのが一番素直なのかもしれません。
やはりKubernetesからは逃れられないようです。