LoginSignup
2
1

Dockerで「bind: address already in use」エラー

Posted at

概要

Dockerコンテナを立ち上げようとしたときに、bind: address already in useエラーが出た時の対処法。

エラー内容

  • docker-compose up --buildを実行したところ発生。
エラーメッセージ
Attaching to hoge-web
Error response from daemon: 

# ポートが使用できない
Ports are not available: 

# ポート3306が既に使用されているため、バインド(割り当て)できない
exposing port TCP 0.0.0.0:3306 -> 0.0.0.0:0: listen tcp 0.0.0.0:3306: bind: address already in use

解決方法

3つの選択肢がある。

  1. 既に使っているポートを停止する
  2. 今回立ち上げようとしていたポート番号を変更する
    • 👉ホストマシン(自分のPC等)とコンテナ内のポート番号両方
  3. 今回立ち上げようとしていたポート番号を変更する
    • 👉ホストマシン(自分のPC等)のみ

1. 既に使っているポートを停止する

  • 既にポート3306を使用しているプロセスを特定し、停止する。
    • MySQLなどのデータベースが既にポート3306を使用している可能性がある。

2. 今回立ち上げようとしていたポート番号を変更する
👉ホストマシン(自分のPC等)とコンテナ内のポート番号両方

  • docker-compose.ymlなどの設定ファイルで、コンテナが使用するポートを別のポートに変更する。

❓別のポート番号って何番使えばいいの🤔

以下のポイントを考慮するとよい。

  1. 標準ポートは避ける
    • よく使われる標準ポート(例えば、80番(HTTP)、443番(HTTPS)、22番(SSH)など)は避けるのが無難
  2. 未使用のポートを選ぶ
    • 一般的に1024番以降のポート番号はユーザーが自由に使用できる範囲
      • 1024から49151までのポート番号は「登録済みポート」としてIANA(Internet Assigned Numbers Authority)によって管理されているが、カスタムアプリケーションで使用してもいい
        • 例: 8080, 8081, 9090, 10000
        • 80809090などのポート番号は、開発者や運用者にとって馴染みがあり、覚えやすいという利点がある
      • 49152から65535までのポート番号は「動的/プライベートポート」として予約されており、ユーザーが自由に使用できる
        • 例: 49152, 49153, 50000, 60000
(例)docker-compose.yml
services:
  db:
    image: mysql:8.0
    ports:
      - '3307:3307' # 3306から変更!

ポート番号 こんな風に使われることが多い
8080 HTTPの代替ポートとしてよく使用される。開発環境やテスト環境で頻繁に使用されるポート。
8081 8080の代替ポートとして使用されることが多い。
9090 管理インターフェースやモニタリングツールなどで使用されることが多い。
10000 特定のカスタムアプリケーションや内部ツールで使用されることが多い。

3. 今回立ち上げようとしていたポート番号を変更する
👉ホストマシン(自分のPC等)のみ

このことを難しい言葉で言うとポートフォワーディングという。
(ネットワーク通信において特定のポート番号を別のポート番号に転送する技術)

(例)docker-compose.yml
services:
  db1:
    image: mysql:8.0
    ports:
      - '3307:3306'  # ホスト側のポート3307をコンテナ側のポート3306にマッピング

❓コンテナ側のポート番号は重複していていいの🤔

よい。

  • ホストマシン側のポートは一意である必要がある。
    • つまり、同じポート番号を複数のサービスやコンテナで同時に使用することはできない。
    • 使用すると冒頭のエラーが発生する。
  • コンテナ側のポートは、各コンテナが独立したネットワーク名前空間を持っているため、他のコンテナと重複しても問題ない。
    • 例えば、複数のコンテナがそれぞれポート3306を使用していても、それぞれのコンテナ内で独立して動作する。
      • 以下の例のように、コンテナ側のポート両方が3306を使っていても動作する
(例)docker-compose.yml
services:
  db1:
    image: mysql:8.0
    ports:
      - '3307:3306'  # ホスト側のポート3307をコンテナ側のポート3306にマッピング

  db2:
    image: mysql:8.0
    ports:
      - '3308:3306'  # ホスト側のポート3308をコンテナ側のポート3306にマッピング

❓そもそもDockerコンテナってオンライン?どこと繋がっているの?🤔

  • Dockerコンテナは、ホストマシン上で実行される仮想化された環境
    • コンテナはホストマシンのリソースを共有しながら、独立したネットワーク名前空間を持っている

🙋つまり、Dockerコンテナ自体はホストマシン上にあるよ

コンテナのネットワーク

  • ホストマシンとの接続
    • コンテナはホストマシンのネットワークインターフェースを通じて外部と通信する
    • docker-compose.ymlファイルで指定されたポートフォワーディングにより、ホストマシンの特定のポートがコンテナ内の特定のポートにマッピングされる
  • ブリッジネットワーク
    • デフォルトでは、Dockerはブリッジネットワークを使用する
    • これは、ホストマシンとコンテナ、そしてコンテナ同士を接続する仮想ネットワーク
    • ブリッジネットワーク内では、コンテナはIPアドレスを持ち、他のコンテナと通信できる

🙋名前空間を上手につかって、ホストマシン上でコンテナ間のネットワーク分離を実現しているよ

コンテナ間の通信

  • 同じネットワーク内のコンテナ
    • 同じDockerネットワークに接続されているコンテナは、互いにホスト名(サービス名)で通信できる
      • 例えば、docker-compose.yml ファイルで定義された db サービスに対して、web サービスから db:3306 のようにアクセスできる
  • 異なるネットワーク間のコンテナ
    • 異なるネットワークに接続されているコンテナ間で通信する場合、適切なネットワーク設定やポートフォワーディングが必要

外部との通信

  • インターネットアクセス
    • コンテナはホストマシンのネットワークインターフェースを通じてインターネットにアクセスできる
      • 例えば、コンテナ内のアプリケーションが外部APIにアクセスする場合、ホストマシンのネットワークを通じて通信が行われる
(例)docker-compose.yml

# ホストマシンのポート8080にアクセスすると、その通信はコンテナ内のポート80に転送する

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"  # ホストマシンのポート8080をコンテナ内のポート80にマッピング

🙋ブラウザでhttp://localhost:8080にアクセスすると、コンテナ内のNginxサーバーに接続されるよ

補足:外部とやりとりする時は、以下の情報を設定していくことが多い
  1. ポートフォワーディングの設定
    • portsキーを使用して、ホストマシンのポートとコンテナ内のポートをマッピング
      • (例)webサービスでは、ホストマシンのポート8080がコンテナ内のポート80にマッピング
  2. 環境変数の設定
    • environmentキーを使用して、コンテナ内のサービスに必要な環境変数を設定
      • (例)appサービスでは、NODE_ENVDATABASE_URLなどの環境変数を設定
  3. ボリュームの設定
    • volumesキーを使用して、データの永続化や設定ファイルの共有を行う
      • (例)dbサービスでは、データベースデータを永続化するためにdb_dataボリュームを使用
  4. ネットワークの設定
    • networksキーを使用して、カスタムネットワークを設定し、サービス間の通信を管理
      • (例)webサービスと appサービスはfrontendネットワークに接続され、appサービスとdbサービスはbackendネットワークに接続
docker-compose.yml
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"  # ホストマシンのポート8080をコンテナ内のポート80にマッピング
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf  # Nginxの設定ファイルを共有
    networks:
      - frontend

  app:
    build: ./app  # アプリケーションのDockerfileがあるディレクトリ
    ports:
      - "3000:3000"  # ホストマシンのポート3000をコンテナ内のポート3000にマッピング
    environment:
      - NODE_ENV=production
      - DATABASE_URL=mysql://user:password@db:3306/mydatabase
    volumes:
      - ./app:/usr/src/app  # アプリケーションコードを共有
    networks:
      - frontend
      - backend

  db:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=mydatabase
      - MYSQL_USER=user
      - MYSQL_PASSWORD=password
    ports:
      - "3306:3306"  # ホストマシンのポート3306をコンテナ内のポート3306にマッピング
    volumes:
      - db_data:/var/lib/mysql  # データベースデータの永続化
    networks:
      - backend

networks:
  frontend:
  backend:

volumes:
  db_data:
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1