Laravelの開発環境をdocker
で作っているのですが、先日とある要件のため、自由なドメイン名でコンテナ間通信をしなければならなくなりました。
docker
への理解がまだまだ足りないがために、ちょっとハマってしまったので備忘録として残したいと思います。
構成
DB等省略している部分もありますが、docker-compose
の構成はこんな感じです。
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です。
$ docker-compose exec php /bin/bash
$ curl -k https://laravel-ngix/api/foo/bar
もちろんlaravel-nginx
の部分はコンテナのipアドレスでもOKです。
では、何らかの理由で自由なドメイン名をつけてコンテナ間通信を行いたい場合はどうすれば良いのでしょう。
単純にコンテナ名を変えれば良いのでしょうか
でもどこかに影響が出てしまったら嫌ですよね。
そこでこんな感じにしてみます。
コンテナにドメイン名(別名)をつけてcurlとかする
答えはいつも公式ドキュメントにあります。
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
を再起動して以下を実行してみてください。
$ 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があったとします。
Route::get('/test', 'TestApiController@testApi')->name('test-api');
public function testApi()
{
// 何らかの処理
return $json;
}
これを以下のように呼び出します。
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)
です。
つまり、以下を実行したことと同意です。
$ 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
を以下のように変更します。
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
なりで開き、以下を追加します。
127.0.0.1 yoursukinanamae.local
念の為、キャッシュをクリア
C:\>ipconfig /flushdns
// macはバージョンによってコマンド違うことがあるので注意
$ sudo killall -HUP nDNSResponder
$ /etc/rc.d/init.d/network resatart
or
$ /etc/rc.d/init.d/network reload
上記で反映されないのならマシン再起動してください。
これで設定は完了です。
以上です。
参考
docker docs
どうしても hosts の設定が反映されない場合の12通りの確認事項
Qiita: Macでhostsファイルを変更・反映
調べ物メモは今日も山積み