2 ポイント 投稿者 GN⁺ 2025-05-06 | 1件のコメント | WhatsAppで共有
  • 個人用サーバーや小型VPSでは、Kubernetesの宣言的自動化は魅力的だが、CPU・メモリ負荷と運用の複雑さが実際の利点を上回ることがある
  • Kubernetesは望ましい状態を継続的に保つ方式で、Podの調整やTLS証明書の更新のような自動化を行うが、そのためにかなり大きなランタイムを常時維持する
  • Azure Kubernetes Service、Microk8s、K3S、Raspberry Piでの実験では、アイドル時のリソース使用量や発熱・ファン騒音が繰り返し問題になった
  • Podmanはコンテナをsystemdサービスにでき、io.containers.autoupdatepodman 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を直接実行する
    • 新しいイメージがあれば、そのイメージでコンテナを再作成する
  • 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件のコメント

 
GN⁺ 2025-05-06
Hacker Newsの意見
  • 原文筆者の気持ちには完全に共感する。職場では数十個のマイクロサービスが動く複数の Kubernetes クラスターを比較的簡単に管理しているが、収益のない趣味プロジェクトでは予算が小さく、Kubernetesを使いたくても使えない。
    1共有vCPUと2GB RAMの月額10ドルVPSでは、Kubernetesは重すぎる。Deploymentの代わりにSSHで docker compose up/down を手動実行し、Ingressの代わりにTraefikのコンテナ検出機能に頼り、CronJobsが使えないのでcrontabを冪等に管理する小さなスクリプトまで自作した。
    本当に欲しいのは、安価なVPSでもうまく動く Kubernetes互換API を提供する軽量な代替案だ。エンタープライズ級のコンテナオーケストレーションと、趣味向けの低価格ホスティングとの間の隔たりは、今なお大きすぎる。

    • 必要な Kube API の範囲によっては、Podmanがその役割を果たせる。KubernetesマニフェストからコンテナやPodを作成できるので、Kubernetesマニフェストを使う 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...
    • k0sk3s を見たことがあるのか気になる。小規模でこれをうまく使っている事例はかなり多い: https://news.ycombinator.com/item?id=43593269
    • Oracleの宣伝のようには聞こえたくないが、Oracle Cloud Free Tier は圧倒的に寛大だ。小さなk8sクラスターを含め、かなり多くのものを動かせるし、k8sのコントロールプレーンのサービスも無料だ。
      無料でARM64コア4個とRAM 24GBが提供され、望む方式に応じて1〜4ノードに分けられる。
      https://www.oracle.com/cloud/free/
    • 昔ながらのやり方で Ansible のようなものを使えばいい。専用サーバー数台をAnsibleで完全に管理しているが、ある種の強化版 docker compose のように使える。
      Traefikとラベルを使ってリバースプロキシとTLS証明書を一般化し、Autheliaを簡単な認証プロバイダーとして付ければよい。GitHubにもサンプルプロジェクトが多く、週末くらいで設定すれば、かなり管理しやすいシステムになる。
    • Kubernetesを使うコストが高すぎるとはすでに述べているので、どの軸で効率を測るかによっては、自作の解決策のほうがむしろ より効率的 かもしれない。
  • systemd はよく批判されるが、本当に多くの問題を解決してくれるので、簡単に無視すべきではない。ディストリビューションに標準で入り始めたとき、人々は変化を強いられるのが嫌だった面が大きい。
    コンテナ、machinectl、より強力なchrootである nspawn、完全仮想化が必要なときに使う vmspawn、マシンをダウンロード・インポート・エクスポートする importctl、ホームディレクトリの暗号化と権限制御を簡単にする homed/homectl などがある。
    fstab の代わりにマウントをユニットとして扱い、起動順序やサービスの開始・停止を制御し、cron より強力な タイマー も提供する。例えば、マシンが停止していて実行できなかったジョブを把握したり、起動後に特定条件で遅延実行したりできる。
    サービスユニットは処理を細かく制御し、権限を制限できるうえ、systemctl edit で元の設定に手を入れずにoverride設定を作成できる。最初に覚えるのは少し面倒だが、複雑なことをするなら、ドキュメントをまったく見ずに済むツールなど結局存在しない。

    • systemdが初期の数年、もしかすると10年近く批判されたのは、プロジェクト自体が悪かったからではない。むしろ、いろいろな問題があっても成功するほど優れていた。
      問題は 管理者の態度 だった。正常に動いていたものを平然と壊しながら、適切な修正策を提供しないというものだった。systemdで苦痛を感じなかったのなら、遅れて参加したか、自分の必要が中心的な管理者の必要と偶然重なっていたのかもしれない。
    • systemdで唯一気に入らない点は、数えきれないほど大きなコードベースから出てきたバイナリが PID 1 の役割を担い、アップグレード時に自分自身をその場で exec しようとして、さらに複雑な動作をすることだ。
      PID 1がすべきことを100%正確に行い、それ以外は何もしないプログラムは、はるかに小さく作れる。そこからsystemdを起動すれば、systemdに何か問題が起きても即座にカーネルパニックにはつながらない。
      出典: https://ewontfix.com/14/
    • cron を忘れろというのは納得しにくい。50年 にわたってうまく動いてきたのに、突然とても間違ったものになり、当然systemdに置き換えられるべきだ、という話になっている。
    • fstab を忘れてsystemdのマウントを使うと、自動マウントのルールが複雑で、ドキュメントと1対1で合わせても、時々単に動作せず、ファイルシステムが適時にマウントされないことがある。
    • systemdは、現代的なデスクトップやサーバーLinux、またはそれに近い用途なら素晴らしい。しかし、プロジェクトが想定した方式から外れたことをしようとすると、嘲笑と抵抗に遭うことになる。muslチームに聞けばいい。
      ディストリビューションやアップストリームの立場では、生活を非常に楽にしてくれるが、その代償としてシステムの最下層に増え続ける複雑さを追加する。見方によっては、journalctltimedatectl、dbus依存または代替といったものが Unix哲学 に合わないと見なせる。
      単にプロセス群を調整し、正しい順序で実行し、自動アクティベーションを保証したいという目的なら、k8sやDockerより適切なレベルのツールだと思う。
  • ホームラボをしばらく podman-systemd、つまり Quadlet で運用してきたが、新しい k8s 亜種を見るたびに、追加の手間を引き受ける価値はないと感じた。古い Ansible プレイブックでイメージを事前に取得しておき、ユニットファイルを所定の場所に置くやり方で十分
    Voron 3D プリンタのスタック全体も podman-systemd で動かしており、全コンポーネントを一度に更新・ロールバックできるようにしている。ただし今は mkosisystemd-sysupdate でディスクイメージ全体を一括更新・ロールバックする方式も検討中
    主な問題は、人々がたいてい docker-compose ファイルだけを配布するため systemd ユニットに変換する必要があることと、一部の Docker イメージがユーザー・権限設定の面で Podman には不要な複雑さを持っていること。特にコンテナが root 実行を拒否したり別ユーザーに切り替えたりすると、面倒な userns ID マッピングが必要になる場合がある
    それでも全体としては、どんな k8s や k8s 亜種の設定よりはるかに複雑さが少ない。systemd と journald の両方に統合され、二か所に分かれない点も良い

    • 似たようなアプローチを何年も使っている: https://github.com/Mati365/hetzner-podman-bunjs-deploy。Podman と systemd ベースで、その間何も壊れていない
      ユニットを置くだけで済む方式なので、非常に安定していて単純
    • compose ファイルを Quadlet ファイルに変換するときは podlet を使える: https://github.com/containers/podlet
    • 結局これは単一ノード、または独立したノード群なのではないかと思う。Podman/systemd/Quadlet は k8s ノードがコンテナを実行する実装詳細、いわば CRI のようなものにはなり得る
      しかし k8s が提供する、複数ノード上でのオーケストレーション・スケジューリング抽象化の代替にはならない。「Podman-systemd ファイルを実行できるマシンがここにあり、実行したい仕様がここにあるので、あとはうまく配置してほしい」という部分が欠けている
    • 似た経験がある。ワークフローは、podman run コマンドでコンテナを立ち上げてみて、正しく動くことを確認した後、podlet で基本のコンテナファイルを作り、ボリュームとネットワークを別の Quadlet ファイルに分離する形でコンテナファイルを修正すれば終わり
      podman-compose プロジェクトも今なお活発にメンテナンスされているようで、docker-compose の良い代替になり得る。ただ、Podman と systemd の連携が非常に満足度が高い
  • これをさらに単純化する次の段階は、systemd の中で Quadlet によってコンテナを管理すること。詳しくは https://www.redhat.com/en/blog/quadlet-podman にある

    • Quadlet こそその道だ。コンテナを実行する方法として本当に良く、設定しておけば忘れていられる感じ。Fedora や Rocky Linux では、少なくとも追加パッケージをインストールする必要もない
    • 記事の終盤で触れられていたが、筆者はまだ見ていない状態だった。Podman の systemd 統合がすでに deprecated のように見え、今後は「Quadlet」ファイルでコンテナを定義しようという話が出ているので、後で学ぶべきものとして残しておいたということ
    • コメントを見に来た理由は、誰かが Quadlet に触れているか確認するためだった。先週ホームサーバーを docker compose から rootless Podman Quadlet に移行し、移行は大変だったが結果にはとても満足している
    • ホームラボを Quadlet へスムーズに移行するうえで、この記事も大いに役立った: https://news.ycombinator.com/item?id=43456934
  • skate を作った: https://github.com/skateco/skate。基本的にはこの目的のためのものだが、複数ホストをサポートし、k8s マニフェストにも対応している。内部的には Podman と systemd を使っている

    • このアプローチはとても気に入っている。複数ホストにまたがって Docker/Podman をシンプルに実行する方法がないのは本当に歯がゆい。Docker Swarm は残念ながら 2019 年以降、事実上放置された状態
      ただし 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 を実行し、実行中のプロセスだけを再起動すれば保護されること
      何かを再ビルドしたり、自分で作ったかもしれないしそうでないかもしれないコンテナの奥深くに埋もれたライブラリをどう更新するか探したりする必要がない
    • ごく単純なアプリケーションで同じ道を選んだ。systemd は意外に快適で、システムが割り当てたユーザーアカウントでサービスを最小権限で実行できる点がかなり良かった
      cgroup サポートのおかげで、1 台の VPS 上で複数サービスを動かすのにも向いている
    • 「大規模 YAML 管理」という問題領域に浪費された人間の寿命を考えると、めまいがする
  • この記事は1年以上前のものなので、今では systemd にはイミュータブルなワークフロー向けの公式対応 OS ディストリビューションである ParticleOS まである
    https://github.com/systemd/particleos
    https://news.ycombinator.com/item?id=43649088

    • 次の論理的なステップは Linux カーネルを 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台の箱に全部詰め込み、その箱を積極的にバックアップすれば終わり。自宅用途にマイクロサービス管理までは本当に必要ない

    • nginx といくつかのカスタムサービスだけを使っているが、要件がとても小さいのでそれで可能。少しでも複雑になったり、複数ノードを立てて 冗長性 が必要になったりすると、コンテナが非常に理にかなってくる