エンジアップ エンジアップ

もう迷わない。ITエンジニアのための総合情報サイト

Docker入門:コンテナ技術の基本からDocker Composeまで丁寧に解説
投稿
X LINE B! f

Docker入門:コンテナ技術の基本からDocker Composeまで丁寧に解説

「自分のPCでは動いたのに」を終わらせたい

エンジニアなら一度は言ったか、言われたことがあるはずです。「自分のMacでは動いているんですが、本番サーバーに上げたら動かなくて……」。原因はたいていの場合、Python や Node.js のバージョン違い、ライブラリのインストール漏れ、OSの差異、環境変数の設定ミスなど、ありふれたものです。しかしその原因を特定して解消するまでに、半日や1日が消えていくこともざらにあります。

Dockerはこの問題を根本から解決するツールです。「どの環境でも同じように動く」というコンテナの思想を一度理解してしまえば、開発・テスト・本番のすべてで同一の実行環境を使い回せるようになります。この記事では、Dockerの仕組みをゼロから丁寧に解説し、実際にWebアプリをコンテナで動かすところまで一緒に進めていきます。

Dockerとは何か

仮想マシンとの違い

Dockerを説明するとき、よく仮想マシン(VM)との比較が使われます。仮想マシンはハイパーバイザーというソフトウェアの上でOSごと仮想化します。それに対してDockerは「コンテナ」という単位でアプリケーションとその依存関係だけを隔離します。OSカーネルはホストマシンのものを共有するため、仮想マシンよりはるかに軽量で起動も速いのが特徴です。

比較項目仮想マシン(VM)Dockerコンテナ
起動速度数十秒〜数分数秒以内
ディスク使用量数GB〜数十GB数十MB〜数百MB
OSの共有各VMが独自OSを持つホストOSのカーネルを共有
隔離レベル高い中程度
用途異なるOSが必要な場合アプリの実行環境統一

イメージとコンテナの関係

Dockerを理解するうえで最も重要な概念が「イメージ」と「コンテナ」の区別です。

イメージは、アプリケーションを動かすために必要なOS・ライブラリ・コード・設定をすべて含んだ「読み取り専用のテンプレート」です。プログラミングでいえばクラスに相当します。

コンテナは、そのイメージを実際に起動して動いている状態のことです。クラスからインスタンスを作るのと同じように、1つのイメージから複数のコンテナを起動することができます。コンテナを停止・削除しても、イメージ自体は変化しません。

Dockerfileを書いてみる

Dockerイメージは Dockerfile というテキストファイルで定義します。このファイルに「どのOSを使うか」「どんなソフトウェアをインストールするか」「どのコマンドで起動するか」を記述します。

シンプルなNode.jsアプリのDockerfile

# ベースイメージを指定(Node.js 20のLTS版)
FROM node:20-alpine

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

# 依存関係ファイルを先にコピー(キャッシュ効率化)
COPY package.json package-lock.json ./

# 依存パッケージをインストール
RUN npm ci --only=production

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

# コンテナ外に公開するポート番号を宣言
EXPOSE 3000

# コンテナ起動時に実行するコマンド
CMD ["node", "server.js"]

このDockerfileをビルドしてイメージを作成するコマンドは以下のとおりです。

# イメージをビルド(-t でイメージ名を指定)
docker build -t myapp:latest .

# ビルドしたイメージを確認
docker images

# コンテナを起動(-p でポートを公開、-d でバックグラウンド実行)
docker run -d -p 3000:3000 --name myapp-container myapp:latest

# 動作確認
curl http://localhost:3000

Dockerfileの書き方のコツ

COPY package.jsonCOPY . . より前に書くのには理由があります。Dockerはビルドの各ステップをキャッシュしており、ファイルに変更がなければ前回のキャッシュを再利用します。package.json が変わっていなければ npm ci のステップはキャッシュが使われるため、ソースコードだけを変更した場合のビルドが大幅に速くなります。この「頻繁に変わるものを後ろに書く」というパターンは、ビルド時間を短縮するうえで非常に重要なテクニックです。

また node:20-alpine のように末尾に -alpine が付くものは、Alpine Linuxベースの軽量イメージです。通常の node:20 が1GB超えるのに対し、node:20-alpine は150MB程度に収まります。本番環境では基本的にalpineベースを選ぶようにしましょう。

Docker Composeで複数コンテナを管理する

実際のWebアプリは、アプリサーバー・データベース・キャッシュサーバーなど複数のサービスが連携して動くことがほとんどです。これらを個別に docker run で起動するのは煩雑です。そこで Docker Compose を使います。

# docker-compose.yml
version: "3.9"

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache

  db:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=mydb

  cache:
    image: redis:7-alpine

volumes:
  postgres_data:

このファイルを用意しておけば、以下のコマンド一発でアプリ・DB・Redisの3つが一斉に起動します。

# すべてのサービスをバックグラウンドで起動
docker compose up -d

# ログを確認
docker compose logs -f app

# すべてのサービスを停止・削除
docker compose down

depends_on を指定すると、dbcache が起動してから app が起動するようになります。ただし「起動した」というのはプロセスが始まったという意味であり、「DBが接続を受け付ける準備ができた」という意味ではない点に注意が必要です。本番環境では接続リトライのロジックをアプリ側に組み込むことが推奨されます。

知っておくべきDockerの基本コマンド

日常的に使うコマンドをまとめておきます。最初は多く感じるかもしれませんが、実際に手を動かしていると自然に身につきます。

コマンド意味
docker build -t 名前 .カレントディレクトリのDockerfileでイメージをビルド
docker run -d -p 外:内 イメージ名コンテナをバックグラウンドで起動
docker ps実行中のコンテナ一覧を表示
docker ps -a停止中を含む全コンテナを表示
docker logs コンテナ名コンテナのログを表示
docker exec -it コンテナ名 sh実行中のコンテナに入ってシェル操作
docker stop コンテナ名コンテナを停止
docker rm コンテナ名停止済みコンテナを削除
docker imagesローカルのイメージ一覧
docker rmi イメージ名イメージを削除

特に docker exec -it コンテナ名 sh はデバッグ時に非常に役立ちます。コンテナの中に入って、ファイルが正しく配置されているか・環境変数が設定されているかを直接確認できます。

開発現場でDockerを使う際の注意点

データの永続化はボリュームで

コンテナを削除すると、コンテナ内で作成されたデータもすべて消えます。データベースのデータやアップロードされたファイルなど、永続化が必要なデータは必ず volumes を使ってホストマシン側に保存するようにしましょう。先ほどの docker-compose.ymlpostgres_data というボリュームを定義しているのがその例です。

.dockerignoreを必ず作る

.gitignore と同様に .dockerignore を作成し、イメージに含めたくないファイルを除外します。node_modules.git・テストファイル・ローカルの設定ファイルなどを除外することで、イメージサイズの削減とビルド速度の向上が期待できます。

node_modules
.git
.env.local
*.test.js
coverage/

まとめ

Dockerは「環境の差異による問題」を根本から解消してくれるツールです。最初はコマンドや概念が多く感じるかもしれませんが、Dockerfile・docker compose up という2つの武器を使いこなせるようになれば、開発体験は大きく変わります。

チームに新しいメンバーが加わったとき、環境構築に丸1日かかっていたのが docker compose up -d の1コマンドで終わるようになる、それだけでも導入する価値は十分あります。まずは手元の個人プロジェクトで試してみることから始めてみてください。