Docker Composeからk3sへ移るべきか――30個のセルフホストアプリを移行して分かった境界線
2026-07-15
Docker Composeからk3sへ移るべきか――30個のセルフホストアプリを移行して分かった境界線のカバー画像

セルフホストを続けていると、どこかで「Docker Composeのままでよいのか」「そろそろKubernetesへ移るべきか」と考える瞬間がきます。

私も、最初はDocker Composeで十分だと思っていました。実際、数個のアプリを動かすだけなら、Composeは分かりやすく、復旧もしやすく、運用コストも低い優れた選択肢です。

しかし、動かすアプリが増え、認証、監視、バックアップ、証明書、更新、Secret管理まで考えるようになると、Composeファイルを増やすだけでは整理しきれない部分が出てきました。

私は最終的に、約30個のセルフホストアプリをDocker Compose中心の構成からk3sへ移しました。

移行後は、Traefik、Argo CD、Forgejo、Longhorn、OpenBao、External Secrets、Prometheus、Grafanaなどを組み合わせて運用しています。ただし、先に結論を書くと、k3sへ移ったからセルフホストが簡単になったわけではありません。

むしろ覚えることは増えました。

それでも移行してよかったのは、増え続けていた複雑さを、Git、宣言的設定、共通基盤という形で整理できるようになったからです。

この記事では、Docker Composeのままでよい人と、k3sへ移る価値がある人の境界線を、実際に移行した経験から整理します。

記事確認日: 2026年7月15日

先に結論

Docker Composeからk3sへ移るべきかは、アプリ数だけでは決まりません。

私は、次のように考えています。

Docker Composeのままでよい人

  • 動かしているアプリが数個から10個程度
  • 1台のサーバーで完結している
  • 更新は月に数回でよい
  • 障害時はSSHで入り、手動で直せればよい
  • GitOpsや自動更新を必要としていない
  • Kubernetes自体を学ぶことが目的ではない

k3sを検討する価値がある人

  • アプリごとに異なるComposeファイルや手順が増えてきた
  • 証明書、Ingress、認証、監視を共通化したい
  • 設定変更やデプロイ履歴をGitに残したい
  • SecretをComposeファイルや.envから切り離したい
  • 複数ノードやローリングアップデートを使いたい
  • 壊れたときに、手作業ではなく宣言した状態へ戻したい
  • Kubernetesの運用そのものを楽しめる

大切なのは、k3sは小さなDocker Composeではなく、運用方法そのものを変える仕組みだということです。

Composeの延長として考えると、移行後に苦労します。

Docker Composeは、かなり優秀

k3sへ移行した記事で最初に書くことではないかもしれませんが、Docker Composeは非常に優れています。

例えば、次のような構成なら、無理にKubernetesへ移る必要はありません。

VPS 1台
├─ reverse-proxy
├─ blog
├─ database
├─ monitoring
└─ backup

compose.yaml.env、データディレクトリ、バックアップ手順が整理されていれば、十分に実用的です。

Composeの強みは、構成と実際のプロセスの距離が近いことです。

docker compose up -d
docker compose logs -f
docker compose pull
docker compose restart

これらのコマンドを覚えれば、多くのトラブルに対応できます。

コンテナが動かなければ、同じサーバーへSSHで入り、ログを見て、設定を直して再起動する。小規模なセルフホストでは、この分かりやすさが大きな利点です。

一方、KubernetesではDeployment、Service、Ingress、PersistentVolumeClaim、Secret、ConfigMapなど、同じアプリを動かすために扱う概念が増えます。

そのため、アプリが少ないうちは、k3sのほうが明らかに複雑です。

私がDocker Composeで苦しくなった理由

私の場合、問題はアプリの起動そのものではありませんでした。

Composeでも、アプリは問題なく動きます。

苦しくなったのは、アプリの外側にある運用です。

1. アプリごとに更新方法が違う

あるアプリはイメージタグを書き換えて再起動する。

別のアプリは、更新前にDB dumpが必要。

別のアプリは、設定ファイルの形式が変わる。

さらに別のアプリは、特定の順序でコンテナを停止する必要がある。

アプリが増えるほど、「どのファイルを直し、どのコマンドを実行し、どこまで確認したか」が人間の記憶に依存していきました。

2. reverse proxyの設定が集中する

外部公開するアプリが増えると、ドメイン、TLS、ミドルウェア、認証、IP制限などの設定も増えます。

Compose環境でも共通のreverse proxyを使えますが、各アプリの設定とproxy側の設定が分かれ、変更時に複数箇所を確認する必要がありました。

3. .envとSecretが増える

最初は.envで十分です。

しかし、DBパスワード、OIDCクライアントSecret、APIトークン、バックアップ先の認証情報などが増えると、「どこに何があるか」「どのバックアップに含まれているか」が分かりにくくなります。

ファイルの権限を厳しくしても、Secretの配布、更新、ローテーションは別問題です。

4. サーバーの状態が正本になる

ComposeファイルをGitに置いていても、実際のサーバー側にだけ存在する設定や修正が増えることがあります。

  • 手動で作成したディレクトリ
  • サーバー上で直接編集した設定
  • 一度だけ実行した初期化コマンド
  • 書き残していないネットワーク設定
  • 手動で追加したcron

この状態になると、Gitから同じ環境を再現できません。

動いているサーバーそのものが正本になります。

5. 復旧手順が長くなる

障害時に必要なのは、コンテナを起動することだけではありません。

DB、画像、設定、証明書、Secret、DNS、依存サービスを正しい順序で戻す必要があります。

アプリが増えると、復旧はdocker compose up -dでは終わらなくなりました。

k3sへ移って変わったこと

k3sへ移行して一番変わったのは、コンテナの動かし方ではなく、変更の入口です。

Docker Composeでは、サーバーへ入り、ファイルを書き換え、コマンドを実行することが多くありました。

現在は、基本的にGitを変更の入口にしています。

Gitへ変更をpush
      ↓
Argo CDが差分を検知
      ↓
クラスタを宣言した状態へ同期

アプリの更新、設定変更、replicasの変更、Ingressの追加などをGit上の差分として扱えるようになりました。

誰が変更したかという問題は個人運用では重要ではありません。しかし、自分が数か月前に何を変更したかを追えることには大きな価値があります。

Gitが「こうあるべき」の正本になる

manifestとKustomizeの設定をGitへ置き、Argo CDから同期しています。

これにより、実際のクラスタに手動変更を加えても、Gitとの差分として検出できます。

クラスタ側だけを変更して、そのまま忘れる状態を減らせました。

ただし、Gitだけでクラスタ全体を復元できるわけではありません。

DBや画像、PersistentVolumeの中身、Secretの正本は別途バックアップが必要です。GitOpsはバックアップの代わりではありません。

Ingressと証明書を共通化できる

外部公開するアプリは、Traefikとcert-managerを共通で利用しています。

各アプリは「どのServiceを、どのホスト名で公開するか」をmanifestで宣言します。

Compose環境でも同じことはできますが、KubernetesではServiceとIngressという共通の形に揃うため、新しいアプリを追加したときの考え方が統一されました。

Secretの置き場所を分けられる

現在は、Secretの正本をOpenBaoに置き、External Secrets Operatorを通してKubernetes Secretへ展開しています。

これにより、Gitには「どのSecretを参照するか」だけを書き、値そのものは置かない形にできます。

もちろん、この仕組み自体が新たな依存関係です。

OpenBaoやExternal Secretsが壊れれば、Secretを必要とするアプリの復旧にも影響します。導入しただけで安全になるわけではなく、認証基盤そのもののバックアップと復旧手順が必要です。

更新を段階的に反映できる

Deploymentを使えば、新しいPodがReadyになった後に古いPodを停止するローリングアップデートを設定できます。

replicasが1でも、更新方法を適切に設定すれば、デプロイ時の停止時間を小さくできます。

Composeでも工夫はできますが、Kubernetesでは更新戦略が標準機能として用意されています。

監視方法を揃えやすい

各アプリのPod、Node、ストレージ、Ingressなどを同じ監視基盤で確認できます。

Prometheus、Grafana、Lokiなどを共通基盤として使うことで、「このアプリだけログの見方が違う」という状態を減らせました。

ただし、監視対象が増えることで、監視基盤そのものも運用対象になります。

k3sへ移って増えたもの

良くなった点だけを書くと、移行判断を誤ります。

k3sへ移行すると、確実に増えるものがあります。

1. 学ぶ概念

最低限でも、次の概念を理解する必要があります。

  • Pod
  • Deployment
  • StatefulSet
  • Service
  • Ingress
  • ConfigMap
  • Secret
  • PersistentVolume
  • PersistentVolumeClaim
  • Namespace
  • RBAC
  • StorageClass
  • Job
  • CronJob

さらにGitOps、Secret管理、証明書管理、ストレージを入れると、CRDとOperatorも増えます。

問題が起きたときには、アプリのログだけでなく、Controller、イベント、Service、DNS、Volume、Ingressまで確認する必要があります。

2. 壊れる層

Composeでは、主にアプリ、Docker、ホストOSを見れば済みます。

k3sでは、その間に多くの層が入ります。

アプリ
↓
Pod
↓
Service
↓
Ingress
↓
CNI
↓
Node
↓
ストレージ

例えば、アプリが開かない原因が、アプリ自身ではなくServiceのselector、Ingressの設定、証明書、クラスタDNS、ネットワーク、Volumeのattach失敗ということもあります。

3. 循環依存

GitOpsを導入すると、Gitがクラスタを復元するための正本になります。

しかし、そのGitサーバー自体を同じクラスタ内で動かすと、クラスタが壊れたときにGitへアクセスできません。

Secret管理、コンテナレジストリ、認証基盤についても同様です。

便利な基盤をクラスタ内へ集めるほど、「その基盤を戻すために、その基盤が必要」という循環依存が生まれます。

私は現在もクラスタ内にForgejoやOpenBaoなどを置いていますが、外部ミラー、バックアップ、bootstrap手順を別に用意しています。

4. バックアップ対象

Kubernetesではmanifestを保存しているだけでは不十分です。

最低でも、次を分けて考える必要があります。

  • Gitにあるmanifest
  • DB dump
  • PersistentVolume内の実データ
  • 画像や添付ファイル
  • Secretの正本
  • コンテナイメージ
  • クラスタ外のDNSや証明書関連設定
  • 復元順序

k3sへ移るとバックアップが自動的に良くなるのではなく、バックアップすべき対象が明確になるだけです。

アプリ数より重要な移行判断のサイン

「何個を超えたらk3s」と単純には決められません。

私が移行を検討するサインだと思うのは、次の状態です。

サーバーへ直接入る作業が増えた

更新や設定変更のたびにSSHし、複数のディレクトリを移動しているなら、変更経路が人間の操作に依存しています。

ただし、Ansibleなどで整理する方法もあります。SSHが多いから即Kubernetes、ではありません。

同じ仕組みを各アプリで繰り返している

証明書、監視、認証、バックアップ、ログ収集などをアプリごとに個別設定しているなら、共通基盤にまとめる価値が出てきます。

複数ノードを使いたい

単一サーバーなら、Composeの単純さが強みです。

複数ノードへアプリを配置したい、ノード停止時に別ノードで再起動したい、ストレージも含めてクラスタとして扱いたい場合は、Kubernetesの利点が大きくなります。

ただし、複数ノードにしただけでは高可用性にはなりません。

DB、ストレージ、ロードバランサー、DNS、外部回線まで含めて考える必要があります。

Gitを唯一の変更入口にしたい

「サーバー上の状態ではなく、Gitに書かれた状態を正本にしたい」という要求は、k3sへ移る強い理由になります。

GitOpsは必須ではありませんが、Kubernetesと相性がよい運用方法です。

Kubernetesを学ぶこと自体に価値がある

趣味や学習目的なら、アプリが少なくても移行する意味はあります。

私自身、最初から最短の運用だけを求めていたわけではありません。仕組みを理解し、自分で設計してみることもセルフホストの目的に含まれていました。

反対に、インフラを学びたいわけではなく、アプリを使いたいだけなら、k3sは遠回りになりやすいです。

移行するなら、最初から全部移さない

Docker Composeからk3sへ移るとき、最初から重要なデータを持つアプリを移すのはおすすめしません。

私は、次の順序が安全だと考えています。

1. データ移行が容易なアプリ

最初は、壊れても再作成しやすいアプリを選びます。

  • 静的なWebアプリ
  • Stirling-PDFのような処理系ツール
  • FreshRSSなど、エクスポート手段が明確なアプリ
  • テスト用の小さなサービス

ここでDeployment、Service、Ingress、ConfigMap、Secretの基本を覚えます。

2. 監視と証明書

次に、cert-manager、監視、ログ収集など、複数アプリで使う基盤を整えます。

ただし、最初からすべて入れる必要はありません。

トラブル時に見る場所が増えすぎるため、使う理由が明確になったものから追加するほうが安全です。

3. DBを持つが、復元しやすいアプリ

DB dumpと復元テストを行ったうえで移します。

「バックアップを取った」ではなく、別のDBへ戻して読めることまで確認します。

4. 写真やファイルを持つアプリ

ImmichやNextcloudのように、DBと実ファイルの両方が重要なアプリは後にします。

PVだけ、DBだけを保存しても完全には戻りません。

復元順序を確認してから移すべきです。

5. Git、Secret管理、認証基盤

Forgejo、OpenBao、OIDC認証基盤など、他のアプリを支えるものは最後です。

便利ですが、壊れたときの影響が大きく、循環依存も生みやすいためです。

Docker Composeとk3sを比較すると

観点 Docker Compose k3s
導入の簡単さ 非常に簡単 学習が必要
小規模運用 強い 過剰になりやすい
構成の見通し ファイル数が少ないうちは良い リソースは多いが形式を統一できる
更新 手動でも分かりやすい 宣言的更新とローリング更新が可能
GitOps 工夫が必要 相性がよい
複数ノード 基本的に別途設計 スケジューリング機能を持つ
Secret管理 .envや外部ツール Secretや外部Secret管理と統合しやすい
ストレージ ホスト上の場所が分かりやすい 抽象化される分、障害解析が難しい
障害対応 層が少ない 確認すべき層が多い
復旧 手順が短ければ簡単 宣言的に戻せるがbootstrapが必要
運用コスト 低い 高い
学習価値 Docker運用 Kubernetes、GitOps、クラウドネイティブ運用

私の結論

約30個のセルフホストアプリを移行した現在も、すべての人にk3sをすすめるつもりはありません。

むしろ、次のように考えています。

アプリを使うことが目的なら、Docker Composeのままのほうがよいことが多い。

増えた運用を共通の仕組みで整理したい、Gitを正本にしたい、Kubernetesそのものを学びたいなら、k3sへ移る価値がある。

k3sは、セルフホストの複雑さを消してくれる仕組みではありません。

アプリ、ネットワーク、ストレージ、Secret、更新、監視といった複雑さを、Kubernetesのルールの中へ移し替える仕組みです。

そのルールを理解できれば、数十個のアプリを同じ考え方で管理できます。

理解しないまま使うと、Composeよりも壊れ方が分かりにくい環境になります。

私にとって移行の境界線は、アプリ数が30個になったことではありませんでした。

動いているサーバーの状態を覚えて管理することに限界を感じ、Gitに書かれた状態から戻せる運用へ変えたくなったことが、本当の移行理由でした。

Docker Composeで運用が整理できているなら、そのままで問題ありません。

Composeファイルの外側にある手作業、共通設定、依存関係、復旧手順が増え続けているなら、k3sを検討する時期かもしれません。

Docker Composeからk3sへ移るべきか――30個のセルフホストアプリを移行して分かった境界線
http://notes.midnightstops.com/posts/37/
作者
kairo
公開日
2026-07-15