Docker ComposeでコンテナのIPアドレスを固定に設定する

はじめに

Docker Composeでコンテナアプリケーションを構築する際、コンテナ間の通信やロードバランサーの設定で、特定のコンテナに固定IPアドレスを割り当てたい場合がある。

デフォルトでは、Docker Composeはコンテナに172.17.0.0/16のネットワークの範囲でIPアドレスを割り当てるため、コンテナの再起動のたびにIPアドレスが変更される可能性がある。
これにより、IPアドレスに依存した設定やアプリケーションで問題が発生することがある。

今回は、Docker Composeで特定のコンテナに固定IPアドレスを設定する方法を記載する。

環境

Windows 11 Professional
WSL2 Ubuntu 24.04 LTS
Docker Desktop 4.41.2 (191736)
Docker version 27.4.1-1
Docker Compose version v2.32.1

設定方法

カスタムネットワークの作成

コンテナに固定IPを設定するには、まずカスタムネットワークを定義する必要がある。デフォルトネットワークでは静的IPの設定ができないためである。

compose.yml
services:
  web:
    image: nginx:latest
    container_name: web_server
    networks:
      static_network:
        ipv4_address: 172.20.0.10

networks:
  static_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1

設定の詳細について

ネットワーク設定

networks:
  static_network:
    driver: bridge              # ネットワークドライバー
    ipam:                      # IP Address Management
      config:
        - subnet: 172.20.0.0/16    # サブネット範囲
          gateway: 172.20.0.1      # ゲートウェイアドレス

サービス設定

services:
  web:
    # ...existing code...
    networks:
      static_network:
        ipv4_address: 172.20.0.10  # 固定IPアドレス

設定例

Webアプリケーション + データベース構成

services:
  nginx:
    image: nginx:latest
    container_name: nginx_proxy
    ports:
      - "80:80"
    networks:
      app_network:
        ipv4_address: 172.25.0.10
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf

  web_app:
    image: node:18-alpine
    container_name: web_application
    working_dir: /app
    command: npm start
    networks:
      app_network:
        ipv4_address: 172.25.0.20
    volumes:
      - ./app:/app
    environment:
      - DB_HOST=172.25.0.30
      - DB_PORT=5432

  database:
    image: postgres:15
    container_name: postgres_db
    networks:
      app_network:
        ipv4_address: 172.25.0.30
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - db_data:/var/lib/postgresql/data

networks:
  app_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/16
          gateway: 172.25.0.1

volumes:
  db_data:

ロードバランサー構成

複数のWebサーバーに固定IPを設定し、ロードバランサーで分散する例

services:
  load_balancer:
    image: nginx:latest
    container_name: lb_nginx
    ports:
      - "80:80"
    networks:
      lb_network:
        ipv4_address: 172.30.0.10
    volumes:
      - ./lb.conf:/etc/nginx/nginx.conf
    depends_on:
      - web1
      - web2

  web1:
    image: httpd:latest
    container_name: web_server_1
    networks:
      lb_network:
        ipv4_address: 172.30.0.20
    volumes:
      - ./web1:/usr/local/apache2/htdocs

  web2:
    image: httpd:latest
    container_name: web_server_2
    networks:
      lb_network:
        ipv4_address: 172.30.0.21
    volumes:
      - ./web2:/usr/local/apache2/htdocs

networks:
  lb_network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.0.0/24
          gateway: 172.30.0.1

対応するNginxロードバランサー設定(lb.conf

lb.conf
upstream backend {
    server 172.30.0.20:80;
    server 172.30.0.21:80;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

複数ネットワークでの設定

一つのコンテナを複数のネットワークに参加させる場合

services:
  api_gateway:
    image: nginx:latest
    container_name: api_gateway
    ports:
      - "80:80"
    networks:
      frontend:
        ipv4_address: 192.168.1.10
      backend:
        ipv4_address: 192.168.2.10

  web_service:
    image: node:18-alpine
    container_name: web_service
    networks:
      frontend:
        ipv4_address: 192.168.1.20

  database_service:
    image: postgres:15
    container_name: db_service
    networks:
      backend:
        ipv4_address: 192.168.2.20
    environment:
      POSTGRES_DB: api_db
      POSTGRES_USER: api_user
      POSTGRES_PASSWORD: api_pass

networks:
  frontend:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.1.0/24
          gateway: 192.168.1.1

  backend:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.2.0/24
          gateway: 192.168.2.1

IPv6アドレスの設定

IPv6アドレスも同様に設定できる

services:
  web:
    image: nginx:latest
    container_name: ipv6_web
    networks:
      ipv6_network:
        ipv4_address: 172.20.0.10
        ipv6_address: 2001:db8::10

networks:
  ipv6_network:
    driver: bridge
    enable_ipv6: true
    ipam:
      config:
        - subnet: 172.20.0.0/16
          gateway: 172.20.0.1
        - subnet: 2001:db8::/64
          gateway: 2001:db8::1

動作確認とテスト

コンテナの起動

# docker-compose.ymlのあるディレクトリで実行
docker-compose up -d

IPアドレスの確認

# 特定のコンテナのIPアドレス確認
docker inspect <container_name> | grep IPAddress

# すべてのコンテナのネットワーク情報確認
docker-compose ps

# ネットワークの詳細確認
docker network ls
docker network inspect <network_name>

接続テスト

# コンテナ内からpingテスト
docker exec <container_name> ping [接続先のコンテナIP]

# コンテナ間の通信テスト
docker exec web_app curl http://[接続先のコンテナIP]:[接続先のコンテナポート]

トラブルシューティング

1. IPアドレスの競合

# エラー例
ERROR: Pool overlaps with other one on this address space

# 解決方法:異なるサブネットを使用
networks:
  my_network:
    ipam:
      config:
        - subnet: 172.21.0.0/16  # 別の範囲を指定

2. 既存ネットワークとの競合

# ネットワークの削除と再作成
docker-compose down
docker network prune
docker-compose up -d

3. IPアドレスの範囲外指定

# 正しい例:サブネット範囲内のIPを指定
networks:
  my_network:
    ipam:
      config:
        - subnet: 172.20.0.0/24   # /24なので172.20.0.1〜254が使用可能

services:
  web:
    networks:
      my_network:
        ipv4_address: 172.20.0.10  # 範囲内のIPを指定

注意事項やベストプラクティス

IPアドレスの範囲について

# プライベートIPアドレス範囲を使用
# 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

networks:
  secure_network:
    ipam:
      config:
        - subnet: 10.10.0.0/16     # 推奨
        # - subnet: 8.8.8.0/24     # パブリックIPは避ける

環境変数の活用

services:
  web:
    image: nginx:latest
    networks:
      app_network:
        ipv4_address: ${WEB_IP:-172.20.0.10}

networks:
  app_network:
    ipam:
      config:
        - subnet: ${SUBNET:-172.20.0.0/16}

対応する.envファイル

WEB_IP=172.20.0.10
DB_IP=172.20.0.20
SUBNET=172.20.0.0/16

参考

おわりに

Docker Composeでコンテナに固定IPアドレスを設定する方法を記載した。
固定IPにすることでIPアドレスを利用したアプリケーションも安定して動作させられるようになる。
このあたりは押さえておきたいなと思って備忘録としてメモした。

Hugo で構築されています。
テーマ StackJimmy によって設計されています。