開発者のためのDocker: イメージ、コンテナ、Compose
あなたのマシンでは完璧に動作するWebアプリを構築したのに、サーバーにデプロイしたり、チームメイトと共有したりすると動作しなくなる。依存関係が欠けていたり、バージョンが競合したり、環境変数が間違っていたりします。これは典型的な「私のマシンでは動く」問題です。Dockerは、アプリケーションとその依存関係を「コンテナ」と呼ばれる標準化された単位にパッケージ化することでこれを解決します。このガイドでは、Dockerの核となる概念—イメージ、コンテナ、Compose—と、それらを使って開発ワークフローを効率化する方法を学びます。
Dockerとは?
Dockerは、アプリケーションをコンテナ内でビルド、実行、配布するためのプラットフォームです。コンテナは、ソフトウェアを実行するために必要なすべて(コード、ランタイム、システムツール、ライブラリ、設定)を含む、軽量で自己完結型の実行可能パッケージです。コンテナはアプリケーション同士や基盤となるインフラストラクチャから分離し、環境間での一貫性を保証します。
イメージとコンテナの違い
イメージは、コンテナを作成するための指示を含む読み取り専用のテンプレートです。アプリケーションとその環境のスナップショットのようなものです。コンテナはイメージの実行可能なインスタンスです。Docker APIまたはCLIを使用して、コンテナを作成、起動、停止、移動、削除できます。
イメージをクラス、コンテナをそのクラスのオブジェクト(インスタンス)と考えてください。同じイメージから複数のコンテナを実行でき、それぞれが他から分離されています。
Dockerfileでイメージをビルドする
Dockerfileは、イメージをビルドするための指示を含むテキストファイルです。以下はNode.jsアプリの簡単な例です:
# 公式のNode.jsランタイムを親イメージとして使用
FROM node:18-alpine
# 作業ディレクトリを設定
WORKDIR /app
# package.jsonとpackage-lock.jsonをコピー
COPY package*.json ./
# 依存関係をインストール
RUN npm install
# アプリケーションコードの残りをコピー
COPY . .
# アプリが実行されるポートを公開
EXPOSE 3000
# アプリを実行するコマンドを定義
CMD ["node", "server.js"]
イメージをビルドするには、次を実行します:
docker build -t my-node-app .
-tフラグはイメージに名前(my-node-app)をタグ付けします。最後の.はビルドコンテキスト(現在のディレクトリ)を指定します。
コンテナを実行する
イメージがあれば、コンテナを実行できます:
docker run -p 3000:3000 -d my-node-app
これはホストのポート3000をコンテナのポート3000にマッピングし、デタッチモード(-d)で実行します。
一般的なコマンド:
docker ps– 実行中のコンテナを一覧表示docker ps -a– すべてのコンテナ(停止中を含む)を一覧表示docker stop <container_id>– コンテナを停止docker rm <container_id>– コンテナを削除docker images– イメージを一覧表示docker rmi <image_id>– イメージを削除
ボリュームでデータを管理する
コンテナは一時的です。削除されるとデータは失われます。データを永続化するには、ボリュームを使用します。ボリュームは、コンテナのファイルシステム外のディレクトリで、Dockerによって管理されます。
docker run -v my_volume:/app/data my-node-app
開発用にホストディレクトリをマウント(バインドマウント)することもできます:
docker run -v $(pwd):/app my-node-app
Docker Compose: マルチコンテナアプリケーション
実際のアプリでは、Webサーバー、データベース、キャッシュなど、複数のサービスが必要になることがよくあります。Docker Composeを使用すると、YAMLファイルでマルチコンテナDockerアプリケーションを定義して実行できます。以下は、PostgreSQLデータベースを備えたNode.jsアプリのdocker-compose.ymlの例です:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
スタック全体を実行するには:
docker compose up -d
これにより、webサービスがビルドされ、Postgresイメージがプルされ、ネットワークが作成され、両方のコンテナが起動します。depends_onは、データベースがWebサービスより先に起動することを保証します。
コンテナ、ネットワーク、ボリュームを停止して削除するには:
docker compose down -v
開発におけるDockerのベストプラクティス
- .dockerignoreを使用する:
node_modulesや.gitなどのファイルをビルドコンテキストから除外します。 - マルチステージビルドを活用する:イメージを小さく保ちます。たとえば、あるステージでアプリをビルドし、本番アーティファクトのみをより小さなランタイムイメージにコピーします。
- バージョンを固定する:再現性のためにDockerfileでバージョンを固定します(例:
node:latestではなくnode:18-alpine)。 - 永続データにはボリュームを、開発中のライブコードリロードにはバインドマウントを使用する。
- コンテナをステートレスに保つ:状態はボリュームまたは外部サービスに保存します。
比較: Docker vs. 仮想マシン
| 側面 | Dockerコンテナ | 仮想マシン |
|---|---|---|
| 起動時間 | 秒 | 分 |
| リソース使用量 | 軽量(OSカーネルを共有) | 重量(VMごとに完全なOS) |
| 分離 | プロセスレベル | ハードウェアレベル |
| ポータビリティ | 高い(Dockerが動作する場所ならどこでも動作) | ハイパーバイザーの互換性に制限される |
FAQ
イメージとコンテナの違いは何ですか?
イメージは、アプリケーションとその環境を定義する読み取り専用のテンプレートです。コンテナはイメージの実行インスタンスです。同じイメージから複数のコンテナを作成できます。
Docker Composeはいつ使用すべきですか?
アプリケーションが連携する必要のある複数のサービス(例:Webサーバー、データベース、キャッシュ)で構成されている場合にDocker Composeを使用します。開発とテストのためのオーケストレーションを簡素化します。
Dockerでデータを永続化するにはどうすればよいですか?
コンテナのファイルシステム外にデータを永続化するには、ボリュームを使用します。ボリュームはDockerによって管理され、コンテナ間で共有できます。バインドマウントを使用してホストディレクトリをマウントすることもできます。
次のプロジェクトをコンテナ化する準備はできましたか?まず簡単なアプリのDockerfileを書き、次にDocker Composeでサービスを徐々に追加していきましょう。その他の開発者ツールについては、設定ファイルを検証して整形するJSON Formatterをチェックしてください。