はじめに
Rails + Docker 環境で開発していると、次のようなエラーに出会うことがあります。
$ docker compose exec web bin/rails generate xxxxx
service "web" is not running
「え、さっきまで動いていたはずでは?」
Docker・Rails を勉強し始めた頃は、どこを見ればいいのか分からず詰まりがちですよね。
この記事では、
- なぜこのエラーが出たのか
- どこを見て原因を特定したのか
- 同じ状況になったときの考え方
を、Rails(Docker)前提で整理します。
結論から言うと
docker compose exec web は、web コンテナが起動していないと実行できません。
今回は「ポート競合」が原因で、web コンテナが起動に失敗していました。
本当にwebコンテナが起動しているか?
まずは思い込みを捨てて事実確認。
docker compose ps で確認
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
フォルダ名-chrome-1 seleniarm/standalone-chromium:latest "/opt/bin/entry_poin…" chrome 12 seconds ago Up 10 seconds 0.0.0.0:4444->4444/tcp, [::]:4444->4444/tcp
フォルダ名-db-1 mysql:5.7 "docker-entrypoint.s…" db 12 seconds ago Up 10 seconds 0.0.0.0:3307->3306/tcp, [::]:3307->3306/tcp
この時点で分かること:
- chrome / db は起動している
- web が存在しない(=起動していない)
web が起動しない理由を調べる
docker compose upして、起動ログを見てみます。
$ docker compose up
[+] Running 4/4
✔ Network フォルダ名_default Created 0.0s
✔ Container フォルダ名-db-1 Created 0.1s
✔ Container フォルダ名-chrome-1 Created 0.1s
✔ Container フォルダ名-web-1 Created 0.3s
Attaching to chrome-1, db-1, web-1
db-1 | 2026-01-24 14:30:14+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.44-1.el7 started.
chrome-1 | 2026-01-24 05:30:15,032 INFO Included extra file "/etc/supervisor/conf.d/selenium.conf" during parsing
chrome-1 | 2026-01-24 05:30:15,038 INFO RPC interface 'supervisor' initialized
chrome-1 | 2026-01-24 05:30:15,038 CRIT Server 'unix_http_server' running without any HTTP authentication checking
chrome-1 | 2026-01-24 05:30:15,059 INFO supervisord started with pid 8
Gracefully Stopping... press Ctrl+C again to force
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint フォルダ名-web-1 (17cd568c21f6c0c93c7256dfe2d33a4ea429d12765e4b31d0064300af1092d0d): Bind for 0.0.0.0:3000 failed: port is already allocated
勉強し始めのときは、何が書いてあるのか、どこを読めばいいのかわからないですよね。
ここで注目するのが、Errorと書いてある一番下の行。
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint フォルダ名-web-1 (17cd568c21f6c0c93c7256dfe2d33a4ea429d12765e4b31d0064300af1092d0d): Bind for 0.0.0.0:3000 failed: port is already allocated
翻訳すると:
エラー: コンテナのネットワーク設定に失敗しました。エンドポイント フォルダ名-web-1 (17cd568c21f6c0c93c7256dfe2d33a4ea429d12765e4b31d0064300af1092d0d) の外部接続のバインド設定に失敗しました: 0.0.0.0:3000 へのバインドが失敗しました。ポートは既に割り当てられています。
=>ポート3000を使おうとしたが、すでに他で使われている
原因の切り分け
- ポートはすでに割り当てられている
= 別のDocker Composeプロジェクトでwebが起動している
= 他のアプリが 3000 番を占有している
今回は、
別のフォルダでDockerを立ち上げっぱなしだった
というしょうもないことが原因でした。
対処法
別フォルダ側でコンテナを停止:
docker compose down
その後、作業中のフォルダで改めて:
docker compose up
→ web コンテナが正常に起動
→ docker compose exec web ... も実行できるようになりました。
まとめ
今回のポイントは次の3つです。
-
docker compose execが失敗したら、まずdocker compose psで起動確認 - web がいなければ、
docker compose upしてログを見る - エラーの最後の方に原因を語っていないか確認
プログラミング学習初期は、
- エラー文が長くて読む気がしない
- AIに言われたコマンドをそのまま叩くだけ
- 「なぜ直ったのか」が分からないまま進む
という状態になりがちだと思います。
自分もまさにそうでした。
ですが今回のように、「どこを見て」「どう考えて」「原因を切り分けたか」
を一度経験すると、次からは自力で辿れるようになります。
同じところで詰まっている方の参考になれば幸いです。