フリーキーズ | 独学プログラミング

Dockerfile入門!初心者でもわかる書き方の基本

リンドくん

リンドくん

たなべ先生、Dockerfileって何なんですか?
なんだか難しそうで...

たなべ

たなべ

Dockerfileは、アプリケーションの実行環境を自動的に作るためのレシピのようなものなんだ。
一度書いておけば、誰でも同じ環境を簡単に再現できるようになるんだよ。

プログラミングを学んでいると、「自分のパソコンでは動くのに、他の人の環境では動かない...」という経験をしたことがある方も多いのではないでしょうか?
そんな環境の違いによる問題を解決してくれるのがDockerです。

そして、そのDockerの動作を定義するのが「Dockerfile」なのです。

この記事では、プログラミング初心者の方でも理解できるよう、Dockerfileの基本的な書き方から実践的な使い方まで、丁寧に解説していきます。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

Dockerfileとは?なぜ必要なのか

リンドくん

リンドくん

でも先生、そもそもなぜDockerfileが必要なんですか?
普通にアプリケーションをインストールすればいいんじゃ...

たなべ

たなべ

確かにそう思うよね。でも、プロジェクトが大きくなると、必要なソフトウェアやライブラリがたくさんになるんだ。
それを毎回手作業でインストールするのは大変だし、ミスも起きやすいよね。

Dockerfileの基本概念

Dockerfileは、Dockerイメージを作成するための設計図です。
簡単に言えば、「どんなソフトウェアをどの順番でインストールするか」を記述したテキストファイルなのです。

Dockerfileの真の価値は以下の点にあります。

  • 環境の再現性 - 誰が実行しても同じ環境が作れます
  • 自動化 - 手作業でのセットアップが不要になります
  • バージョン管理 - Gitなどで環境の変更履歴を管理できます
  • 共有のしやすさ - チームメンバー全員が同じ環境で開発できます

なぜDockerfileが重要なのか

現代のソフトウェア開発では、以下のような問題に直面することがあります。

  1. 「自分の環境では動くのに...」問題 - 開発者ごとに異なる環境設定による不具合
  2. 複雑なセットアップ手順 - 新メンバーが開発を始めるまでに時間がかかる
  3. 本番環境との差異 - 開発環境と本番環境で動作が異なる
  4. 依存関係の管理 - ライブラリのバージョン違いによる問題

Dockerfileを使うことで、これらの問題を一気に解決できます。
実際、多くの企業やオープンソースプロジェクトでDockerが標準的に使われているのは、こうした理由からなのです。

Dockerfileの基本的な書き方

リンドくん

リンドくん

実際にDockerfileってどう書くんですか?難しそうですね...

たなべ

たなべ

心配しないで!基本的な命令は数個だけ覚えればいいんだよ。
まずは最もシンプルなDockerfileから見ていこう。

最もシンプルなDockerfile

まず、最も基本的なDockerfileの例を見てみましょう。

# ベースとなるイメージを指定
FROM ubuntu:24.04

# 作業ディレクトリを設定
WORKDIR /app

# ファイルをコピー
COPY hello.txt /app/

# コマンドを実行
CMD ["cat", "hello.txt"]

このDockerfileは、Ubuntuをベースに、テキストファイルを表示するだけのシンプルな例です。
これだけでも、Dockerfileの基本的な構造が理解できるのではないでしょうか。

基本命令の解説

Dockerfileでよく使う基本的な命令を見ていきましょう。

FROM - ベースイメージの指定

FROM ubuntu:24.04

FROMは、Dockerイメージの土台となるベースイメージを指定します。
これは必ず最初に書く命令で、既存のイメージの上に自分のアプリケーション環境を構築していきます。

よく使われるベースイメージには以下のようなものがあります。

  • ubuntu:24.04 - Ubuntu Linux
  • node:20 - Node.js環境
  • python:3.14 - Python環境
  • nginx:alpine - 軽量なNginxサーバ

WORKDIR - 作業ディレクトリの設定

WORKDIR /app

WORKDIRは、以降の命令を実行するディレクトリを指定します。
指定したディレクトリが存在しない場合は自動的に作成されます。

COPY - ファイルのコピー

COPY package.json /app/
COPY . /app/

COPYは、ホストマシン(自分のPC)からDockerイメージへファイルをコピーします。
アプリケーションのソースコードや設定ファイルをイメージに含める際に使用します。

RUN - コマンドの実行

RUN apt -y update && apt -y install curl
RUN npm install

RUNは、イメージ作成時にコマンドを実行します。
パッケージのインストールや環境設定など、イメージを構築する際の処理を記述します。

CMD - コンテナ起動時のコマンド

CMD ["npm", "start"] # `npm start`のようにスペースを挟むときは配列の形にする

CMDは、コンテナが起動したときに実行されるデフォルトのコマンドを指定します。
アプリケーションの起動コマンドを記述するのが一般的です。

実践的なNode.jsアプリケーションのDockerfile

では、実際のアプリケーション開発でよく使われる、Node.jsアプリケーション用のDockerfileを見てみましょう。

# Node.js 20をベースイメージとして使用
FROM node:20

# 作業ディレクトリを設定
WORKDIR /app

# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./

# 依存関係をインストール
RUN npm install

# アプリケーションのソースコードをコピー
COPY . .

# アプリケーションが使用するポートを公開
EXPOSE 3000

# アプリケーションを起動
CMD ["npm", "start"]

このDockerfileは、Node.jsアプリケーションを動かすために必要な環境を自動的に構築します。
一度このファイルを作成すれば、誰でも同じ環境でアプリケーションを実行できるようになるのです。

Dockerfileを効率的に書くコツ

リンドくん

リンドくん

基本的な書き方はわかりました!でも、もっと効率的な書き方とかあるんですか?

たなべ

たなべ

Dockerfileにはビルドを速くしたり、イメージを小さくしたりするテクニックがたくさんあるんだ。
実務でも役立つコツを教えるよ。

レイヤーキャッシュを活用する

Dockerは、Dockerfileの各命令ごとにレイヤーと呼ばれる層を作成します。
変更されていないレイヤーは再利用される(キャッシュされる)ため、ビルド時間を大幅に短縮できます。

悪い例(非効率)
FROM node:20
WORKDIR /app

# すべてのファイルをコピーしてから依存関係をインストール
COPY . .
RUN npm install

CMD ["npm", "start"]

この書き方だと、ソースコードが少しでも変更されると、npm installも毎回実行されてしまいます。

良い例(効率的)
FROM node:20
WORKDIR /app

# 先にpackage.jsonだけをコピー
COPY package*.json ./
RUN npm install

# その後でソースコードをコピー
COPY . .

CMD ["npm", "start"]

この書き方なら、ソースコードを変更してもpackage.jsonが変わっていなければ、npm installはキャッシュから実行されます。
これにより、ビルド時間が数分から数秒に短縮されることもあります!

マルチステージビルドでイメージを軽量化

マルチステージビルドを使うと、ビルド時にのみ必要なツールを最終イメージから除外できます。

# ビルドステージ
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 実行ステージ
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./

EXPOSE 3000
CMD ["node", "dist/index.js"]

この例では、ビルド用と実行用で別々のステージを使っています。
最終的なイメージには実行に必要なファイルだけが含まれるため、イメージサイズを大幅に削減できます。

RUN命令を効率的にまとめる

RUN命令は、可能な限りまとめて実行することでレイヤー数を減らせます。

悪い例

RUN apt -y update
RUN apt -y install curl
RUN apt -y install git
RUN apt clean

良い例

RUN apt -y update && \
    apt -y install \
        curl \
        git \
    && apt clean \
    && rm -rf /var/lib/apt/lists/*

まとめて実行することで、レイヤー数が減り、イメージサイズも小さくなります。
また、不要なキャッシュファイルも削除しているため、さらに軽量化されています。

.dockerignoreファイルの活用

Dockerfileと同じディレクトリに.dockerignoreファイルを作成すると、イメージに含めたくないファイルを除外できます。

node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.DS_Store

これにより、不要なファイルがイメージに含まれなくなり、ビルド時間とイメージサイズの両方を削減できます。

よくあるトラブルと解決法

リンドくん

リンドくん

Dockerfileを書いてみたんですけど、エラーが出ちゃって...
初心者がよくハマるポイントってありますか?

たなべ

たなべ

あるある!実は初心者の方が陥りやすい問題にはパターンがあるんだ。
よくあるトラブルと解決法を見ていこう。

問題1 パスの指定ミス

症状: COPY failed: file not foundというエラーが出る

原因: COPYやADDで指定したファイルが見つからない

解決法:

  • Dockerfileからの相対パスで指定されているか確認
  • .dockerignoreで除外されていないか確認
  • ファイル名の大文字小文字が正しいか確認
# 正しい例
COPY ./src/app.js /app/

# 間違った例(絶対パスは使えない)
# COPY /Users/username/project/src/app.js /app/

問題2 権限エラー

症状: コンテナ内でファイルの読み書きができない

原因: ファイルやディレクトリの所有者・権限が適切でない

解決法:

  • USER命令で適切なユーザーを指定
  • 必要に応じてRUN chownで所有者を変更
# 非rootユーザーで実行する例
FROM node:20

WORKDIR /app
COPY package*.json ./
RUN npm install

COPY . .

# 非rootユーザーを作成
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

CMD ["npm", "start"]

問題3 ビルドが遅い

症状: Dockerイメージのビルドに時間がかかりすぎる

原因: キャッシュが効いていない、または不要なファイルをコピーしている

解決法:

  • 依存関係のインストールをソースコードのコピーより前に行う
  • .dockerignoreで不要なファイルを除外
  • マルチステージビルドを活用
# キャッシュを活用した例
FROM python:3.14

WORKDIR /app

# requirements.txtを先にコピーしてインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# その後でソースコードをコピー
COPY . .

CMD ["python", "app.py"]

問題4 イメージサイズが大きすぎる

症状: 作成したイメージが数GBになってしまう

原因: 不要なファイルやビルドツールが含まれている

解決法:

  • Alpine Linuxベースのイメージを使用
  • マルチステージビルドで不要なファイルを除外
  • キャッシュファイルを削除
# 軽量なAlpineイメージを使用
FROM node:20-alpine

WORKDIR /app

# 依存関係のインストール後にキャッシュを削除
COPY package*.json ./
RUN npm ci --only=production && \
    npm cache clean --force

COPY . .

CMD ["node", "index.js"]

Dockerfileのベストプラクティス

リンドくん

リンドくん

これから本格的にDockerを使っていきたいんですけど、気をつけるべきことってありますか?

たなべ

たなべ

もちろん!プロの開発現場で使われているベストプラクティスを押さえておくと、チーム開発でも役立つよ。

1. セキュリティを意識する

rootユーザーで実行しない

FROM node:20

WORKDIR /app

# アプリケーションの準備
COPY package*.json ./
RUN npm install
COPY . .

# 非rootユーザーを作成して切り替え
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser

CMD ["npm", "start"]

機密情報をイメージに含めない

  • パスワードやAPIキーをDockerfileに直接書かない
  • 環境変数や.envファイルをイメージに含めない
  • シークレット情報はDocker Secretsやボリュームマウントを使用

2. イメージを最小限に保つ

不要なファイルを削除する

RUN apt -y update && \
    apt -y install --no-install-recommends \
        package1 \
        package2 \
    && apt clean \
    && rm -rf /var/lib/apt/lists/*

軽量なベースイメージを使用

# 通常版(約900MB)
FROM node:20

# Alpine版(約170MB)
FROM node:20-alpine

3. 明確なタグを使用する

悪い例

FROM node:latest  # バージョンが不明確

良い例

FROM node:20.19.5  # 特定のバージョンを指定
# または
FROM node:20.19.5-alpine3.22  # タグで環境も明示

4. ドキュメントを充実させる

# Node.js 20をベースにしたWebアプリケーション用イメージ
# 作成者: your-name
# 最終更新: 2025-09-29

FROM node:20-alpine

# 作業ディレクトリを設定
WORKDIR /app

# ラベルでメタデータを追加
LABEL maintainer="your-email@example.com"
LABEL version="1.0"
LABEL description="Sample Node.js application"

# 依存関係のインストール
COPY package*.json ./
RUN npm ci --only=production

# アプリケーションのコピー
COPY . .

# ヘルスチェックを追加
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js || exit 1

EXPOSE 3000

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

5. ログを適切に扱う

# ログを標準出力に出力(Dockerがキャプチャできるように)
CMD ["node", "server.js"]

# ログファイルへの出力は避ける
# CMD ["node", "server.js", ">", "app.log"]  # 悪い例

これらのベストプラクティスを守ることで、保守しやすく、安全で、効率的なDockerfileを作成できます。

まとめ

リンドくん

リンドくん

Dockerfileについていろいろ学べました!思ったよりシンプルで、使いこなせそうな気がしてきました!

たなべ

たなべ

その意気だね!最初は基本的な使い方から始めて、徐々に高度なテクニックを取り入れていけばいいんだよ。
まずは自分のプロジェクトで試してみることが大切だね。

この記事では、Dockerfileの基本的な書き方から実践的なテクニックまで解説してきました。

重要なポイントをおさらいしましょう。

  • Dockerfileは環境構築の自動化に欠かせないツールです
  • 基本命令(FROM、WORKDIR、COPY、RUN、CMD)を理解すれば、シンプルなDockerfileが書けます
  • レイヤーキャッシュの活用でビルド時間を大幅に短縮できます
  • マルチステージビルドでイメージを軽量化できます
  • セキュリティとベストプラクティスを意識することが重要です

Dockerfileを使いこなせるようになると、以下のようなメリットが得られます。

  • チームメンバー全員が同じ環境で開発できる
  • 新メンバーのオンボーディングが劇的に速くなる
  • 本番環境との差異がなくなり、デプロイが安定する
  • インフラのコード化(Infrastructure as Code)が実現できる

現代のソフトウェア開発では、Dockerは必須のスキルとなっています。
最初は難しく感じるかもしれませんが、基本を押さえて実際に手を動かしていけば、必ず使いこなせるようになります。

ぜひ今日学んだことを活かして、自分のプロジェクトでDockerfileを作成してみてください。
小さなプロジェクトから始めて、徐々に複雑な構成に挑戦していくのがおすすめです。

この記事をシェア

関連するコンテンツ