ホストマシンとDockerコンテナで各種リソースを利用した環境での通信の整理

Django、nuxt.js、expressなどを利用したサンプル環境を次のような構成で構築してみました。

nuxt.js・・・SSR・フロントエンド
express、Django・・・APIサーバー

Djangoはホストマシンで稼働
nuxt.js,experssはDockerで稼働
MySQLは別コンテナで稼働

各リソース（Django,express,nuxt)の学習用に検討しながら組んだものですが、
この記事ではリソース間の通信部分について整理してみました。

Django、express、nuxtの諸々の部分はまた別途整理したいと思います

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/89a1936a-4148-1f4f-8008-824c3129a46b.png width=90%>

###ホストマシンからDockerコンテナへの通信
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/2dd69a9c-8760-f6b9-c6cb-b2c900d8f8c9.png width=90%>
Dockerを開発で使っていると一番よく使うケースと思いますが、
所定のポートを紐付けてコンテナを立ち上げてlocalhostでアクセスします。

MySQLコンテナ

```
docker run \
　・・・
  -p 13306:3306 \ #localhostの13306をコンテナ内の3306にバインド
　・・・
  -itd mysql:5.7
```
node.jsコンテナ

```
docker run \
　・・・
  -p 3000:3000 \ #localhostの3000をコンテナ内の3000にバインド
  -p 3001:3001 \ #localhostの3001をコンテナ内の3001にバインド
　・・・
  node:latest
```

nuxt.jsには3000ポートでアクセスします
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/3702c75b-5add-b431-eefc-7e3f27d4261a.png width=90%>

nuxt.jsからexpressへのアクセスは3001ポートでアクセスします
（ここは、ブラウザからの通信も、nuxt.jsのSSRでも同じでいけます）

```
  async fetch(context): Promise<void> {
    ・・・
    const api_host = 'http://localhost:3001'
    ・・・
    const response = await (context as any).$axios.$get(
      api_host + ・・・
    )
```

###ホストマシン内での通信
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/66d70dbe-67db-9aa6-450f-1a20ae37e067.png width=90%>
Djangoはホストマシン内のPythonの仮想環境で動かしています
ブラウザからの通信は同じホスト内通信なので、localhost:8000となります
これも普通ですね

ですが、この構成の時、nuxt.jsのSSR（process.server==true時)では
localhost:8000 では通信できません（後述）

```
 async fetch(context): Promise<void> {
    let api_host: string
    //サーバーサイドレンダリングのとき
    if (process.server) {
      api_host = ??????
    }
　　 //ブラウザからのアクセスの時
　　 else {
      api_host = 'http://localhost:8000'
    }
    const response = await (context as any).$axios.$get(
      api_host + ・・・
    )
```

###同一コンテナ内での通信
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/98928a90-b467-6c8f-dbf8-ed93c16e9b0b.png width=90%>
nuxt.jsのサーバーサイドレンダリング時に、nuxt.jsから同一コンテナ内のexpressに通信します
同一コンテナ内で3001でlistenしているexpressなので、localhost:3001で通信できます
（ブラウザからの通信時と同じです）

###コンテナ間通信
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/aae0e57c-a530-c9e4-cc69-aeb726d591fe.png width=90%>
node.jsコンテナからMySQLの別コンテナに通信します
この場合、コンテナ名でアクセスすれば3306ポートでアクセスできます

###コンテナからホストマシンへの通信
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/b22dee40-a170-a084-eb74-52ff7fb3672c.png width=90%>
この記事の本題のような部分です
この絵の中で、node.jsコンテナのlocalhostはコンテナ内を指します
では、nuxt.jsからSSRでDjangoへアクセスする術があるのか、ということになり詰まりました。

結論としては、
Docker Desktop Mac 環境ではこのホスト名でアクセスができました

```
http://host.docker.internal:8000
```
ただ、これはおそらく Docker Desktop（windows版でも？）で利用可能なホストのようです

windowsでも同じ構成のアプリを構築しているのですが、諸事情でwindowsでは Docker Desktopは
インストールしていなくて、virtualboxのcentosにDockerを入れて使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274034/c9d3fc5f-eff5-969b-fdd1-567de24cbe76.png)
この時は、コンテナ内からホストマシンへのアクセスに`host.docker.internal`は有効ではありませんでした。
コンテナから、virtualboxのcentosを通り越して、Windowsに通信する必要がありそうですが、
この解決については以下の記事がドンピシャで参考にさせていただきました
[Windows + VirtualBox + Docker で動作しているコンテナからホスト OS へのアクセス](http://takaya030.hatenablog.com/entry/2016/10/29/000647)

virtualboxのcentosで以下を叩きます

```
$ ip r
default via 10.0.2.2 dev eth0 proto dhcp metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-25ec00a7e9f1 proto kernel scope link src 172.18.0.1
172.19.0.0/16 dev br-94818cb53527 proto kernel scope link src 172.19.0.1
192.168.33.0/24 dev eth1 proto kernel scope link src 192.168.33.11 metric 101
```
`default via`がデフォルトゲートウェイになるようで、
このIP`10.0.2.2`を通してコンテナからWindowsへの通信ができました

```
http://10.0.2.2:8000
```

nuxt.js上では、Mac,windowsの環境毎に、.envで接続用のホストを定義して利用しています。
このあたりのコードの詳細は別途まとめたいと思っています。