🖥️

【3-5】Docker Compose実践編!WordPressとNode.js環境をコードで構築

に公開

Docker Compose実践編!WordPressとNode.js環境をコードで構築

はじめに

前回の記事では、docker-compose.ymlの基本を学び、コマンド一発で複数のコンテナを起動・停止する強力さを体験しました。
https://zenn.dev/koikoi_infra/articles/ebcf0cfd1473c7
今回はその知識をさらに発展させ、より実践的なマルチコンテナアプリケーションを2種類構築していきます。一つは世界中で愛用されているCMS 「WordPress」の本格的な実行環境。もう一つは、モダンな開発で人気の 「Node.js + MongoDB + Redis」 という開発スタックです。

この記事では、Dockerfileとの連携や、コンテナ間の接続設定など、実務で必須となるDocker Composeの応用テクニックを、具体的なアプリケーションの構築を通じて習得します。

実践①: WordPress + MySQL + phpMyAdmin構成

ブログやWebサイトを構築するための本格的な環境を、Docker Composeで一気に立ち上げます。

Step 1: docker-compose.ymlの設計と作成

WordPress本体、データベース(MySQL)、データベース管理ツール(phpMyAdmin)の3つのサービスを連携させるための設計図を作成します。

# 作業ディレクトリを作成して移動
cd ~
mkdir ~/wordpress-compose
cd ~/wordpress-compose

# docker-compose.ymlを作成
cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  # --- WordPress本体のサービス ---
  wordpress:
    image: wordpress:latest
    container_name: my-wordpress
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress_pass
      WORDPRESS_DB_NAME: wordpress_db
    volumes:
      - wordpress-data:/var/www/html
    depends_on:
      - db
    networks:
      - wp-network

  # --- データベース(MySQL)のサービス ---
  db:
    image: mysql:8.0
    container_name: wp-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: wordpress_db
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_pass
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - wp-network

  # --- DB管理ツール(phpMyAdmin)のサービス ---
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: wp-phpmyadmin
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      PMA_USER: root
      PMA_PASSWORD: root_password
    depends_on:
      - db
    networks:
      - wp-network

volumes:
  wordpress-data:
  mysql-data:

networks:
  wp-network:
    driver: bridge
EOF
環境変数はどのように連携しているのか?

この設定の核心はwordpressサービスとdbサービスのenvironmentセクションにあります。なぜこれらの値は対応している必要があるのでしょうか?

答えは、「wordpressコンテナがdbコンテナの『クライアント』だから」です。

wordpressイメージは、「起動時にこれらの環境変数があったら、その情報を使ってデータベースに接続しに行く」ようにプログラムされています。一方、mysqlイメージは「起動時にこれらの環境変数があったら、その情報でデータベースとユーザーを初期作成する」ように作られています。

つまり、私たちは2つの異なるコンテナ(プログラム)に、それぞれが必要とする形式で、同じ接続情報を教えてあげているのです。

wordpressサービス(接続する側)の質問 dbサービス(接続される側)の回答
WORDPRESS_DB_HOST: DBサーバーはどこ? services:で定義したdbというサービス名
WORDPRESS_DB_USER: ユーザー名は? MYSQL_USER: wordpressというユーザーを作っておく
WORDPRESS_DB_PASSWORD: パスワードは? MYSQL_PASSWORD: パスワードはwordpress_passだよ
WORDPRESS_DB_NAME: データベース名は? MYSQL_DATABASE: wordpress_dbというDBを作っておく

このように、片方で「作成するユーザー情報」、もう片方で「接続しにいくユーザー情報」を正確に一致させることで、2つのコンテナは初めて正しく連携できるのです。

Step 2: 環境の起動とデータ永続化の確認

# WordPress環境を起動
docker compose up -d

ブラウザでhttp://192.168.3.101:8080にアクセスし、WordPressの初期設定を完了させます。簡単なテスト投稿を一つ作成した後、docker compose downで一度環境を破棄し、再度docker compose up -dで立ち上げてみましょう。

以前作成した投稿がそのまま表示されれば、volumesによってデータが正しく永続化されている証拠です。

実践②: Node.js + MongoDB + Redis 開発環境

次に、Dockerfileと連携させ、よりモダンなWebアプリケーション開発で使われる技術スタックを構築します。

Step 1: Node.js APIの準備

catコマンドで、APIサーバーのソースコード(package.json、server.js)、そしてビルドするためのDockerfileを一気に作成します。

# 作業ディレクトリとソースコード一式を作成
cd ~
mkdir -p ~/node-mongo-redis/app
cd ~/node-mongo-redis

# package.json の作成
cat > app/package.json << 'EOF'
{
  "name": "node-api-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": { "start": "node server.js" },
  "dependencies": {
    "express": "^4.18.0",
    "mongoose": "^7.0.0",
    "redis": "^4.6.0"
  }
}
EOF

# server.js の作成
cat > app/server.js << 'EOF'
const express = require('express');
const mongoose = require('mongoose');
const redis = require('redis');
const app = express();
const port = 3000;
// MongoDB接続 (mongoはサービス名)
mongoose.connect('mongodb://mongo:27017/testdb');
// Redis接続 (redisはサービス名)
const client = redis.createClient({ url: 'redis://redis:6379' });
client.connect();
app.get('/', async (req, res) => {
  res.json({ message: 'Node.js + MongoDB + Redis API', status: 'running' });
});
app.listen(port, () => {
  console.log(`API server running at http://localhost:${port}`);
});
EOF

# Dockerfile の作成
cat > app/Dockerfile << 'EOF'
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
EOF

Step 2: フルスタック環境のdocker-compose.yml作成

Node.js API、MongoDB、Redis、そしてDB管理ツールの4つのサービスを連携させるdocker-compose.ymlを作成します。

cat > docker-compose.yml << 'EOF'
version: '3.8'

services:
  # --- 自作のNode.js APIサービス ---
  api:
    build: ./app
    container_name: node-api
    ports:
      - "3000:3000"
    volumes:
      - ./app:/app
      - /app/node_modules
    depends_on:
      - mongo
      - redis
    networks:
      - dev-network

  # --- MongoDBサービス ---
  mongo:
    image: mongo:latest
    container_name: dev-mongo
    volumes:
      - mongo-data:/data/db
    networks:
      - dev-network

  # --- Redisサービス ---
  redis:
    image: redis:alpine
    container_name: dev-redis
    volumes:
      - redis-data:/data
    networks:
      - dev-network

  # --- MongoDB管理ツール ---
  mongo-express:
    image: mongo-express
    container_name: mongo-admin
    ports:
      - "8082:8081"
    environment:
      ME_CONFIG_MONGODB_SERVER: mongo
    depends_on:
      - mongo
    networks:
      - dev-network

volumes:
  mongo-data:
  redis-data:

networks:
  dev-network:
    driver: bridge
EOF
開発効率を上げる高度なvolumes設定

このapiサービスのvolumes設定は、開発効率を劇的に向上させるための重要なテクニックです。

volumes:
  - ./app:/app
  - /app/node_modules

./app:/app: ホストOSのappディレクトリをコンテナの/appにマウントします。これにより、ホスト側でソースコード(例: server.js)を編集すると、コンテナを再起動することなく即座に変更が反映されます(ホットリロード)。

/app/node_modules: こちらは「名前なしボリューム」です。Dockerfile内のRUN npm installでインストールされたコンテナ内のnode_modulesを、ホスト側の空のnode_modulesで上書きしてしまうのを防ぎます。これにより、コンテナは自身のnode_modulesを使い続け、ホスト側は汚染されません。

Step 3: 開発環境の起動と動作確認

build:ディレクティブを使っているため、--buildオプション付きで起動します。

docker compose up -d --build

ターミナルからcurl http://localhost:3000を実行してAPIからの応答を確認し、ブラウザでhttp://192.168.3.101:8082にアクセスしてMongo Expressの管理画面が表示されることを確認しましょう。

まとめ

Docker Composeを使いこなすことで、複雑なアプリケーション環境でも、誰でも、どこでも、コマンド一発で再現できるようになりました。これは、現代の開発・運用において非常に強力な武器となります。

Discussion