#0153（2025/05/26）DockerコンテナからホストPCへアクセスする方法

# DockerコンテナからホストPCへアクセスする方法

## 1. はじめに

コンテナ化されたアプリケーションがホストマシン上で動作するサービスにアクセスする場面は少なくありません。例えば、ローカルで立ち上げたデータベース、モックサーバー、デバッグ用の HTTP サーバーなどです。本稿では、**ホスト ↔ コンテナ間通信の仕組みを理解した上で、macOS / Linux / Windows それぞれの最適解**を解説します。

---

## 2. 基礎知識 – Dockerネットワークの仕組み

Docker はデフォルトで `bridge` ネットワークを作成し、各コンテナを仮想ブリッジに接続します。ホスト側には

* Linux: `docker0` インターフェース（例: `172.17.0.1/16`）
* macOS / Windows: 軽量 VM 内に同等の仮想ブリッジ

が生成されます。

| OS      | ホスト側ブリッジ      | ホストアクセス用ホスト名           | 備考              |
| ------- | ------------- | ---------------------- | --------------- |
| macOS   | HyperKit VM 内 | `host.docker.internal` | DNS で解決         |
| Windows | WSL2 VM 内     | `host.docker.internal` | DNS で解決         |
| Linux   | `docker0`     | なし（IP 直打ち）             | `172.17.0.1` など |

---

## 3. macOS 編 – `host.docker.internal` の活用

Docker Desktop (macOS) では、ホストのゲートウェイアドレスを FQDN `host.docker.internal` として自動公開しています。

### 3.1 サンプル: HTTP サーバーへのアクセス

```bash
# ホスト側 (macOS) – ポート8000で HTTP サーバーを起動
python3 -m http.server 8000
```

**Dockerfile**

```Dockerfile
FROM python:3.12-slim
RUN apt-get update && apt-get install -y curl
CMD ["curl", "http://host.docker.internal:8000"]
```

```bash
# ビルド & 実行
$ docker build -t mac-host-access .
$ docker run --rm mac-host-access
```

### 3.2 Docker Compose での記述例

```yaml
services:
  app:
    image: python:3.12-slim
    command: ["curl", "http://host.docker.internal:8000"]
```

> Compose ファイルからでも同名で解決されるため追加設定は不要です。

### 3.3 制限とトラブルシューティング

* **VPN/Proxy**: corporate VPN で DNS が上書きされると名前解決に失敗する場合あり。
* **ファイアウォール**: macOS の PF またはアプリ固有 FW がポートをブロックしていないか確認。
* **複数ネットワーク**: `host.docker.internal` はデフォルトルートを指す。複数 NIC の場合はブリッジ経路を確認。

---

## 4. Linux 編 – `172.17.0.1` とカスタムブリッジネットワーク

Linux ではホスト OS に直接 Docker Engine が動作しており、ブリッジインターフェース `docker0` が生成されます。

### 4.1 docker0 インターフェースを確認する

```bash
$ ip addr show docker0
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 ...
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
```

### 4.2 サンプル: コンテナ → ホスト HTTP サーバー

```bash
# ホスト側
python3 -m http.server 8000

# コンテナ側（対話的に）
$ docker run --rm -it curlimages/curl http://172.17.0.1:8000
```

### 4.3 `--add-host` で名前解決を統一する

複数 OS で同一イメージを使いたい場合、Linux でも `host.docker.internal` を使えると便利です。

```bash
docker run --add-host=host.docker.internal:host-gateway \
           curlimages/curl http://host.docker.internal:8000
```

> Docker 20.10 以降は `host-gateway` キーワードで自動的にゲートウェイ IP が解決されます。

**Docker Compose (v3)**

```yaml
services:
  app:
    image: curlimages/curl
    extra_hosts:
      - "host.docker.internal:host-gateway"
    command: ["http://host.docker.internal:8000"]
```

---

## 5. Windows 編 – Docker Desktop / WSL2 環境

WSL2 をバックエンドに採用している Docker Desktop for Windows でも `host.docker.internal` が利用可能です。ただしネットワーク構造が複雑になるため注意点があります。

### 5.1 `host.docker.internal` 利用パターン

```powershell
# PowerShell でホスト側に HTTP サーバーを起動
PS> python -m http.server 8000

# コンテナからアクセス
> docker run --rm curlimages/curl http://host.docker.internal:8000
```

### 5.2 WSL2 内部ネットワークの挙動

* Docker Desktop が自動生成する NAT ネットワーク `172.28.0.0/20` などが存在。
* WSL2 ディストリビューションからは `localhost` → Windows ホストへ転送されるが、Docker VM からは異なる。

### 5.3 よくある落とし穴

| 症状                             | 原因                        | 解決策                   |
| ------------------------------ | ------------------------- | --------------------- |
| `host.docker.internal` が解決できない | WSL2 の DNS キャッシュ不整合       | `wsl --shutdown` で再起動 |
| ポートが到達しない                      | Windows Defender Firewall | 該当ポートを許可              |
| Proxy 環境で403/timeout           | システム環境変数 HTTP(S)\_PROXY   | コンテナ側に無効化設定を反映        |

---

## 6. 共通のベストプラクティス

1. **Listen Address を `0.0.0.0` に** – Flask や Node.js はデフォルトで `127.0.0.1` バインド。ホストからの接続を受け付けない。
2. **ポート競合監視** – `lsof -i :PORT` で既存プロセスを確認。
3. **Compose で環境変数置換** – OS ごとに異なる値を `.env` で切り替え。
4. **VPN / ZeroTrust** – 名前解決が阻害されるケースが多い。split‑tunnel 設定を推奨。
5. **セキュリティ** – 開発用途でも外部へ露出しないよう `ufw`/`pfctl` でローカル限定アクセスに。