現場でこれ、よく見ます。
docker compose exec app bash
打てば作業できる。
でも「いま何してるの?」って聞かれると、説明がふわっとする。
この回はそこを、コマンド暗記じゃなく “見取り図” でほどきます。
特定の言語・フレームワークには寄せません。概念に絞ります。
TL;DR(先にこれだけ)
- Dockerは「箱」ではなく、隔離されたプロセス(= コンテナ) を動かす仕組み
- あなたが叩く
docker ...はお願い。実行担当は Docker Engine - Composeは「複数コンテナのセット」をまとめて扱う
-
compose execは「中に入る」より正確には 起動中コンテナで作業用のコマンドを一時的に走らせてつなぐ
Dockerって何?
まず、Dockerが何かを“最短”で言うならこうです。
Dockerは、アプリを 同じ手触りで起動できるようにする仕組み です。
「同じ手触り」というのは、ローカルでも、CIでも、本番でも、
起動に必要な前提をなるべく揃えて、同じように動かすという意味です。
現場でDockerが普通に出てくるのは、これが嬉しいからです。
なんでDockerが必要なの?
Dockerを使わないと、地味にこういうズレが起きます。
- README通りにやったのに動かない(人によって前提が違う)
- ローカルでは動くのに、別の環境で落ちる(依存関係や設定が微妙に違う)
- 「何を入れたら動くか」が人の頭の中にある(再現がしんどい)
Dockerはここを、こういう方向に寄せます。
- “人のPC” に依存せず
- “動かす単位” を揃えて
- 「起動の前提」 を共有しやすくする
この「動かす単位」を表すのが、次に出てくる Image と Container です。
まずはこれだけ:Dockerの中心は「テンプレ→起動中」
Dockerのコアは本当にこれだけです。
イメージ(テンプレ) から コンテナ(起動中) を作って動かす
Image(テンプレ) ──起動──> Container(起動中)
この1本線が分かれば、Dockerの話は急に読みやすくなります。
イメージとコンテナの違い:テンプレと「起動した結果」
| 名前 | ざっくり言うと |
|---|---|
| Image(イメージ) | 起動に必要なものがまとまった“テンプレ” |
| Container(コンテナ) | そのテンプレを元に起動した“動いてる状態” |
「テンプレ」って言っているのは、同じImageから何度でも起動できるからです。
Image(テンプレ)
├─ 起動 → Container A(起動中)
├─ 起動 → Container B(起動中)
└─ 起動 → Container C(起動中)
ここで大事なのは、「ImageとContainerは別物」だということ。
(この区別がつくと、現場の会話が途端に分かりやすくなります)
「起動中」ってローカルだとどういうこと?
ローカルだと「顧客が使ってるアプリ」感が薄いので、ここが引っかかりやすいです。
この記事で言う「起動中」は、すごく素朴に
コンテナの中で「終わらない系のコマンド」が動き続けている
という意味です。
サーバを起動すると、待ち受け続けて止めるまで終わらないですよね。
それと同じことが、コンテナの中で起きています。
Container(起動中)
- サーバ起動など「待ち受ける系」が動き続ける
ローカルなら「あなたのPCの中で」それが動いてます。
本番なら「サーバの中で」動いてます。
場所が違うだけで、構造は同じです。
じゃあ誰が起動してるの?
ここまでくると自然に疑問が出ます。
「ImageからContainerを起動するの、誰がやってるの?」
答えが Docker Engine です。
難しいことは言わず、まずはこう捉えるのが一番ラクです。
-
docker ...は「お願い」 - Engineは「実行役」
あなたのターミナル(お願い)
docker / docker compose
|
v
Docker Engine(実行役)
|
v
Container(起動中)
だから「どこで動いてるの?」の答えは、
Docker Engineがいる場所で動いてるになります。
Composeって何? Image と何が違うの?
ここ、けっこう大事です。
ImageとComposeは「どっちもDockerっぽい名前」なので混ざりやすい。
結論から言うと、役割が違います。
| 名前 | 何を決める? | ざっくり言うと |
|---|---|---|
| Image | 1つのコンテナの“中身” | テンプレ(これから実体が生まれる) |
| Compose | 複数コンテナの“組み合わせ” | セットの指示(どう並べて動かすか) |
イメージとしてはこう。
Image:中身の話
Image → Container
Compose:組み合わせの話
「app はこのImageで」
「db はこのImageで」
「この2つをセットで動かしてね」
Composeはテンプレそのものじゃなくて、テンプレ(Image)をどう使うかの「まとめ役」だと思うと混ざりません。
docker compose exec は “起動中に作業を差し込む” 操作
改めて、これ。
docker compose exec app bash
起きてることはこうです。
起動中の
appコンテナで、bashという 作業用のコマンド を一時的に動かして、あなたの端末とつなぐ
図にするとこう。
(ふだん)
appコンテナ:
- 起動中ずっと動いてる:サーバ起動など「終わらない系」
exec すると…
appコンテナ:
- 起動中ずっと動いてる:サーバ起動など
- 一時的に動かす:bash(あなたの作業用)
ここが腹落ちすると、exec 周りのモヤモヤがだいぶ消えます。
-
execは「起動」ではない(起動中のコンテナが前提) -
execは「起動中の中で、作業用のコマンドを一時的に動かす」 - 作業が終われば、その作業用コマンドは終わる(でもサーバは動き続ける)
じゃあ up と exec はどう違うの?
感覚だけ揃えるとこうです。
-
docker compose up:セット(app/dbなど)を 起動する -
docker compose exec:起動済みの中で 作業する
compose up
-> appコンテナを起動(終わらない系が走り始める)
-> dbコンテナを起動
compose exec
-> 起動中のappコンテナで作業用のコマンドを一時的に動かす
さいごに
普段やっていることを、最後に1枚にまとめます。
(1) Image(テンプレ)を用意する
|
v
(2) Compose が「このセットで動かす」を決める
|
v
(3) Engine が実際にコンテナを起動する
|
v
(4) exec で、起動中コンテナに作業を一時的に差し込む
┌───────────┐
│ Image群 │ (テンプレ)
└─────┬─────┘
│(どれを使うか指定)
┌─────▼─────┐
│ Compose │ (セットの指示)
└─────┬─────┘
│(実行お願い)
┌─────▼─────┐
│ Engine │ (実行担当)
└─────┬─────┘
│(起動)
┌─────▼──────────────────────┐
│ Containers(起動中の実体) │
│ - app(終わらない系が動く) │
│ - db ... │
│ + execで作業を一時的に追加 │
└────────────────────────────┘
この見取り図が頭にあると、docker compose exec がこう読めるようになります。
「Compose管理下の、起動中コンテナに対して、作業用のコマンドを一時的に動かしてる」
「聞いたことあるけど分からない」が、ちゃんと“分かる”に変わる入口として、この回が役に立てば嬉しいです。