Dockerfile の作成と使用方法入門

DockerBeginner
オンラインで実践に進む

はじめに

この Dockerfile チュートリアルは、Dockerfile を作成および使用するための包括的な入門書です。Docker に初めて触れる方、または既存の知識を深めたい方にとって、このガイドは、Docker イメージとコンテナの理解から、独自のカスタム Docker イメージの構築と最適化まで、Dockerfile の基礎を段階的に解説します。

Docker と Dockerfile の概要

Docker とは何か?

Docker は、開発者がアプリケーションをコンテナと呼ばれる一貫性があり隔離された環境で構築、デプロイ、実行できるようにするオープンソースプラットフォームです。コンテナは、アプリケーションとその依存関係を単一のポータブルなユニットにパッケージ化し、アプリケーションが基盤となるインフラストラクチャに関係なく同じように動作することを保証します。

Dockerfile の理解

Dockerfile は、Docker イメージを構築するための手順のセットを含むテキストベースのスクリプトです。ベースイメージ、実行する手順、コンテナの設定を指定します。Dockerfile を使用することで、Docker イメージの作成と管理を自動化でき、アプリケーションの構築、配布、デプロイを容易にします。

Dockerfile を使用する利点

  • 一貫性: Dockerfile は、開発環境から本番環境まで、アプリケーションが異なる環境で同じように動作することを保証します。
  • 再現性: Dockerfile は、アプリケーションの環境を再現できるようにし、問題のデバッグとトラブルシューティングを容易にします。
  • スケーラビリティ: Docker コンテナは、アプリケーションのリソース要件に応じて、簡単にスケールアップまたはスケールダウンできます。
  • 移植性: Docker イメージは、さまざまなプラットフォームやクラウド環境間で共有およびデプロイできます。

Docker と Dockerfile の開始

Docker と Dockerfile を始めるには、システムに Docker がインストールされている必要があります。公式 Docker ウェブサイト (https://www.docker.com/get-started) から Docker をダウンロードしてインストールできます。Docker がインストールされたら、独自の Dockerfile を作成して Docker イメージを構築し始めることができます。

## Ubuntu 22.04 で Docker をインストール
sudo apt-get update
sudo apt-get install -y docker.io

次のセクションでは、Dockerfile の構造と構文、カスタム Docker イメージの構築方法について詳しく説明します。

Docker イメージとコンテナの理解

Docker イメージ

Docker イメージは、Docker コンテナを作成するための指示のセットを含む、読み取り専用のテンプレートです。アプリケーションコード、ランタイム、システムツール、ライブラリ、およびアプリケーションを実行するために必要なその他のファイルが含まれています。Docker イメージは Dockerfile を使用して構築され、Docker Hub などの Docker レジストリを通じて共有および配布できます。

Docker コンテナ

Docker コンテナは、Docker イメージの実行可能なインスタンスです。コンテナは軽量で、スタンドアロンの、実行可能なパッケージであり、コード、ランタイム、システムツール、システムライブラリなど、アプリケーションを実行するために必要なすべてのものが含まれています。コンテナは互いに、そしてホストオペレーティングシステムから隔離されているため、一貫性があり信頼性の高いアプリケーションのデプロイを保証します。

## シンプルな Ubuntu コンテナを実行
docker run -it ubuntu:22.04 bash

イメージレイヤーと Docker イメージキャッシュ

Docker イメージは、それぞれベースイメージに対して行われた一連の変更を表す複数のレイヤーで構成されています。新しいイメージを構築すると、Docker はイメージキャッシュを使用してこれらのレイヤーを再利用し、ビルドプロセスを効率化します。このキャッシュ機構は、ビルドプロセスを高速化し、最終イメージのサイズを削減するのに役立ちます。

graph TD A[ベースイメージ] --> B[レイヤー 1] B --> C[レイヤー 2] C --> D[レイヤー 3] D --> E[アプリケーションイメージ]

Docker イメージのプッシュとプル

カスタム Docker イメージを Docker Hub などのレジストリにプッシュして、他のユーザーと共有したり、異なる環境にデプロイしたりできます。逆に、レジストリからイメージをプルして、独自のプロジェクトで使用できます。

## Docker イメージを Docker Hub にプッシュ
docker push labex/my-app:latest

## Docker Hub から Docker イメージをプル
docker pull labex/my-app:latest

次のセクションでは、独自の Docker イメージを構築するために使用できる Dockerfile の基本的な構文と構造について説明します。

Dockerfile の構文と構造の基本

Dockerfile の構文

Dockerfile は、Docker イメージを構築するための指示のセットを含むテキストベースのスクリプトです。Dockerfile の基本的な構文は次のとおりです。

## コメント
INSTRUCTION 引数

Dockerfile で最も一般的な指示には以下があります。

指示 説明
FROM ビルドに使用されるベースイメージを指定します。
RUN ビルド中にコンテナ内でコマンドを実行します。
COPY ホストからコンテナにファイルまたはディレクトリをコピーします。
ADD COPY と似ていますが、リモートファイルのダウンロードとアーカイブの抽出も可能です。
CMD コンテナ起動時に実行するデフォルトのコマンドを指定します。
EXPOSE コンテナが指定されたネットワークポートでリスニングすることを Docker に通知します。
ENV 環境変数を設定します。
WORKDIR 後続の RUNCMDENTRYPOINTCOPY、および ADD 指示のための作業ディレクトリを設定します。

Dockerfile の構造

一般的な Dockerfile は、次の構造に従います。

  1. ベースイメージ: FROM 指示を使用して、ubuntu:22.04 などのベースイメージから始めます。
  2. 更新と依存関係のインストール: パッケージマネージャーを更新し、必要な依存関係をインストールするために RUN 指示を使用します。
  3. アプリケーションコードのコピー: COPY 指示を使用して、アプリケーションコードをコンテナにコピーします。
  4. 環境変数の設定: 必要な環境変数を設定するために ENV 指示を使用します。
  5. ポートの公開: アプリケーションがリスニングするポートを公開するために EXPOSE 指示を使用します。
  6. エントリポイントの定義: コンテナ起動時に実行するデフォルトのコマンドを指定するために CMD または ENTRYPOINT 指示を使用します。

シンプルな Python ウェブアプリケーションのための Dockerfile の例を次に示します。

FROM python:3.9-slim

## パッケージマネージャーの更新と依存関係のインストール
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  && rm -rf /var/lib/apt/lists/*

## アプリケーションコードのコピー
COPY . /app
WORKDIR /app

## Python 依存関係のインストール
RUN pip install --no-cache-dir -r requirements.txt

## アプリケーションが動作するポートの公開
EXPOSE 8000

## エントリポイントの定義
CMD ["python", "app.py"]

次のセクションでは、Dockerfile を使用してカスタム Docker イメージを構築する方法について説明します。

Dockerfile を使用したカスタム Docker イメージの構築

Dockerfile の作成

カスタム Docker イメージを構築するには、Dockerfile を作成する必要があります。プロジェクトディレクトリに Dockerfile という名前の新規ファイルを作成します。このファイルには、Docker イメージの構築手順が含まれます。

Docker イメージの構築

Dockerfile が準備できたら、docker build コマンドを使用して Docker イメージを構築できます。

docker build -t labex/my-app:latest .

このコマンドは Dockerfile を読み込み、指示を実行し、labex/my-app:latest という名前の新しい Docker イメージを作成します。コマンド末尾の . はビルドコンテキストを指定しており、Dockerfile があるディレクトリを指します。

ビルドプロセスの理解

docker build コマンドを実行すると、Docker は Dockerfile 内の指示を順番に実行します。各指示はイメージに新しいレイヤーを作成し、Docker はイメージキャッシュを使用してビルドプロセスを最適化します。

graph TD A[Dockerfile] --> B[ビルドステップ 1] B --> C[ビルドステップ 2] C --> D[ビルドステップ 3] D --> E[Docker イメージ]

イメージのタグ付けとプッシュ

イメージを構築したら、特定のバージョンまたはラベルでタグ付けし、Docker Hub などの Docker レジストリにプッシュできます。これにより、他のユーザーがイメージを使用できるようになります。

## イメージのタグ付け
docker tag labex/my-app:latest labex/my-app:v1.0

## Docker Hub へのイメージのプッシュ
docker push labex/my-app:v1.0

イメージのプルと実行

イメージがレジストリで使用可能になったら、それをプルして、イメージに基づいたコンテナを実行できます。

## Docker Hub からイメージのプル
docker pull labex/my-app:v1.0

## イメージからのコンテナの実行
docker run -p 8000:8000 labex/my-app:v1.0

次のセクションでは、より効率的な Dockerfile レイヤーの最適化方法について説明します。

Dockerfile レイヤーの効率化

Docker イメージレイヤーの理解

前述の通り、Docker イメージは複数のレイヤーで構成されており、各レイヤーはベースイメージに対する変更のセットを表します。これらのレイヤーは Docker によってキャッシュされ、ビルドプロセスを高速化します。

Dockerfile レイヤーの最適化

Dockerfile レイヤーの効率を向上させるためには、以下のベストプラクティスに従う必要があります。

  1. 関連する指示のグループ化: 関連する指示をまとめてイメージキャッシュを活用します。例えば、複数の RUN 指示を使用する代わりに、すべての依存関係を単一の RUN 指示でインストールします。

  2. レイヤー数の削減: Dockerfile の各指示は新しいレイヤーを作成します。可能な限り指示を組み合わせることで、レイヤー数を減らします。

  3. マルチステージビルドの活用: マルチステージビルドでは、単一の Dockerfile 内に複数の FROM 指示を使用できます。これにより、より小さく効率的なイメージを作成できます。

  4. イメージキャッシュの活用: Dockerfile の指示を、イメージキャッシュを活用するような順序に配置します。例えば、変更される可能性が低い指示(システム依存関係のインストールなど)を Dockerfile の先頭に配置します。

最適化された Dockerfile の例を次に示します。

FROM python:3.9-slim AS base

## システム依存関係のインストール
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  && rm -rf /var/lib/apt/lists/*

## 非ルートユーザーの作成
RUN useradd -m -s /bin/bash appuser
USER appuser

WORKDIR /app

## Python 依存関係のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

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

## ポートの公開とエントリポイントの定義
EXPOSE 8000
CMD ["python", "app.py"]

この例では、関連する指示をグループ化し、レイヤー数を最小限に抑え、イメージキャッシュを活用することで、より効率的な Dockerfile を作成しています。

Dockerfile で環境変数を管理する

Dockerfile で環境変数を定義する

Dockerfile で ENV 指令を使用して環境変数を定義できます。これにより、実行時にコンテナ内で利用可能な環境変数を設定できます。

ENV APP_ENV=production
ENV DB_HOST=postgres.example.com
ENV DB_PASSWORD=secret

環境変数の参照

Dockerfile で環境変数を定義したら、他の指示で $ 接頭辞を使用して参照できます。

ENV APP_ENV=production
COPY config.$APP_ENV.yml /app/config.yml

実行時に環境変数を上書きする

コンテナを実行する際に、-e フラグまたは --env フラグを使用して、実行時に環境変数を上書きすることもできます。

docker run -e DB_PASSWORD=newpassword labex/my-app:latest

環境変数を管理するためのベストプラクティス

Dockerfile で環境変数を管理するためのベストプラクティスを以下に示します。

  1. 説明的な変数名を使用する: 各変数の目的を理解しやすくするために、説明的で意味のある変数名を使用します。
  2. 機密情報と非機密情報を分離する: パスワードや API キーなどの機密情報は、Dockerfile の外部でシークレットまたは環境変数として保存します。
  3. 適切なデフォルト値を提供する: Dockerfile で環境変数のデフォルト値を設定し、実行時に上書きできるようにします。
  4. 環境変数を文書化する: プロジェクトの README またはドキュメントで、各環境変数の目的と期待される値を文書化します。

これらのベストプラクティスに従うことで、Dockerfile で環境変数を効果的に管理し、コンテナが正しく構成されていることを確認できます。

コンテナでのポート公開とコマンド実行

Dockerfile でポート公開する

コンテナ外のアプリケーションにアクセスできるようにするには、アプリケーションがリスニングしているポートを公開する必要があります。Dockerfile で EXPOSE 指令を使用して公開するポートを指定します。

EXPOSE 8000
EXPOSE 5432

このイメージに基づいてコンテナを実行すると、-p フラグまたは --publish フラグを使用して、公開されたポートをホストシステムにマッピングできます。

docker run -p 8000:8000 -p 5432:5432 labex/my-app:latest

コンテナ内でコマンドを実行する

Dockerfile で CMDENTRYPOINT 指令を使用して、コンテナ起動時に実行されるデフォルトコマンドを指定できます。

CMD 指令は、デフォルトコマンドとその引数を設定します。CMD 指令が使用されている場合、docker run コマンドはデフォルトコマンドを上書きできます。

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

ENTRYPOINT 指令は、コンテナ起動時に実行されるデフォルトアプリケーションを設定します。ENTRYPOINT コマンドは docker run コマンドによって上書きできませんが、引数を渡すことができます。

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

この例では、コンテナを実行すると、python app.py コマンドが実行されます。

docker run labex/my-app:latest

RUN 指令を使用して、ビルドプロセス中にコマンドを実行することもできます。これは、依存関係のインストールやアプリケーション環境の設定など、様々なタスクに役立ちます。

RUN apt-get update && apt-get install -y \
 build-essential \
 libpq-dev \
 && rm -rf /var/lib/apt/lists/*

コンテナでのポート公開とコマンド実行方法を理解することで、Docker 環境内でアプリケーションがアクセス可能で適切に構成されていることを確認できます。

Docker イメージへのファイルとディレクトリの複製

COPY 指令

Dockerfile の COPY 指令は、ホストマシン上のファイルやディレクトリを Docker イメージにコピーするために使用されます。COPY 指令の構文は次のとおりです。

COPY <src> <dest>

ここで、<src> はホストマシン上のファイルまたはディレクトリのパス、<dest> は Docker コンテナ内のファイルまたはディレクトリがコピーされる先のパスです。

COPY requirements.txt /app/
COPY . /app/

上記の例では、requirements.txt ファイルと現在のディレクトリ(.)全体が、Docker コンテナ内の /app/ ディレクトリにコピーされます。

ADD 指令

ADD 指令は COPY 指令と似ていますが、いくつかの追加機能があります。ADD 指令は、リモート URL からファイルのコピーが可能で、圧縮アーカイブ(例:.tar.gz.zip)を Docker イメージ内に直接展開することもできます。

ADD https://example.com/file.tar.gz /app/
ADD local_file.tar.gz /app/

上記の例では、file.tar.gz ファイルはリモート URL からダウンロードされ、/app/ ディレクトリに展開されます。また、local_file.tar.gz ファイルはコピーされて/app/ ディレクトリに展開されます。

ファイルコピーのベストプラクティス

Docker イメージへのファイルとディレクトリの複製時に考慮すべきベストプラクティスを以下に示します。

  1. COPY を ADD より優先する: 一般的に、COPY 指令を ADD より優先することをお勧めします。COPY はよりシンプルで、予期しない動作を起こしにくいからです。
  2. 必要なものだけコピーする: アプリケーションの実行に必要なファイルとディレクトリだけをコピーします。不要なファイルのコピーは、Docker イメージのサイズを増やすため避けてください。
  3. .dockerignore を使用: プロジェクトディレクトリに .dockerignore ファイルを作成し、Docker ビルドコンテキストに含めないファイルやディレクトリを指定します。
  4. ビルドキャッシュを活用する: Docker ビルドキャッシュを活用するように COPY 指令を配置します。変更される可能性が低いファイルのコピー指示を Dockerfile の先頭に配置します。

これらのベストプラクティスに従うことで、効率的で保守可能な、必要なファイルと依存関係のみを含む Docker イメージを作成できます。

保守可能な Dockerfile を記述するためのベストプラクティス

説明的な名前とコメントを使用する

Dockerfile と Docker イメージには、その目的を明確に伝える説明的な名前を付けましょう。さらに、Dockerfile の各セクションまたは指示の目的を説明するコメントを使用します。

## 最新のセキュリティアップデートを含むベースイメージを使用する
FROM ubuntu:22.04

## 必要な依存関係をインストールする
RUN apt-get update && apt-get install -y \
 build-essential \
 libpq-dev \
 && rm -rf /var/lib/apt/lists/*

## アプリケーションコードをコピーする
COPY . /app
WORKDIR /app

マルチステージビルドを活用する

マルチステージビルドを使用すると、単一の Dockerfile で複数の FROM 指令を使用できるため、より小さく効率的なイメージを作成できます。これは、特定のツールチェーンを使用してアプリケーションをビルドする必要がある場合に特に役立ちます。最終イメージにツールチェーン全体を含める必要はありません。

## ビルドステージ
FROM python:3.9-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

## 最終ステージ
FROM python:3.9-slim
COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages
COPY --from=builder /app /app
WORKDIR /app
CMD ["python", "app.py"]

環境変数を効果的に使用する

前述したように、環境変数を使用して構成設定を格納し、Dockerfile でそれらを管理するためのベストプラクティスに従います。

レイヤーとキャッシュを最適化する

Docker ビルドキャッシュを活用するように Dockerfile の指示を配置します。関連する指示をまとめて、変更される可能性が低い指示を Dockerfile の先頭に配置します。

.dockerignore を活用する

最終的な Docker イメージに必要なファイルやディレクトリを除外するために .dockerignore ファイルを使用します。これにより、ビルドコンテキストを削減し、ビルド時間を短縮できます。

Dockerfile を文書化および保守する

Dockerfile を適切に文書化します。イメージの目的、使用される環境変数、コンテナのビルドまたは実行のための特別な指示などを含めます。

これらのベストプラクティスに従うことで、理解しやすく、保守しやすく、拡張可能な Dockerfile を作成できます。これにより、Docker ベースのアプリケーションをより堅牢でスケーラブルなものにすることができます。

Dockerfile の一般的な問題のトラブルシューティング

構文エラー

Dockerfile の構文が正しいことを確認してください。一般的な構文エラーには、指示の欠落または誤り、引用符の欠落、インデントの誤りなどがあります。

## 構文エラーの例
FROM ubuntu:22.04
RUN apt-get update
    apt-get install -y build-essential

ビルド失敗

Docker ビルドが失敗した場合、エラーメッセージを確認して問題を特定します。一般的なビルド失敗の原因には、次のものがあります。

  • 必要な依存関係の欠落
  • ファイルパスの誤り
  • パーミッションの問題
  • ネットワーク接続の問題
## 依存関係の欠落によるビルド失敗の例
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    ## このパッケージが欠落しています
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

ランタイムの問題

Docker コンテナが期待どおりに動作しない場合、コンテナログを確認してエラーメッセージや予期しない動作がないか確認します。一般的なランタイムの問題には、次のものがあります。

  • 環境変数の誤り
  • ポートマッピングの誤り
  • パーミッションの問題
  • アプリケーション固有のエラー
## ポートマッピングの誤りによるランタイム問題の例
EXPOSE 8000
## コンテナを実行するときに、ポートが正しくマッピングされていません
docker run -p 8080:8000 labex/my-app:latest

Dockerfile のデバッグ

Dockerfile をデバッグするために、以下のテクニックを使用できます。

  1. docker build コマンドに --no-cache フラグを使用する。これにより、フルビルドを強制し、イメージキャッシュをバイパスできます。
  2. docker run コマンドに --rm フラグを使用する。これにより、コンテナが終了したら自動的に削除されるため、コンテナの状態を検査しやすくなります。
  3. docker logs コマンドを使用する。実行中のコンテナのログを表示します。
  4. docker exec コマンドを使用する。実行中のコンテナに入り、ファイルシステムを検査したり、追加のコマンドを実行したりできます。

一般的な Dockerfile の問題と適切なデバッグ手法を理解することで、Docker ベースのアプリケーションの問題を迅速に特定し解決できます。

まとめ

この Dockerfile チュートリアルを終了すると、Dockerfile の構文と構造をしっかりと理解し、独自の Docker イメージを作成および管理できるようになります。保守可能な Dockerfile を記述するためのベストプラクティス、および一般的な問題のトラブルシューティング手法を学習します。この知識があれば、Docker の力を活用して開発およびデプロイワークフローを効率化できます。