1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

再起動でコンテナが消える問題 — rc.local / systemd / ECS の使い分け

1
Posted at

はじめに

サーバーを再起動したら、docker compose up -d で立てたコンテナが全部消えていた——一度はやるミス。

# 再起動前は動いていた
docker compose up -d

# サーバー再起動後…
docker ps
# 何も出ない

Docker デーモン自体は起動時に戻ってくる。ではなぜコンテナは戻らないのか。

👉 docker compose up は「今このコンテナを起動する」という一度きりの指示。ホストを再起動すると、その指示は残っていない。

--restart を付ければいいと思うかもしれない:

# compose.yaml
services:
  app:
    image: myapp
    restart: always

これは Docker デーモンが再起動したときにはコンテナを復帰させる。しかし:

❌ restart: always だけでは足りない場面がある

  • compose ファイル一式(複数サービス・env・volume)の管理
  • 他サービスとの起動順・依存関係
  • 起動に失敗したときの検知とログ
  • そもそもクラウドのマネージド環境へ移す場合

この記事では「再起動してもコンテナを生かし続ける」手段を、次の3段階で整理する。

  1. rc.local — 古いやり方
  2. systemd unit file — 1台サーバーの現代的な正解
  3. AWS ECS — そもそも自動起動を意識しないマネージド

その前に:compose ファイルはどこに置くべきか

自動起動を仕込む前に、まず compose ファイルの置き場所 を決める。ここがぶれると、後で書く起動スクリプトの参照パスもぶれる。

推奨は /opt/<アプリ名>/ 配下:

/opt/myapp/
├── compose.yaml
├── .env
└── data/

/opt は「そのホストに後から入れたアプリ一式」を置く標準的な場所。root 所有で、システム全体のサービスとして扱いやすい。

❌ アンチパターン:ホームディレクトリに置く

/home/alice/myapp/compose.yaml   # 自動起動でハマりやすい
  • 自動起動は root 権限で走ることが多く、ユーザーの $HOME / PATH / 権限に依存すると起動時に詰まる
  • そのユーザーが消えたり権限が変わると動かなくなる
  • 「誰の環境か」に暗黙依存するのは本番向きではない

👉 開発中は手元で docker compose up するのでホーム配下でも動くが、自動起動に載せる段で必ず刺さる。

置き場所 用途 自動起動との相性
/opt/<app>/ 後から入れたアプリ一式(推奨) ◎
/srv/<app>/ そのホストが提供するデータ寄りのサービス ○
/home/<user>/ 開発・お試し ✗(本番では避ける)

以降は /opt/myapp/compose.yaml を前提に進める。


段階1:rc.local — 古いやり方

一番素朴なのは /etc/rc.local に起動コマンドを書く方法。起動の最後に一度だけ実行されるスクリプトだ。

# /etc/rc.local
#!/bin/bash

cd /opt/myapp && docker compose up -d

exit 0

実行権限が要る:

chmod +x /etc/rc.local

👉 動くには動く。しかし現代の systemd 環境では /etc/rc.local はデフォルトで無効で、rc-local.service という互換レイヤが拾ってくれるのに頼っている。ディストロによっては自分でこのサービスを有効化しないと動かない。

❌ rc.local の弱点

  • 依存関係を書けない:docker.service の起動完了を待たずに叩いて失敗することがある(起動レースの罠)
  • 失敗検知がない:docker compose up がコケてもどこにもまともに残らず、気づけない
  • 再起動ポリシーがない:一度失敗したら終わり。落ちても立て直さない
  • 停止処理がない:シャットダウン時に compose down 相当が走らない

「とりあえず動かす」には使えるが、本番のサービスをこれに載せるのは避けたい。次の systemd がほぼ全ての点で上位互換になる。


段階2:systemd unit file — 1台サーバーの正解

1台のサーバーで自動起動させるなら、rc.local ではなく systemd の unit ファイルを書く。rc.local の弱点がすべて埋まる。

# /etc/systemd/system/myapp.service
[Unit]
Description=myapp docker compose
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
Restart=on-failure

[Install]
WantedBy=multi-user.target

有効化して即起動:

systemctl daemon-reload
systemctl enable --now myapp

状態とログの確認:

systemctl status myapp
journalctl -u myapp -f

ポイントを分解する:

  • Requires=docker.service / After=docker.service:Docker が起動してから実行する。rc.local の起動レースが消える
  • WorkingDirectory=/opt/myapp:compose の場所をここで一元管理。ExecStart 側にパスを散らさない
  • ExecStop=... compose down:シャットダウン時にきれいに落とす
  • Restart=on-failure:失敗時に立て直す
  • journalctl -u myapp:ログが1か所に集まり、失敗が追える

👉 Type=oneshot + RemainAfterExit=yes は「up -d で起動して抜けるが、サービスとしては起動済み扱いにする」書き方。up -d を使わずフォアグラウンドで張り付かせる書き方もあるが、compose の up/down で組む方が停止処理まで自然に書ける。

rc.local との比較:

観点 rc.local systemd unit
Docker との起動順 書けない(レース) After=docker.service
失敗検知・ログ ほぼなし journalctl -u
再起動ポリシー なし Restart=
停止処理 なし ExecStop=
有効/無効の切替 手作業 systemctl enable/disable

👉 compose ファイルを /opt/myapp に固定し、WorkingDirectory で指すだけ。場所とサービス定義が素直に対応する。


段階3:AWS ECS — 自動起動を意識しない世界

規模が上がると発想が変わる。「ホストの再起動時に何をするか」を自分で書くのをやめる。

AWS ECS では、タスク定義(何をどう動かすか)と、サービスの desired count(何個動かし続けるか)をプラットフォームが維持する。

  • systemd の Restart= に相当するのが ECS サービススケジューラ。desired count を常に保とうとする
  • コンテナが落ちても、ホスト(EC2 / Fargate)が飛んでも、別の場所で立て直される
  • 「サーバーを再起動する」「起動時に何を実行する」という運用概念そのものが薄くなる

compose からの移行イメージ:

docker compose ECS
services: の1サービス タスク定義のコンテナ定義
restart: always サービスの desired count
depends_on / 起動順 タスク内依存・サービス設計
.env / environment: タスク定義の environment / Secrets
ホストの systemd unit (不要。スケジューラが担う)

❌ 誤解:「ECS なら全部楽になる」わけではない

  • VPC・サブネット・セキュリティグループなどネットワーク設計が要る
  • タスク実行ロール / タスクロールなど IAM の設計が要る
  • ログは CloudWatch 側の設定になる

👉 補足:昔あった docker compose の ECS 連携(Docker Compose CLI + ECS context)は非推奨。今は素直にタスク定義(や IaC)を書くのが基本。

つまり ECS は「起動を生かし続ける」という一点では自分で unit を書く必要がなくなる代わりに、別の設計コストを払う世界だ。


使い分けの早見表

観点 rc.local systemd unit AWS ECS
位置づけ 古い / 非推奨 1台サーバーの正解 マネージドの終着点
依存管理 書けない After / Requires サービス設計で吸収
失敗検知・ログ ほぼなし journalctl CloudWatch
再起動ポリシー なし Restart= desired count
ホスト障害からの復帰 不可 同一ホスト再起動のみ 別ホストで再スケジュール
運用コスト 低(だが脆い) 中 高(設計が要る)/ 運用は楽

まとめ

  • docker run --restart / restart: always は Docker デーモンの再起動には効くが、ホスト再起動や compose 一式の管理には不十分
  • compose ファイルは /opt/<app>/ に置き、ホーム配置は避ける。自動起動で刺さる
  • 1台サーバーなら rc.local ではなく systemd unit file を書く。依存(After)・ログ(journalctl)・再起動ポリシー(Restart=)・停止処理(ExecStop)が揃う
  • 規模が上がったら「自動起動を自分で書く」発想を捨てて ECS などマネージドへ。desired count がスケジューラに任せる形になる

👉 手段は「素朴だが脆い」→「1台で堅い」→「そもそも意識しない」と登っていく。今どの段にいるかで選べばよい。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?