メインコンテンツまでスキップ

第46章:CMD(起動コマンド)▶️

この章のゴール🏁

  • Dockerfileの CMD が「起動したときにデフォルトで何を実行するか」を決めるものだと説明できる🙂
  • CMDおすすめの書き方(exec形式) を使って、Todo API をちゃんと起動できる🚀
  • 「一時的に別コマンドで起動する(上書き)」ができるようになる🎮

1) CMDってなに?ざっくり一言で😄📝

CMD「このイメージを起動したら、基本はコレを実行してね」 という “デフォルト起動コマンド” を決める命令だよ▶️ ポイントはこれ👇

  • Dockerfileの 最後の CMD だけが有効(前に書いたのは上書きされる)🧹
  • docker run起動時にコマンドを指定すると CMD を上書きできる🎯
  • RUN と違って、CMD はビルド時に実行されない(起動時に効く)⚡

これらは公式のDockerfileリファレンスにまとまってるよ📚(Docker Documentation)


2) CMDの書き方は3つある(でも初心者は2つ覚えればOK)🧠✨

Dockerfileの CMD には代表的に3パターンあるよ👇(公式定義)(Docker Documentation)

  1. exec形式(推奨)
  • 例:CMD ["node", "dist/server.js"]
  • “配列(JSON)”で書くやつ。シグナル(停止指示)が届きやすくて安定🧯
  1. exec形式(ENTRYPOINTへのデフォルト引数) 🧩
  • 例:CMD ["--port", "3000"]
  • ENTRYPOINT とセット運用する時に使う(この章では「そういう使い道もある」くらいでOK)🙂
  1. shell形式(非推奨寄り) ⚠️
  • 例:CMD node dist/server.js
  • 実は内部的にシェル経由になりやすく、停止シグナルがアプリに届かない事故などが起きやすい…😵

迷ったら exec形式だけ覚える でOK!🙆‍♂️


3) なんでexec形式が推奨なの?(超重要:止め方がきれいになる)🧯🛑

コンテナを止めるとき、docker stop みたいな停止操作は PID 1(コンテナの一番えらいプロセス) にシグナルを送るのが基本だよ📌 でも shell形式やシェルスクリプト経由だと、シグナルが子プロセスに転送されず、アプリが SIGTERM を受け取れないことがあるんだ😱(Snyk)

さらに Docker のCLIリファレンスにも「PID 1 の扱いは特殊で、デフォルト動作のシグナルが無視されることがある」って注意があるよ🧠(Docker Documentation)

なので、この章では exec形式で、アプリ本体を “直に起動” する を基本ルールにするよ✅


4) ハンズオン:Todo API を CMD で起動させる▶️🧪

ここからは「Todo API(Node/TS)」を想定して、よくある2パターンを作るよ😊 (どっちを選ぶかは、今のプロジェクトの package.json の scripts 次第!)


パターンA:ビルド済み(dist)を node で起動する(おすすめ)🏆

TypeScriptを dist/ に出して起動する構成なら、これが一番スッキリ✨

Dockerfileの最後に👇を置く:

CMD ["node", "dist/server.js"]

コツ🧠

  • 配列の各要素は「1引数」だよ!

    • ["node", "dist/server.js"]
    • ["node dist/server.js"](これだと “1個の文字列” 扱いになって事故りがち)

動作確認コマンド例👇

docker build -t todo-api:cmd .
docker run --rm -p 3000:3000 todo-api:cmd

パターンB:npm script で起動する(開発寄り)🛠️

package.json"start""dev" があるなら、こういうのも定番!

CMD ["npm", "run", "start"]

または dev なら:

CMD ["npm", "run", "dev"]

※「停止がキレイに伝わる」観点では、最終的に node 直起動 が好まれやすいよ(特に本番)🙂 このへんの “開発用/本番用の分離” は次の章でちゃんとやる予定🎭


5) 「CMDを上書きして1回だけ別コマンド」やりたい!🎮✨

ここが CMD の気持ちよさポイント😆 docker run はこういう形👇で、イメージ名の後ろに書いたコマンドで上書きできるよ(Docker Documentation)

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

例:いつもの起動じゃなくて、1回だけテストを回す🧪

docker run --rm todo-api:cmd npm test

例:1回だけバージョン確認する🔎

docker run --rm todo-api:cmd node -v

例:コンテナの中身を確認する(シェルで入る)🕵️‍♂️

docker run --rm -it todo-api:cmd sh

6) いまこのイメージ、何が起動する設定なの?を確認👀🧾

「これ CMD 効いてる?」って迷ったら、inspect で確認できるよ🔍

docker image inspect todo-api:cmd --format "{{json .Config.Entrypoint}} {{json .Config.Cmd}}"
  • CmdCMD
  • EntrypointENTRYPOINT

7) おまけ:停止・ゾンビ対策で “init” を入れる話(必要になったらでOK)👻🧯

プロセス周りが気になってきたら、--initコンテナ内PID 1に init を置く手があるよ。 Docker公式に「ゾンビプロセス回収など init の責務を担う」って説明がある✅(Docker Documentation)

例:

docker run --init --rm -p 3000:3000 todo-api:cmd

この章では「そういう武器もある」くらいでOK!🧰


8) AI活用プロンプト例🤖✨(コピペOK)

  • 「この package.json の scripts を貼るので、コンテナ起動に最適な CMDexec形式で提案して。dev/start の2案ほしい」
  • 「このDockerfileの CMD が原因で起動しない可能性ある?チェック観点を箇条書きで」
  • docker run IMAGE ...CMD を上書きする例を、テスト/マイグレーション/シェルの3つで作って」

9) ミニ演習📝🎯

  1. CMD ["node","dist/server.js"] にして起動できるか確認する🚀
  2. docker run ... node -vCMD を上書きできるか試す🔁
  3. わざと shell形式 CMD node dist/server.js にして、違いを体験してみる(戻すの忘れずに!)⚠️

次の章で「開発用と本番用は別」🎭に入るから、ここで CMD の感覚がつかめると超ラクになるよ😆✨