systemdでDocker ComposeをLinuxサービスとして実行する

systemd によって管理される起動時の Docker Compose

目次

Linux サーバー上の Docker Compose は、ブート時に起動し、シャットダウン時にクリーンに停止し、手動介入なしで再起動に耐えられるべきです。

Docker Compose は Kubernetes ではありません。このガイドが対象とするワークロードにとって、それで十分です。多くの現実的なシステムにおいて、単一の Linux ホスト上の Compose プロジェクトは、適切なインフラストラクチャの規模です。シンプルで、読みやすく、バックアップが容易で、内部ツール、サイドプロジェクト、セルフホスト型サービス、ステージング環境、小規模な本番アプリ、開発者インフラストラクチャには十分に機能します。

docker compose config ont the table with laptop

通常欠けている要素は、サービス管理です。以下を手動で実行するだけでは不十分です。

docker compose up -d

この1つのコマンドはスタックを起動しますが、ブート時にスタックがどのように起動し、シャットダウン中に停止し、変更後にリロードし、ログを記録し、障害から回復し、安全に更新されるべきかについて文書化していません。そこで systemd が活躍します。

このガイドでは、Linux サービスとして Docker Compose プロジェクトを systemd と共に実行する方法を解説します。ユニットファイル、ブート順序、更新、ログ、バックアップについて説明します。責任の分離は意図的なものです。Docker はコンテナを実行し、Compose はスタックを定義し、systemd はホスト上のプロジェクトの起動と停止を行います。これは 開発ツール - 開発ワークフローガイド の一部です。

Docker Compose をサービスとして運用する場合

systemd 下で Compose を実行するのは、以下のような場合に意味があります。

  • 単一の Linux サーバー
  • 小規模なセルフホスト型アプリケーション
  • リバースプロキシスタック
  • モニタリングスタック
  • ローカル開発プラットフォーム
  • 内部ツール
  • ステージング環境
  • 制限が明確な単純な本番サービス

例:

  • Nginx Proxy Manager
  • Traefik
  • Gitea
  • Grafana と Prometheus
  • PostgreSQL と小規模なウェブアプリ
  • Uptime Kuma
  • Home Assistant のヘルパーサービス
  • プライベートレジストリ
  • 内部 API、ワーカー、Redis

Compose は、1人が1つのディレクトリを読むことで運用モデルを理解できる場合に適しています。

Docker Compose では不十分な場合

以下が必要な場合は、他のソリューションを使用してください。

  • マルチノードスケジューリング
  • ホスト間での自動スケジューリング
  • クラスターレベルのサービスディスカバリ
  • 水平オートスケーリング
  • 多数のマシンへのローリングデプロイ
  • 細粒度のワークロードアイデンティティ
  • 複雑なネットワークポリシー
  • 大規模なマルチチームプラットフォーム運用

その段階では、Kubernetes、Nomad、Swarm、またはマネージドプラットフォームの方が適しているかもしれません。

私の実践的なルールは、systemd を学ぶことを避けるために Kubernetes を使うのを避け、また複数のホスト間でのオーケストレーションが明らかに必要なワークロードで Compose を使うのを避けることです。

基本的なアーキテクチャ

クリーンなセットアップでは、プロジェクトファイル、systemd ユニット、ホスト上の永続データを分離します。Compose プロジェクトは /opt/myapp/ の下に存在し、compose.yaml.envdata/backups/、および scripts/update.sh などのオプションのスクリプトを含みます。systemd ユニットファイルは /etc/systemd/system/myapp.service に配置されます。

flowchart TB subgraph host["Linux host"] systemd["systemd unit\n/etc/systemd/system/myapp.service"] compose["Docker Compose\n/opt/myapp/compose.yaml"] docker["Docker Engine"] fs["Persistent data\n/opt/myapp/data/"] end systemd -->|"ExecStart: docker compose up -d"| compose compose --> docker docker --> fs

各レイヤーには明確な役割があります。Docker はコンテナを実行し、Compose はアプリケーションスタックを定義し、systemd はブートおよびシャットダウン時に Compose プロジェクトの起動と停止を行います。ホストファイルシステムは永続データを保存し、バックアップは明示的に保持され、更新はスクリプト化されたレビュー可能なステップを通じて行われます。このレイアウトは意図的に退屈なものです。なぜなら、退屈なインフラストラクチャは、午前2時に何か壊れたときに修理しやすいからです。

Compose プロジェクトディレクトリの準備

/opt の下にディレクトリを作成します。

sudo mkdir -p /opt/myapp
sudo chown -R "$USER":"$USER" /opt/myapp
cd /opt/myapp

Compose ファイルを作成します。

nano compose.yaml

例:

services:
  web:
    image: nginx:stable
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    healthcheck:
      test: ["CMD-SHELL", "nginx -t || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

volumes: {}

コンテンツディレクトリを作成します。

mkdir -p html
echo "Hello from Docker Compose" > html/index.html

まず手動でテストします。

docker compose up -d
docker compose ps
docker compose logs --tail=50

次に、ライフサイクルを systemd に引き継ぐ前に停止します。

docker compose down

Compose プロジェクトが手動で動作するまで、systemd サービスを作成しないでください。テスト中は pslogspull、およびプロジェクト構造のために Docker Compose チートシート を近くに置いておいてください。

最新の docker compose コマンドを使用する

ユニットファイルを書く前に、Docker Engine と Compose プラグインがインストールされている必要があります。Ubuntu では、Ubuntu に Docker をインストールする で APT、Snap、ルートレスモード、およびインストール後のセキュリティについて説明しており、機能する docker compose コマンドが得られるようになります。

これを使用します。

docker compose version

これではありません。

docker-compose version

古い docker-compose バイナリはまだ多くのマシンに存在しますが、最新の Docker は Compose を Docker CLI プラグインとして使用します。

サービスファイルおよびスクリプトでは、以下を優先します。

/usr/bin/docker compose

Docker パスは以下で見つけることができます。

command -v docker

通常は以下の通りです。

/usr/bin/docker

Docker Compose 用の systemd サービスを作成する

ユニットファイルがわからない場合は、Linux で任意の実行ファイルをサービスとして実行するTypeExecStartsystemctl、および一般的な systemd ワークフローについて説明しています。このセクションでは、これらのパターンを Compose スタックに特化して適用します。

サービスファイルを作成します。

sudo nano /etc/systemd/system/myapp.service

このユニットを使用します。

[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120

[Install]
WantedBy=multi-user.target

systemd をリロードします。

sudo systemctl daemon-reload

サービスを開始します。

sudo systemctl start myapp.service

ブート時に有効にします。

sudo systemctl enable myapp.service

ステータスを確認します。

systemctl status myapp.service

コンテナを確認します。

cd /opt/myapp
docker compose ps

なぜ Type=oneshot と RemainAfterExit=yes なのか?

多くのガイドで微妙に誤解されがちなのはここです。

docker compose up -d はデタッチモードでコンテナを起動し、終了します。そのため、systemd が監督する長時間実行されるフォアグラウンドの Compose プロセスはありません。systemd ユニットは docker compose up -d が長時間実行されるデーモンであると偽ってはいけません。

これを使用します。

Type=oneshot
RemainAfterExit=yes

これは systemd に以下を指示します。

  • スタートコマンドを実行する。
  • コマンドが正常に終了した後、ユニットをアクティブとみなす。
  • サービスが停止されたときに ExecStop を実行する。

これはデタッチされた Compose の実際の動作と一致するため、Type=oneshotRemainAfterExit=yes はほとんどのスタックにとって正しいデフォルトです。

なぜ Type=simple ではないのか?

Type=simple では、systemd は ExecStart プロセスが実行され続けることを期待しますが、docker compose up -d はコンテナを起動した後終了します。これにより、systemd はサービスが終了したと誤認し、設定に応じて停止ロジックを呼び出したり、ユニットを非アクティブとマークしたりする可能性があります。

Type=simple を使用したい場合は、通常 Compose をフォアグラウンドで実行します。

ExecStart=/usr/bin/docker compose up

これは機能しますが、サーバー上の Compose スタックには通常好んで使用しません。デタッチされたコンテナと明示的な ExecStop の方が運用が容易です。

より本番環境向けのユニット

実際のサーバーでは、少し厳格なユニットを好みます。

[Unit]
Description=MyApp Docker Compose stack
Documentation=https://example.com/docs/myapp
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
EnvironmentFile=-/opt/myapp/.env.systemd
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120

[Install]
WantedBy=multi-user.target

重要な詳細:

  • WorkingDirectory は Compose プロジェクトを指します。
  • ExecStartPre は Compose 設定を検証します。
  • ExecReload は変更されたサービスを再作成します。
  • ExecStop は Compose プロジェクトのコンテナとデフォルトネットワークを停止して削除します。
  • EnvironmentFile=-... はファイルがオプションであることを意味します。

オプションの systemd 環境ファイルを作成します。

nano /opt/myapp/.env.systemd

例:

COMPOSE_PROJECT_NAME=myapp

次に systemd をリロードします。

sudo systemctl daemon-reload
sudo systemctl restart myapp.service

Compose .env と systemd EnvironmentFile

Compose と systemd はそれぞれ独自の環境メカニズムを持っており、これらを混同するとブート時に「変数が設定されていません」という混乱するエラーが発生します。

Compose は、Compose ファイルの変数置換のためにプロジェクトディレクトリ内の .env ファイルを自動的に読み込みます。

.env:

APP_TAG=1.2.3
WEB_PORT=8080

compose.yaml:

services:
  web:
    image: nginx:${APP_TAG}
    ports:
      - "${WEB_PORT}:80"

systemd の EnvironmentFiledocker compose コマンド自体の環境変数を設定します。

例:

EnvironmentFile=-/opt/myapp/.env.systemd

多くのプロジェクトでは、Compose .env だけで十分です。

以下のようなものを定義したい場合に systemd 環境ファイルを使用します。

COMPOSE_PROJECT_NAME=myapp
COMPOSE_FILE=compose.yaml
DOCKER_HOST=unix:///var/run/docker.sock

どちらのファイルもカジュアルなシークレット保管庫として使用しないでください。シークレットが重要な場合は、Docker シークレット、外部シークレットマネージャー、暗号化されたファイル、または少なくとも厳格な権限を使用してください。

制限的な権限を設定します。

chmod 600 /opt/myapp/.env
chmod 600 /opt/myapp/.env.systemd

再起動ポリシー: Docker と systemd

再起動ポリシーには2つのレイヤーがあります。Compose 内のコンテナ再起動ポリシーと systemd サービス再起動ポリシーであり、これらを盲目的に混用しないでください。

長時間実行されるコンテナの場合、Compose で再起動ポリシーを設定します。

services:
  web:
    image: nginx:stable
    restart: unless-stopped

一般的な再起動値:

ポリシー 意味
no 自動的に再起動しない
always 終了後およびデーモン再起動後に再起動
on-failure 失敗後にのみ再起動
unless-stopped 手動で停止されない限り再起動

ほとんどの永続サービスでは、以下を好みます。

restart: unless-stopped

予測可能で、意図的な手動停止を尊重します。

systemd ユニット自体は通常繰り返し再起動すべきではありません。なぜなら docker compose up -d は実行中のワークロードではないからです。コンテナがそうなのです。

したがって、特定の理由がない限り、以下を避けてください。

Restart=always

ほとんどの Compose-as-service ユニットでは、コンテナの再起動を Docker に任せてください。

ヘルスチェック

再起動ポリシーはプロセスが終了したときにコンテナを再起動します。しかし、すべての不健康なアプリケーションを魔法のように修正するわけではありません。

役立つ場所にヘルスチェックを追加します。

services:
  app:
    image: example/app:latest
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s

ヘルスを確認します。

docker compose ps

コンテナを検査します。

docker inspect container-name

ヘルスチェックは以下に特に有用です。

  • ウェブアプリ
  • リバースプロキシ
  • データベース
  • キュー
  • 内部 API
  • ヘルスエンドポイントを持つワーカー

プロセスが存在することのみをチェックする場合、それらはあまり有用ではありません。なぜなら、生きていますが固まっているプロセスは依然として健全に見えるからです。悪いヘルスチェックは単に YAML における別の嘘です。

スタートアップ順序と depends_on

Compose は依存関係を定義できます。

services:
  app:
    image: example/app:latest
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

これはスタートアップ順序の助けになりますが、過度に信頼しないでください。アプリケーションは依然としてリトライを処理する必要があります。データベースは再起動し、ネットワークは不安定になり、DNS には時間がかかります。強靭なアプリは、完璧なスタートアップ順序を仮定するのではなく、接続をリトライします。

ログ: journalctl と docker compose logs

2つのログビューがほとんどのデバッグをカバーします。systemd はユニット自体のライフサイクルをキャプチャし、Compose は実行中のコンテナからのアプリケーション出力をキャプチャします。

systemd サービスログ:

journalctl -u myapp.service -n 100 --no-pager

systemd ログを追従します。

journalctl -u myapp.service -f

Compose サービスログ:

cd /opt/myapp
docker compose logs --tail=100
docker compose logs -f
docker compose logs -f web

ほとんどのアプリデバッグでは docker compose logs の方が有用ですが、ライフサイクルデバッグ — 起動障害、ユニットクラッシュ、権限エラー — では journalctl の方が有用です。systemctl start myapp が失敗した場合は、まず journalctl をチェックしてください。スタックが起動したがアプリが破損している場合は、docker compose logs をチェックしてください。

ログローテーション

設定しないと、Docker ログは永遠に増大します。

小規模なサーバーの場合、/etc/docker/daemon.json で Docker ログローテーションを設定します。

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Docker を再起動します。

sudo systemctl restart docker

次に Compose スタックを再起動します。

sudo systemctl restart myapp.service

これは新しく作成されたコンテナに適用されます。必要に応じてコンテナを再作成します。

cd /opt/myapp
docker compose up -d --force-recreate

ログローテーションは派手ではありませんが、小規模なサーバーでのディスクフル障害を防ぐ最も簡単な方法の1つです。

Compose サービスの更新

単純な手動更新フロー:

cd /opt/myapp
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f

systemd によって管理されている場合は、以下を使用できます。

sudo systemctl reload myapp.service

ユニットに以下がある場合:

ExecReload=/usr/bin/docker compose up -d --remove-orphans

ただし、ExecReload はそのステップを含めない限りイメージをプルしないことに注意してください。

明示的な更新のために、スクリプトを作成します。

mkdir -p /opt/myapp/scripts
nano /opt/myapp/scripts/update.sh

スクリプト:

#!/usr/bin/env bash
set -euo pipefail

cd /opt/myapp

docker compose config --quiet
docker compose pull
docker compose up -d --remove-orphans
docker image prune -f
docker compose ps

実行可能にします。

chmod +x /opt/myapp/scripts/update.sh

実行します。

/opt/myapp/scripts/update.sh

その後、サービスユニットはライフサイクルに集中し、更新スクリプトがデプロイを処理します。

バックアップフック付きのより安全な更新スクリプト

ステートフルなサービスの場合、バックアップ後にのみ更新します。

#!/usr/bin/env bash
set -euo pipefail

APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/myapp/backups"

cd "$APP_DIR"

mkdir -p "$BACKUP_DIR"

echo "Validating compose file"
docker compose config --quiet

echo "Running backup hook"
if [ -x "$APP_DIR/scripts/backup.sh" ]; then
  "$APP_DIR/scripts/backup.sh"
else
  echo "No backup hook found"
fi

echo "Pulling images"
docker compose pull

echo "Recreating services"
docker compose up -d --remove-orphans

echo "Pruning unused images"
docker image prune -f

echo "Current status"
docker compose ps

これは依然としてシンプルですが、今や運用習慣をエンコードしています:変更前にバックアップ。

サービスの停止

スタックを停止します。

sudo systemctl stop myapp.service

これにより以下が実行されます。

docker compose down

デフォルトでは、docker compose down は以下を削除します。

  • Compose ファイル内のサービスのコンテナ
  • Compose ファイルで定義されたネットワーク
  • デフォルトネットワーク

名前付きボリュームを要求しない限り、削除しません。

以下をカジュアルに使用しないでください。

docker compose down -v

これにより、Compose ファイルで宣言された名前付きボリュームとコンテナに接続された匿名ボリュームが削除されます。データベースやステートフルなアプリの場合、これは実際のデータの削除を意味する可能性があります。

down -v は「この環境を破壊する」と意図する場合にのみ使用してください。

サービスの再起動

systemd ユニットを再起動します。

sudo systemctl restart myapp.service

これにより停止コマンドが実行され、その後開始コマンドが実行されます。

コンテナを再作成せずに再起動するのみ:

cd /opt/myapp
docker compose restart

重要な違い:

  • docker compose restart は既存のコンテナを再起動します。
  • docker compose up -d は必要に応じてコンテナを再作成して設定またはイメージの変更を適用します。

compose.yaml を変更した場合は、以下を使用します。

docker compose up -d

以下のみではありません。

docker compose restart

孤立コンテナの処理

compose.yaml でサービスの名前を変更または削除した場合、古いコンテナが孤立として残る可能性があります。

これを使用します。

docker compose up -d --remove-orphans

このガイドの systemd サービスの例が以下を使用する理由です。

ExecStart=/usr/bin/docker compose up -d --remove-orphans

これにより、スタックは現在の Compose ファイルに近づきます。

バックアップ

バックアップはワークロードに依存しますが、原則は安定しています。

バインドマウントの場合:

/opt/myapp/data/

そのディレクトリをバックアップします。

名前付きボリュームの場合:

docker volume ls

ボリュームを検査します。

docker volume inspect volume-name

データベースの場合、ファイルシステムのコピーだけでは十分ではありません。アプリケーション対応のバックアップを使用します。

PostgreSQL の例:

docker compose exec -T db pg_dump -U postgres appdb > backups/appdb.sql

MariaDB の例:

docker compose exec -T db mariadb-dump -u root -p appdb > backups/appdb.sql

Redis の例:

docker compose exec redis redis-cli BGSAVE

バックアッププランのない Compose スタックはサービスではありません。アップタイムがある一時的な実験に過ぎません。

セキュリティベースライン

Linux 上の小規模な Compose サービスの場合、このベースラインから始めます。

  • Compose プロジェクトを /opt/appname の下に保つ。
  • 安定性が重要な場合は、latest だけでなく明示的なイメージタグを使用する。
  • バインドマウントまたは名前付きボリュームを意図的に使用する。
  • 必要ないポートを公開しない。
  • パブリックサービスをリバースプロキシの背後に置く。
  • エッジで HTTPS を使用する。
  • Git からシークレットを外す。
  • .env の権限を制限する。
  • 真に必要でない限り、特権コンテナを避ける。
  • コンテナに Docker ソケットをマウントしない。
  • Docker とイメージを更新する。
  • 別のマシンからファイアウォールの動作をテストする。

危険なパターン:

volumes:
  - /var/run/docker.sock:/var/run/docker.sock

これにより、コンテナが Docker の制御を得ます。実際には、ホストレベルの制御になる可能性があります。リスクを理解している場合にのみ使用してください。

リソース制限

小規模なサーバーでは、1つの悪いコンテナがホストを消費する可能性があります。

Compose はリソース関連の設定をサポートしていますが、動作は Docker Engine と Compose のバージョンに依存する場合があります。単純な保護のために、アプリケーションレベルの制限と Docker ログ制限から始めます。

一部のワークロードでは、メモリ制限を追加できます。

services:
  app:
    image: example/app:stable
    restart: unless-stopped
    mem_limit: 512m

また、アプリケーションレベルのワーカー数、キュー制限、キャッシュサイズも設定します。コンテナ制限は有用ですが、アプリケーションを理解する替代品ではありません。

例: 現実的な Compose サービス

ディレクトリ:

/opt/whoami/
  compose.yaml
  .env

Compose ファイル:

services:
  whoami:
    image: traefik/whoami:v1.10
    restart: unless-stopped
    ports:
      - "${WHOAMI_PORT}:80"
    healthcheck:
      test: ["CMD-SHELL", "wget -qO- http://localhost || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 3

.env ファイル:

WHOAMI_PORT=8080
COMPOSE_PROJECT_NAME=whoami

systemd ユニット:

[Unit]
Description=Whoami Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/whoami
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120

[Install]
WantedBy=multi-user.target

インストールします。

sudo systemctl daemon-reload
sudo systemctl enable --now whoami.service

テスト:

curl http://localhost:8080

ステータスを確認します。

systemctl status whoami.service
cd /opt/whoami
docker compose ps

トラブルシューティング

サービスが起動するがコンテナが実行されていない

systemd を確認します。

journalctl -u myapp.service -n 100 --no-pager

Compose を検証します。

cd /opt/myapp
docker compose config

Docker を確認します。

systemctl status docker
docker info

WorkingDirectory が間違っている

systemd が Compose ファイルを見つけられない場合は、以下を確認します。

WorkingDirectory=/opt/myapp

次に確認します。

ls -la /opt/myapp
ls -la /opt/myapp/compose.yaml

サービスは現在のシェルディレクトリではなく WorkingDirectory から実行されます。

Docker 権限拒否

ユニットがルートとして実行される場合、通常 Docker にアクセスできます。

User=someuser を設定した場合、そのユーザーは Docker にアクセスできる必要があります。通常、これは docker グループのメンバーシップ、またはルートレス Docker セットアップを意味します。

確認します。

groups someuser

適切であればユーザーを追加します。

sudo usermod -aG docker someuser

注意が必要です。Docker グループは実質的に特権的です。

Compose コマンドが見つからない

Docker を探します。

command -v docker

ユニットでフルパスを使用します。

ExecStart=/usr/bin/docker compose up -d --remove-orphans

Compose プラグインが欠落している場合:

docker compose version

Docker パッケージソースを使用してインストールします。

環境変数が不足している

systemd がどのように見えるか Compose 設定を確認します。

cd /opt/myapp
docker compose config

systemd に追加の環境変数が必要な場合は、以下を使用します。

EnvironmentFile=-/opt/myapp/.env.systemd

Compose に置換用の変数が必要な場合は、以下を使用します。

/opt/myapp/.env

これらは関連していますが、同一ではありません。

再起動後にコンテナが起動しない

systemd サービスが有効になっているか確認します。

systemctl is-enabled myapp.service

有効にします。

sudo systemctl enable myapp.service

Docker を確認します。

systemctl is-enabled docker
systemctl status docker

ブートログを確認します。

journalctl -u myapp.service -b --no-pager

アプリがデータベース準備完了前に起動する

データベースヘルスチェックと service_healthy 付きの depends_on を追加します。

また、アプリケーションも修正します。データベース接続をリトライするべきです。インフラストラクチャのスタートアップ順序は役立ちますが、アプリケーションのリトライロジックの方が優れています。

Docker ログでディスクが埋め尽くされる

Docker のディスク使用量を確認します。

docker system df

大きなコンテナログを確認します。

sudo du -h /var/lib/docker/containers | sort -h | tail

/etc/docker/daemon.json で Docker ログローテーションを設定します。

次にコンテナを再作成します。

一般的な間違い

間違い 1: rc.local で docker compose up を実行する

rc.local またはログインスクリプトから docker compose up を実行するのは、機能しなくなるまで機能します。代わりに適切な systemd ユニットを使用してください。

間違い 2: systemd で Restart=always と Compose で restart: always を使用する

通常、Compose でコンテナ再起動ポリシーのみが必要です。2つのスーパーバイザーが互いに戦うのを避けてください。

間違い 3: –remove-orphans を忘れる

サービスの名前変更と削除により、古いコンテナが残る可能性があります。以下を使用します。

docker compose up -d --remove-orphans

間違い 4: 設定変更後に docker compose restart を使用する

restart はコンテナを再起動します。すべての設定変更を適用しません。

以下を使用します。

docker compose up -d

間違い 5: 考えずに down -v を実行する

これによりボリュームが削除される可能性があります。ステートフルなサービスの場合、これはデータの削除を意味する可能性があります。

間違い 6: Pull 前にバックアップなし

新しいイメージは壊れる可能性があります。データベースはマイグレーションする可能性があります。タグは移動する可能性があります。まずバックアップしてください。

間違い 7: すべてのポートを公開する

ホストが公開する必要があるもののみを公開してください。内部サービス間のトラフィックは Compose ネットワーク上にとどまることができます。

最終的な推奨パターン

ほとんどの単一ホスト Linux サービスの場合、このパターンを使用します。

Compose ファイル:

services:
  app:
    image: example/app:stable
    restart: unless-stopped
    ports:
      - "8080:8080"
    env_file:
      - .env

systemd ユニット:

[Unit]
Description=MyApp Docker Compose stack
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/docker compose config --quiet
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecReload=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
TimeoutStopSec=120

[Install]
WantedBy=multi-user.target

有効にします。

sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service

運用します。

sudo systemctl status myapp.service
sudo systemctl restart myapp.service
journalctl -u myapp.service -f
cd /opt/myapp && docker compose logs -f

このパターンは派手ではありません。それがポイントです。Docker Compose は小規模で理解しやすいシステムに優れ、systemd はホストサービスの起動と停止に優れており、共にすべてのプロジェクトにクラスターが必要であると偽ることなく、信頼性の高い単一サーバーデプロイモデルを提供します。Compose 外でのコンテナレベルのコマンド — イメージ、ボリューム、ネットワーク、およびクリーンアップ — については、Docker チートシート を参照してください。

購読する

システム、インフラ、AIエンジニアリングの新記事をお届けします。