【docker】好きなドメイン名(別名)でコンテナ間通信したい【compose】

Laravelの開発環境を`docker`で作っているのですが､先日[とある要件](https://qiita.com/KeisukeKudo/items/6d93c38a101a78faa7ca)のため､自由なドメイン名でコンテナ間通信をしなければならなくなりました｡
`docker`への理解がまだまだ足りないがために､ちょっとハマってしまったので備忘録として残したいと思います｡
# 構成
DB等省略している部分もありますが､`docker-compose`の構成はこんな感じです｡

```docker-compose.yml
version: '3'

services:
  nginx:
    build: ./nginx
    container_name: "laravel-nginx"
    environment:
      TZ: "Asia/Tokyo"
    ports:
      - "8080:80"
      - "443:443"
    volumes:
      - ./project:/var/www/html
  php:
    build: ./php
    container_name: "laravel-php"
    environment:
      TZ: "Asia/Tokyo"
    volumes:
      - ./project:/var/www/html
```
`laravel-php`コンテナにLaravelプロジェクトを配置し､`laravel-nginx`コンテナで配信する､というような構成です｡

# コンテナ間で自由なドメイン名でcurlとかしたい!
`laravel-php`にログインして`laravel-nginx`に`curl`するには､通常以下のような感じでOKです｡

```bash
$ docker-compose exec php /bin/bash
$ curl -k https://laravel-ngix/api/foo/bar
```
もちろん`laravel-nginx`の部分はコンテナのipアドレスでもOKです｡

では､何らかの理由で自由なドメイン名をつけてコンテナ間通信を行いたい場合はどうすれば良いのでしょう｡
単純にコンテナ名を変えれば良いのでしょうか
でもどこかに影響が出てしまったら嫌ですよね｡
そこでこんな感じにしてみます｡

### コンテナにドメイン名(別名)をつけてcurlとかする
答えはいつも[公式ドキュメント](https://docs.docker.com/compose/compose-file/#networks)にあります｡

```docker-compose.yml
version: '3'

services:
  nginx:
    build: ./nginx
    container_name: "laravel-nginx"
    environment:
      TZ: "Asia/Tokyo"
    ports:
      - "8080:80"
      - "443:443"
    volumes:
      - ./project:/var/www/html
    #ここを追加
    networks:
      default:
        aliases:
          - yoursukinanamae.local
  php:
    build: ./php
    container_name: "laravel-php"
    environment:
      TZ: "Asia/Tokyo"
    volumes:
      - ./project:/var/www/html
```
これでデフォルトネットワークで`yoursukinanamae.local`が名前解決できるようになりました｡
`docker-compose`を再起動して以下を実行してみてください｡

```bash
$ docker-compose exec php /bin/bash
$ curl -k https://yoursukinanamae.local/api/foo/bar
```
curlくんが元気に応答してくれるようになりました｡

`networks`キーは､別のネットワーク上のコンテナと通信するために使う機能という認識でしたが､場合によっては同一ネットワークに属するコンテナ間でも使いどころがあるんですね｡
いろいろと勉強になりました｡


# 以下読み飛ばしてもいいところ
何故上記のようなことを設定したかった､という話なので､興味がない方は読み飛ばしてください｡

私の環境で問題になったのは､ホストOSで`https://localhost/api/*`をPHPの**ソース上で実行**した場合です｡
※本記事の`docker-compose.yml`で環境構築し､Laravelをインストールして作っています｡

このようなAPIがあったとします｡

```routes/api.php
Route::get('/test', 'TestApiController@testApi')->name('test-api');
```
```TestApiController.php
public function testApi()
{
    // 何らかの処理
    return $json;
}
```
これを以下のように呼び出します｡

```TestWebController.php
public function testWeb()
{
    // https://localhost/api/test
    $url = route('test-api');
    $client = new \GuzzileHttp\Client();
    $response = $client->get($url);
    $content = $response->getBody()->getContents();
    $json = json_encode($content);

    return view('view');
}
```
上記はエラーになります｡
`$url`に格納されている値がアクセス可能なURLではないからです｡
`https://localhost/api/test`にアクセスできないというのはどういうことなのでしょうか
これはWebサーバーとAPサーバーが別々のコンテナであることが原因です｡

### リクエストを投げるべきIPアドレスが違う
PHPを実行しているコンテナ → `laravel-php`コンテナ(IP Address: 192.168.0.1)
Webサーバー → `laravel-nginx`コンテナ(IP Address: 192.168.0.2)

上記で実行した`localhost`のipアドレスは`192.168.01(laravel-php)`です｡
つまり､以下を実行したことと同意です｡

```bash:laravel-php
$ docker-compose exec php /bin/bash
$ curl -k https://localhost/api/test
// もしくは curl -k https://192.168.01/api/test
```
`laravel-php`は､PHPを実行しているだけで､Webサーバーは立っていません｡
そこにGETリクエストを投げたところで､応答があるわけがないのです｡
本当は`192.168.0.2(laravel-nginx)`に投げて欲しいのに......

### 解決するには
まず､コンテナのipアドレスを指定することを考えました｡
ですが考えてすぐ却下
立ち上げ直したらipアドレスは変わってしまいますしね｡

次に､コンテナ名を指定してみることを考えました｡
開発環境ですし､正直これでよかったのですが､せっかくならドメイン名っぽいの付けたいよねとなり､今回紹介した方法に落ち着きました｡

### WebサーバーコンテナにGETリクエストするように変更する
本記事で紹介した`docker-comose.yml`の設定が終わったら､Laravelの`.env`を以下のように変更します｡

```diff:.env
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
- APP_URL=https://localhost
+ APP_URL=https://yoursukinanamae.local
```
ここを変えないとPHPUnit実行時に､`route('name')`のドメインが変わってくれません｡

次に､ホストOSの`127.0.0.1(localhost)`をWebサーバーコンテナと同じドメイン名でアクセスできるようにします｡
そうすることで､ブラウザから実行した際に､`route('name')`で取得できるドメインが`https://yoursukinanamae.local`になります｡

`hosts`ファイルに記述します｡

私の環境はWindows 10なので､`hosts`ファイルは
`C:\Windows\System32\drivers\etc\host`
にあります｡
ちなみにMacやLinuxの場所は
`/etc/hosts`

`hosts`ファイルを管理者権限なり`sudo`なりで開き､以下を追加します｡

```hosts
127.0.0.1 yoursukinanamae.local
```
念の為､キャッシュをクリア

```cmd
C:\>ipconfig /flushdns
```
```bash:mac
// macはバージョンによってコマンド違うことがあるので注意
$ sudo killall -HUP nDNSResponder
```
```bash:linux
$ /etc/rc.d/init.d/network resatart
or
$ /etc/rc.d/init.d/network reload
```
上記で反映されないのならマシン再起動してください｡
これで設定は完了です｡

以上です｡



# 参考
[docker docs](https://docs.docker.com/compose/compose-file)
[どうしても hosts の設定が反映されない場合の12通りの確認事項](http://tooljp.com/qa/hosts-fail-comfirm-point-9080.html)
[Qiita: Macでhostsファイルを変更・反映](https://qiita.com/junker919/items/cc15653a681e2dcd79ea)
[調べ物メモは今日も山積み](https://yamazon.wordpress.com/2009/12/05/etchosts-%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E5%A4%89%E6%9B%B4%E3%82%92%E5%8F%8D%E6%98%A0%E3%81%95%E3%81%9B%E3%82%8B/)