Dockerfileの基本命令を理解しよう|FROM・RUN・COPY・CMD の使い方
こんにちは、とまだです。
みなさん、Dockerfileを書いていて「これって何のための命令だっけ?」と迷ったことはありませんか?
私も最初は、FROMとRUNの違いがよくわからなくて混乱しました。
今回は現役のエンジニア、そして元プログラミングスクール講師としての経験から、Dockerfileの基本命令について解説します。
Dockerfileって結局なんなの?
Dockerfileを一言で表すなら「レシピ」です。
料理のレシピと同じように、材料と手順が書かれています。
ただし、作るのは料理ではありません。
アプリケーションが動く環境です。
なぜDockerfileが必要なの?
「環境構築でハマった」という経験、ありませんか?
チームメンバーのPCでは動くのに、自分のPCでは動かない。
そんな悩みを解決してくれるのがDockerです。
そして、Dockerfileはその環境を誰でも同じように作れる設計図なんです。
FROM命令:土台を決める
FROMは「どの土台を使うか」を決める命令です。
家を建てるときの基礎工事みたいなものですね。
FROM node:16
これは「Node.js 16がインストールされた環境を土台にする」という意味です。
ベースイメージの選び方
ベースイメージ選びは重要です。
なぜなら、大きすぎるとイメージが重くなるからです。
逆に、小さすぎると必要なものが入っていません。
だから、用途に合わせて選ぶのがコツです。
よく使われるベースイメージをいくつか紹介します。
Node.jsアプリならnode
。
Pythonアプリならpython
。
軽量化したいならalpine
系を選ぶといいでしょう。
RUN命令:環境を整える
RUNは「イメージを作るときに実行するコマンド」です。
引っ越し先の家で、まず最初に家具を配置するようなイメージです。
FROM ubuntu
RUN apt-get update && apt-get install -y curl
この例では、Ubuntuの環境にcurlをインストールしています。
なぜ&&でつなぐのか?
RUN命令を何度も書くと、それだけレイヤーが増えます。
そして、レイヤーが増えるとイメージサイズが大きくなってしまうんです。
だから、関連するコマンドは&&
でつなぎます。
1つのRUNにまとめるのがベストプラクティスです。
ただし、あまりに長くなる場合は可読性を優先しましょう。
バックスラッシュ(\)で改行すると見やすくなります。
COPY命令:ファイルを配置する
COPYは「ホストのファイルをイメージにコピーする」命令です。
引っ越しのときに、荷物を新居に運び込むイメージですね。
FROM node:16
WORKDIR /app
COPY . /app
RUN npm install
カレントディレクトリのすべてを/app
にコピーしています。
ADDとCOPYの違い
実はADDという似た命令もあります。
でも、初心者の方は基本的にCOPYを使ってください。
なぜなら、ADDは予期せぬ動作をすることがあるからです。
例えば、圧縮ファイルを自動展開する機能があります。
シンプルにファイルをコピーしたいだけならCOPYで十分です。
CMD命令:起動時の動作を決める
CMDは「コンテナが起動したときに実行されるコマンド」です。
車のエンジンをかけたときに、最初に動き出す部分みたいなものです。
FROM node:16
WORKDIR /app
COPY . /app
RUN npm install
CMD ["npm", "start"]
コンテナが起動するとnpm start
が実行されます。
CMDとENTRYPOINTの使い分け
ENTRYPOINTという似た命令もあります。
でも、最初はCMDだけ覚えれば大丈夫です。
CMDは「デフォルトのコマンド」です。
起動時に上書きできます。
一方、ENTRYPOINTは「必ず実行されるコマンド」です。
より固定的なんですね。
基本的にはCMDを使いましょう。
特殊な要件があるときだけENTRYPOINTを検討します。
実務での活用シーン
チーム開発での威力
開発チームで環境の違いに悩まされた経験はありませんか?
「俺の環境では動くんだけどなぁ」という言葉。
これがDockerfileがあれば解決します。
なぜなら、全員が同じDockerfileを使えば同じ環境で開発できるからです。
しかも、Gitで管理できます。
だから、環境の変更履歴も追えるんです。
CI/CDパイプラインでの活用
自動テストや自動デプロイでもDockerfileは大活躍します。
例えば、プルリクエストごとに自動でビルド。
そして、テスト実行。
合格したらそのまま本番デプロイ。
こんな流れが実現できるんです。
「本番だけバージョンが違った」なんてミスも防げますね。
よくあるベストプラクティス
キャッシュを活用する
Dockerはステップごとにキャッシュを作ります。
変更がないステップは再実行されません。
だから、変更頻度の低いものを先に書くのがコツです。
例えば、依存関係のインストールは先に。
ソースコードのコピーは後に。
こうすることでビルド時間を短縮できます。
レイヤーを減らす工夫
レイヤーが増えるとイメージサイズが大きくなります。
だから、RUN命令はできるだけまとめましょう。
また、不要なファイルは含めないようにしましょう。
.dockerignore
ファイルを使うといいです。
COPYから除外できます。
セキュリティへの配慮
rootユーザーで実行しないようにしましょう。
USER命令で一般ユーザーに切り替えます。
これがベストプラクティスです。
また、機密情報はDockerfileに書かないでください。
環境変数として実行時に渡すようにしましょう。
もう一歩進んだテクニック
マルチステージビルド
ビルド用と実行用でイメージを分ける手法です。
特に、コンパイルが必要な言語で有効です。
FROM golang AS builder
WORKDIR /app
COPY . /app
RUN go build -o myapp
FROM alpine
COPY /app/myapp /usr/local/bin/myapp
CMD ["myapp"]
ビルドに必要なツールを本番環境に持ち込まずに済みます。
結果的に軽量なイメージが作れるんです。
環境変数の活用
ENV命令で環境変数を設定できます。
FROM node:16
ENV PORT=3000
WORKDIR /app
COPY . /app
RUN npm install
CMD ["npm", "start"]
ただし、秘密の情報は書かないように注意してください。
実行時に外から渡すのが安全です。
トラブルシューティングのコツ
ビルドが失敗したとき
まずはエラーメッセージをよく読みましょう。
パッケージが見つからない場合があります。
そんなときは、apt-get update
を忘れていないか確認です。
ネットワークエラーなら、少し時間を置いて再実行してみてください。
依存関係の競合なら、バージョンを明示的に指定するといいでしょう。
コンテナが起動しないとき
docker exec
でコンテナに入って調査できます。
docker exec -it <コンテナ名> /bin/bash
環境変数やファイルの配置を確認してみましょう。
ログを見ることも大切です。
今回のまとめ
Dockerfileの基本命令について解説しました。
FROMで土台を決める。
RUNで環境を整える。
COPYでファイルを配置する。
CMDで起動時の動作を決める。
この流れを理解すれば、基本的なDockerfileは書けるようになります。
最初はシンプルなものから始めてみてください。
慣れてきたら、マルチステージビルドにも挑戦してみましょう。
環境変数の活用も試してみてください。
今回紹介した基本命令を使いこなせれば、開発効率が格段に上がります。
ぜひ実践で使ってみてくださいね。
著者について

とまだ
フルスタックエンジニア
Learning Next の創設者。Ruby on Rails と React を中心に、プログラミング教育に情熱を注いでいます。初心者が楽しく学べる環境作りを目指しています。
著者の詳細を見る →