Docker Composeのネットワーク接続エラーを完全解決!設定方法とトラブルシューティング

Docker

Docker Composeのネットワーク接続エラーを完全解決!設定方法とトラブルシューティング

はじめに

Docker Composeを使ってマルチコンテナアプリケーションを構築している際、コンテナ間の通信がうまくいかないというエラーに遭遇した経験はありませんか?このネットワーク関連のエラーは、初心者から経験者まで多くの開発者が経験する一般的な問題です。本記事では、Docker Composeのネットワーク接続エラーの原因から解決方法まで、わかりやすく解説します。

Docker Composeネットワークエラーの原因

1. デフォルトネットワークの理解不足

Docker Composeを起動すると、自動的にプロジェクト用の独立したネットワークが作成されます。このネットワーク内でのみ、コンテナ間の通信が可能になります。外部のネットワークやホストマシンとの通信が必要な場合は、明示的な設定が必要です。

2. サービス名によるホスト名解決の失敗

Docker Composeでは、docker-compose.ymlに定義したサービス名が、コンテナ内でのホスト名として機能します。しかし、このホスト名解決が失敗する場合があります。主な原因は以下の通りです:

  • ネットワークが正しく設定されていない
  • サービス名のタイプミス
  • コンテナがまだ起動していない状態でのアクセス試行
  • 異なるネットワークのコンテナ間での通信試行

3. ポートマッピングとポート公開の混同

ports設定とexpose設定の違いを理解していないことが原因になります。portsはホストマシンへのポート公開、exposeはコンテナ内ネットワークへのポート公開です。

4. ネットワークドライバーの非互換性

Docker Composeで指定できるネットワークドライバー(bridge、overlay等)が、目的に合致していない場合も考えられます。

Docker Composeネットワークの基本概念

デフォルトネットワーク動作

Docker Composeを実行すると、以下のプロセスが自動的に行われます:

  1. プロジェクト用のブリッジネットワークが自動作成される
  2. 各サービスがこのネットワークに接続される
  3. DNS サーバーが起動し、サービス名解決が有効になる
  4. 同じネットワーク内のコンテナは、サービス名でお互いに通信可能

ホスト名解決のメカニズム

Docker Composeネットワーク内では、各コンテナは以下のホスト名で参照可能です:

  • サービス名(例:db、web)
  • コンテナ名(例:myproject_db_1)
  • サービス名.ネットワーク名

解決手順

ステップ1:docker-compose.ymlの基本設定を確認

まず、docker-compose.ymlファイルが正しく構成されているか確認しましょう。バージョンとサービス定義が必須です。

version: '3.8'

services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    networks:
      - app-network

  db:
    image: postgres:13
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

ステップ2:ネットワーク設定を明示的に定義

ネットワークセクションで明示的にネットワークを定義することで、コンテナ間通信がより安定します。

version: '3.8'

services:
  api:
    build: ./api
    container_name: api_container
    ports:
      - "3000:3000"
    networks:
      - backend
    depends_on:
      - database

  database:
    image: mysql:8.0
    container_name: db_container
    environment:
      MYSQL_ROOT_PASSWORD: root_pass
      MYSQL_DATABASE: mydb
    networks:
      - backend
    volumes:
      - db_data:/var/lib/mysql

networks:
  backend:
    driver: bridge

volumes:
  db_data:

ステップ3:depends_onで起動順序を制御

コンテナの起動順序を指定することで、接続エラーを防げます。

version: '3.8'

services:
  web:
    image: nginx:latest
    depends_on:
      - app
    networks:
      - app-network

  app:
    build: .
    depends_on:
      - redis
    networks:
      - app-network

  redis:
    image: redis:7
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

ステップ4:接続確認とデバッグ

コンテナ内から実際に接続可能かテストします。

# コンテナ内でシェルを実行
docker-compose exec web bash

# サービス名でpingテスト
ping db

# DNS解決を確認
nslookup db

# ポート接続を確認
nc -zv db 5432

実践的なコード例

例1:Node.js + PostgreSQL の構成

version: '3.8'

services:
  nodejs_app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: nodejs_app
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:password@postgres:5432/mydb
      - NODE_ENV=development
    depends_on:
      - postgres
    networks:
      - app-network
    volumes:
      - ./src:/app/src

  postgres:
    image: postgres:14-alpine
    container_name: postgres_db
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    networks:
      - app-network
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  app-network:
    driver: bridge

volumes:
  postgres_data:

Node.jsアプリケーションからの接続例:

// connection.js
const { Pool } = require('pg');

const pool = new Pool({
  user: 'user',
  password: 'password',
  host: 'postgres',  // サービス名を使用
  port: 5432,
  database: 'mydb'
});

pool.query('SELECT NOW()', (err, result) => {
  if (err) {
    console.error('Connection error:', err);
  } else {
    console.log('Connected:', result.rows);
  }
});

例2:複数ネットワークの構成

version: '3.8'

services:
  web:
    image: nginx:latest
    networks:
      - frontend
    ports:
      - "80:80"

  api:
    build: ./api
    networks:
      - frontend
      - backend
    depends_on:
      - database

  database:
    image: postgres:13
    networks:
      - backend
    environment:
      POSTGRES_PASSWORD: secret

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

例3:環境変数を使用した柔軟な設定

version: '3.8'

services:
  web:
    build: ./web
    ports:
      - "${WEB_PORT}:3000"
    environment:
      - DB_HOST=${DB_HOST:-database}
      - DB_PORT=${DB_PORT:-5432}
      - DB_NAME=${DB_NAME:-mydb}
    networks:
      - app-network
    depends_on:
      - database

  database:
    image: postgres:${POSTGRES_VERSION:-13}
    environment:
      POSTGRES_DB: ${DB_NAME:-mydb}
      POSTGRES_PASSWORD: ${DB_PASSWORD:-password}
    networks:
      - app-network
    volumes:
      - db_data:/var/lib/postgresql/data

networks:
  app-network:
    driver: bridge

volumes:
  db_data:

.envファイル:

WEB_PORT=8080
DB_HOST=database
DB_PORT=5432
DB_NAME=production_db
DB_PASSWORD=secure_password
POSTGRES_VERSION=14

よくある間違いと対処法

間違い1:localhost でのアクセス試行

❌ 間違ったコード:

const connection = mysql.createConnection({
  host: 'localhost',  // これは間違い
  user: 'root',
  password: 'password',
  database: 'mydb'
});

✅ 正しいコード:

const connection = mysql.createConnection({
  host: 'database',  // docker-compose.ymlで定義したサービス名
  user: 'root',
  password: 'password',
  database: 'mydb'
});

間違い2:ネットワーク設定の省略

❌ 間違ったコード:

version: '3.8'

services:
  web:
    image: nginx:latest

  db:
    image: postgres:13
    # ネットワーク設定がない場合、通信が不安定になる可能性がある

✅ 正しいコード:

version: '3.8'

services:
  web:
    image: nginx:latest
    networks:
      - app-network

  db:
    image: postgres:13
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

間違い3:ポート設定の混同

❌ 間違ったコード:

services:
  api:
    build: .
    ports:
      - "3000:3000"
    # ポート3000はホストに公開されるが、
    # コンテナから別のコンテナへアクセスする際は
    # ホストのポートではなく、コンテナのポート3000を使用

✅ 正しい理解:

services:
  api:
    build: .
    expose:
      - "3000"  # コンテナネットワーク内で公開
    ports:
      - "3000:3000"  # ホストマシンにも公開

  consumer:
    build: ./consumer
    # api コンテナにアクセスする際
    # http://api:3000 を使用(expose/ports に関わらず)

間違い4:起動順序の制御なし

❌ 間違ったコード:

version: '3.8'

services:
  app:
    build: .
    # depends_on がないため、db より先に起動しようとする可能性がある

  db:
    image: postgres:13

✅ 正しいコード:

version: '3.8'

services:
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:13
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

トラブルシューティング コマンド集

ネットワーク接続エラーをデバッグする際に役立つコマンド:

# 1. ネットワーク一覧を表示
docker network ls

# 2. 特定のネットワーク詳細を表示
docker network inspect project_app-network

# 3. コンテナ間接続テスト
docker-compose exec web curl http://api:3000

# 4. DNS解決をテスト
docker-compose exec web getent hosts db

# 5. ネットワークインターフェース確認
docker-compose exec web ip addr

# 6. ポート開放状況の確認
docker-compose exec api netstat -tlnp

# 7. コンテナログの確認
docker-compose logs api

# 8. 特定サービスのみログ表示
docker-compose logs -f api

# 9. コンテナを再起動
docker-compose restart api

# 10. ネットワークを再作成(完全なクリーンアップ)
docker-compose down
docker-compose up -d

ベストプラクティス

1. 明示的なネットワーク定義

常にnetworksセクションを明示的に定義し、サービスをそのネットワークに接続しましょう。

2. ヘルスチェックの実装

データベースなどのサービスにはhealthcheckを設定し、完全な起動を待つようにします。

3. 環境変数の活用

.envファイルを使用して、設定を柔軟に管理します。

4. 接続リトライロジック

アプリケーション側でも、サービスへの接続にリトライロジックを実装します。

// リトライロジックの実装例
async function connectWithRetry(config, maxRetries = 5) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const connection = await createConnection(config);
      console.log('Connected successfully');
      return connection;
    } catch (error) {
      console.log(`Attempt ${i + 1} failed, retrying...`);
      if (i === maxRetries - 1) throw error;
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }
}

5. 本番環境への適用

ローカル開発での成功をそのまま本番環境に適用せず、セキュリティとスケーラビリティを考慮した設定に変更します。

まとめ

Docker Composeのネットワーク接続エラーは、適切な設定と理解があれば十分に解決できる問題です。本記事で解説した以下のポイントを押さえることが重要です:

  • 自動ネットワーク作成の理解:Docker Composeはプロジェクト用のブリッジネットワークを自動作成し、サービス名でのホスト名解決を提供します
  • 明示的な設定:ネットワークを明示的に定義することで、より安定した構成が実現できます
  • localhost ではなくサービス名:コンテナ間通信ではlocalhost ではなく、docker-compose.yml で定義したサービス名を使用します
  • 起動順序の制御:depends_on とhealthcheck で起動順序と準備完了状態を管理します
  • デバッグ手法:docker-compose logs や exec コマンドで、問題を効率的に診断できます

これらのベストプラクティスを実装することで、Docker Compose を使ったマルチコンテナアプリケーション開発がより安定し、生産性が向上します。問題が発生した場合は、提供したトラブルシューティングコマンドを活用し、段階的に問題を解決していくことをお勧めします。

Docker Compose のネットワーク機能を完全に理解することで、スケーラブルで保守性の高いコンテナアプリケーションを構築できるようになるでしょう。

タイトルとURLをコピーしました