Kubernetesをsystemdで置き換える(2024年)
(blog.yaakov.online)- 個人用サーバーや小型VPSでは、Kubernetesの宣言的自動化は魅力的だが、CPU・メモリ負荷と運用の複雑さが実際の利点を上回ることがある
- Kubernetesは望ましい状態を継続的に保つ方式で、Podの調整やTLS証明書の更新のような自動化を行うが、そのためにかなり大きなランタイムを常時維持する
- Azure Kubernetes Service、Microk8s、K3S、Raspberry Piでの実験では、アイドル時のリソース使用量や発熱・ファン騒音が繰り返し問題になった
- Podmanはコンテナをsystemdサービスにでき、
io.containers.autoupdateとpodman auto-updateで新しいイメージを検知して置き換えられる - Podman、systemd、user lingeringの組み合わせは、Kubernetesで求めていた自動化の大半をよりシンプルに提供するが、systemd統合はQuadletの方向へ移行している
Kubernetesの自動化が個人サーバーには重かった理由
- Kubernetesは複数の構成要素、Webサービス、サイドカー、Webhookで成り立っているが、中核となる動作は現在の状態と望ましい状態を継続的に比較して差分を適用するループに近い
- あるべきPodがなければ作成する
- replicaが3つであるべきなのに4つあれば1つ削除する
- このモデルはcert-managerのような拡張で特に有用だった
- 特定ドメインに有効なTLS証明書が必要だと宣言する
- 証明書の取得方法を指定しておくと、証明書がない場合や有効期限が近い場合に新しい証明書を取得してWebサーバーにインストールする
- 個人的な実験用途では面白く学習価値もあったが、実運用の目的には過剰なツールに近かった
- リソース負荷は複数の環境で繰り返し発生した
- NUCではコンピューターが回り続けて熱くなり、ファンの騒音が出て眠りにくかった
- Azure Kubernetes ServiceではKubernetes実装がRAMを大きく消費し、worker nodeでアイドル時のCPUを約**7〜10%**使用した
- 2 vCPU x86_64 VPSの単一インスタンスMicrok8sでは、アイドル時CPUが約**12%**程度だった
- 2 vCPU Ampere A1マシンのK3Sはより軽量な実装として知られていたが、それでも約**6%**の常時CPUを使用した
- Raspberry Piでも、発熱やファンの問題を起こさずにワークロード向けの十分なCPUを残せる実装は見つからなかった
Podmanとsystemdに置き換えた自動化の方法
- Kubernetesを使い続けていた最大の理由はデプロイ自動化だった
- GitOpsとFluxを使うと変更作業が簡単だった
- コンテナイメージの自動化とFlux v2のWebhookにより、新しいイメージをpushすると数秒以内にサーバーが新しいイメージを取得し、本番アプリケーションを実行した
- Kubernetes以外で見つけた既存の代替手段は満足できるものではなかった
- 元のコマンドライン引数をすべて覚えてコンテナを作り直す方式は管理負担が大きかった
docker.sockの完全な制御権を要求するツールも好まなかった
- Podman auto-updatingは必要な機能にかなり近かった
- PodmanはDocker CLIの代替とみなせる
- コンテナ作成後にsystemdサービスファイルを生成できる
- サービスを開始するとコンテナを作成または置き換え、サービスを停止するとコンテナを削除する
- 自動更新は
io.containers.autoupdateタグで動作する- 1日1回タイマーで実行するか、
podman auto-updateを直接実行する - 新しいイメージがあれば、そのイメージでコンテナを再作成する
- 1日1回タイマーで実行するか、
- Fedora MagazineのAuto-updating Podman containers with systemdが実装方法の大半を提供しており、さらに2つの設定が必要だった
systemctl --user enable mycontainer.serviceでログイン時にコンテナが自動起動するようにするloginctl enable-lingerでサーバー起動時にユーザーセッションが動作するようにする
- Podman、systemd、user lingeringの組み合わせにより、Kubernetesで得ていた利点の約**99%**を、はるかに低い複雑さとCPU・メモリ負荷で得られた
- すべてのサービスを既存VPSから、vCPUとRAMが半分の新しいVPSへ移行し、数時間の稼働ベースでより軽く速く、コンピュートコストも低かった
- ただしPodmanのsystemd統合はすでに非推奨になったようで、コンテナ定義はQuadletファイルの方向で議論が進んでいる
1件のコメント
Hacker Newsの意見
原文筆者の気持ちには完全に共感する。職場では数十個のマイクロサービスが動く複数の Kubernetes クラスターを比較的簡単に管理しているが、収益のない趣味プロジェクトでは予算が小さく、Kubernetesを使いたくても使えない。
1共有vCPUと2GB RAMの月額10ドルVPSでは、Kubernetesは重すぎる。Deploymentの代わりにSSHで
docker compose up/downを手動実行し、Ingressの代わりにTraefikのコンテナ検出機能に頼り、CronJobsが使えないのでcrontabを冪等に管理する小さなスクリプトまで自作した。本当に欲しいのは、安価なVPSでもうまく動く Kubernetes互換API を提供する軽量な代替案だ。エンタープライズ級のコンテナオーケストレーションと、趣味向けの低価格ホスティングとの間の隔たりは、今なお大きすぎる。
docker composeのように動作する。記事で説明されている方式のように、systemdユニットとも併用できる。PodmanはDocker APIも大部分、または全部をサポートしているため
docker composeも動作し、SSH経由でリモートソケットに接続して作業することもできる。https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
無料でARM64コア4個とRAM 24GBが提供され、望む方式に応じて1〜4ノードに分けられる。
https://www.oracle.com/cloud/free/
docker composeのように使える。Traefikとラベルを使ってリバースプロキシとTLS証明書を一般化し、Autheliaを簡単な認証プロバイダーとして付ければよい。GitHubにもサンプルプロジェクトが多く、週末くらいで設定すれば、かなり管理しやすいシステムになる。
systemd はよく批判されるが、本当に多くの問題を解決してくれるので、簡単に無視すべきではない。ディストリビューションに標準で入り始めたとき、人々は変化を強いられるのが嫌だった面が大きい。
コンテナ、
machinectl、より強力なchrootであるnspawn、完全仮想化が必要なときに使うvmspawn、マシンをダウンロード・インポート・エクスポートするimportctl、ホームディレクトリの暗号化と権限制御を簡単にするhomed/homectlなどがある。fstabの代わりにマウントをユニットとして扱い、起動順序やサービスの開始・停止を制御し、cronより強力な タイマー も提供する。例えば、マシンが停止していて実行できなかったジョブを把握したり、起動後に特定条件で遅延実行したりできる。サービスユニットは処理を細かく制御し、権限を制限できるうえ、
systemctl editで元の設定に手を入れずにoverride設定を作成できる。最初に覚えるのは少し面倒だが、複雑なことをするなら、ドキュメントをまったく見ずに済むツールなど結局存在しない。問題は 管理者の態度 だった。正常に動いていたものを平然と壊しながら、適切な修正策を提供しないというものだった。systemdで苦痛を感じなかったのなら、遅れて参加したか、自分の必要が中心的な管理者の必要と偶然重なっていたのかもしれない。
execしようとして、さらに複雑な動作をすることだ。PID 1がすべきことを100%正確に行い、それ以外は何もしないプログラムは、はるかに小さく作れる。そこからsystemdを起動すれば、systemdに何か問題が起きても即座にカーネルパニックにはつながらない。
出典: https://ewontfix.com/14/
cronを忘れろというのは納得しにくい。50年 にわたってうまく動いてきたのに、突然とても間違ったものになり、当然systemdに置き換えられるべきだ、という話になっている。fstabを忘れてsystemdのマウントを使うと、自動マウントのルールが複雑で、ドキュメントと1対1で合わせても、時々単に動作せず、ファイルシステムが適時にマウントされないことがある。ディストリビューションやアップストリームの立場では、生活を非常に楽にしてくれるが、その代償としてシステムの最下層に増え続ける複雑さを追加する。見方によっては、
journalctl、timedatectl、dbus依存または代替といったものが Unix哲学 に合わないと見なせる。単にプロセス群を調整し、正しい順序で実行し、自動アクティベーションを保証したいという目的なら、k8sやDockerより適切なレベルのツールだと思う。
ホームラボをしばらく podman-systemd、つまり Quadlet で運用してきたが、新しい k8s 亜種を見るたびに、追加の手間を引き受ける価値はないと感じた。古い Ansible プレイブックでイメージを事前に取得しておき、ユニットファイルを所定の場所に置くやり方で十分
Voron 3D プリンタのスタック全体も podman-systemd で動かしており、全コンポーネントを一度に更新・ロールバックできるようにしている。ただし今は
mkosiとsystemd-sysupdateでディスクイメージ全体を一括更新・ロールバックする方式も検討中主な問題は、人々がたいてい
docker-composeファイルだけを配布するため systemd ユニットに変換する必要があることと、一部の Docker イメージがユーザー・権限設定の面で Podman には不要な複雑さを持っていること。特にコンテナが root 実行を拒否したり別ユーザーに切り替えたりすると、面倒なusernsID マッピングが必要になる場合があるそれでも全体としては、どんな k8s や k8s 亜種の設定よりはるかに複雑さが少ない。systemd と journald の両方に統合され、二か所に分かれない点も良い
ユニットを置くだけで済む方式なので、非常に安定していて単純
composeファイルを Quadlet ファイルに変換するときはpodletを使える: https://github.com/containers/podletしかし k8s が提供する、複数ノード上でのオーケストレーション・スケジューリング抽象化の代替にはならない。「Podman-systemd ファイルを実行できるマシンがここにあり、実行したい仕様がここにあるので、あとはうまく配置してほしい」という部分が欠けている
podman runコマンドでコンテナを立ち上げてみて、正しく動くことを確認した後、podletで基本のコンテナファイルを作り、ボリュームとネットワークを別の Quadlet ファイルに分離する形でコンテナファイルを修正すれば終わりpodman-composeプロジェクトも今なお活発にメンテナンスされているようで、docker-composeの良い代替になり得る。ただ、Podman と systemd の連携が非常に満足度が高いこれをさらに単純化する次の段階は、systemd の中で Quadlet によってコンテナを管理すること。詳しくは https://www.redhat.com/en/blog/quadlet-podman にある
docker composeから rootless Podman Quadlet に移行し、移行は大変だったが結果にはとても満足しているskate を作った: https://github.com/skateco/skate。基本的にはこの目的のためのものだが、複数ホストをサポートし、k8s マニフェストにも対応している。内部的には Podman と systemd を使っている
ただし k8s は API とユーザー体験が最悪だと思う。Docker Compose 仕様のほうがずっとユーザーフレンドリーなので、現在は複数ホスト向けの
docker-composeを実験している: https://github.com/psviderski/uncloud再び deb パッケージにまとめ、EC2 インスタンス上で systemd から直接実行する方式に戻り、コンテナはもう使っていない。インスタンスは ALB 付きの Auto Scaling Group に入れ、起動時に簡単な
ansible-pullが deb をインストールするかなり素のままのやり方だが、終わりのない JSON の中の YAML の中の HCL には疲れた。今は Ansible YAML くらいだけを扱いたい
apt full-upgradeを実行し、実行中のプロセスだけを再起動すれば保護されること何かを再ビルドしたり、自分で作ったかもしれないしそうでないかもしれないコンテナの奥深くに埋もれたライブラリをどう更新するか探したりする必要がない
cgroup サポートのおかげで、1 台の VPS 上で複数サービスを動かすのにも向いている
この記事は1年以上前のものなので、今では systemd にはイミュータブルなワークフロー向けの公式対応 OS ディストリビューションである ParticleOS まである
https://github.com/systemd/particleos
https://news.ycombinator.com/item?id=43649088
systemd-kernelに置き換えることだろうし、そうなれば完成だ読んでみると、これらすべては
docker composeコマンドと、証明書を自動で取得してくれる Caddy のようなもので置き換えられそうに見えるcompose.yamlさえあれば、基本的にはdocker compose up -d --pull alwaysの1行で済む。CI 設定もscp compose.yaml user@remote-host:~/の後にssh user@remote-host 'docker compose up -d --pull always'で十分利点はシンプルで、開発マシンでも動くこと。もちろん副次的な目的が、面白いことを試して学ぶことなら、Quadlet、k8s、systemd も良い選択肢だ
docker context create --docker 'host=ssh://user@remote-host' remote-hostを実行すればよいその後は
docker -c remote-host compose -f compose.yaml up -d --pull alwaysを使えば、ファイルをコピーする必要がない。また~/.ssh/configにユーザー情報を設定しておけば、SSH 呼び出しでuser@を書かなくてよくなり、チームでドキュメントやコマンドをコピーして使いやすいDOCKER_HOST環境変数を設定すればよい。ただしcomposeファイルの補間には ローカル環境変数 が使われるので注意が必要単一サーバーへのデプロイがこんなに複雑であるべきではないと思い、自分の望む形でデプロイするツールを作った: https://harbormaster.readthedocs.io/
Harbormaster は YAML ファイルでリポジトリを見つけ、定期的にクローン・更新した後、その中の Docker Compose ファイルを実行する。すべての状態も単一ディレクトリに保存するので、バックアップが簡単
単一サーバーだけが必要なら、これまで見たコンテナオーケストレーションツールの中で最も簡単で良い。設定全体がリポジトリに宣言され、すべての状態が1つのディレクトリにあり、すべてがただの Compose ファイルである点が気に入っている
ここのコメントを読んでいると、自分が年を取った気分になる。もう誰も ssh と nginx だけを使わないのだろうか、と思ってしまう
1台の箱に全部詰め込み、その箱を積極的にバックアップすれば終わり。自宅用途にマイクロサービス管理までは本当に必要ない