こんぶにのブログ

エンジニアという職業を通して学んだことを発信するブログです。

【Docker】Laravel SailでDockerコンテナを複数起動したけど、めちゃくちゃ難しかった話【未解明】

先日、Laravel SailでDockerコンテナを複数起動し、片方のコンテナの中に内蔵されているmysqlにアクセスするということをした。
大変に時間がかかってしまったので、ここに記しておこうと思った。
ちなみに、未だに仕組みが良く分かっていない。
こんな感じなんだろうという理解なので、あまり参考にしすぎないでほしい。

やったこと

以下のsail upでのインストールを2つのプロジェクトで同じように行った。
Laravel Sail 9.x Laravel
最初に起動した方にはmysqlも含めた。
2つ目に起動するコンテナにはmysqlを含めず、最初に起動したほうのmysqlコンテナにアクセスする、というものだ。
この時点でDockerの仕組みをあまり理解してない自分は、??状態だった。

一つ目のdocker-compose.yml

# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.1
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.1/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80' //.envにAPP_PORTがあればそれを、なければホストの80番でアプリのコンテナを起動。dockerの80番へポートフォワーディング。
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
    mysql:
        image: 'mysql/mysql-server:8.0'
        ports:
            - '4306:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: "%"
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 1
        volumes:
            - 'sail-mysql:/var/lib/mysql'
            - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
        networks:
            - sail
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
            retries: 3
            timeout: 5s
networks:
    sail:
        driver: bridge
        name: app-1
volumes:
    sail-mysql:
        driver: local

起動するときは0.0.0.0:80。ローカルでも80で動いてるから。

二つ目のdocker-compose.yml

version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.2
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.2/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-8081}:80' //ホストの8081でアプリのコンテナ起動、dockerの80番に処理はお願いする
            - '${VITE_PORT:-5174}:${VITE_PORT:-5174}'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
            IGNITION_LOCAL_SITES_PATH: '${PWD}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
networks:
    sail:
        driver: bridge
        external: true
        name: app-1 // 最初に起動したほうを指定する ??
volumes:
    sail-mysql:
        driver: local

起動するときは0.0.0.0:8001。ローカルでは8001で動いてるから。

分からないこと

コメントにしているポートフォワーディングの部分が良く分かってない。
ふたつのアプリがdockerの80番へリクエストを送っているのに、どうしてアプリ1と2で別の結果が返ってくるんだろう?
docker:80番は、Webサーバだから来たリクエストを認識して、そのパスのファイルを返すなり、routeにcontrollerの処理が書かれていればその先にお願いをするはず。
そこまではいい。ここからが分からん。
ローカル:80番がdocker80番にリクエストを送るときはこんな感じだろうか。
・ブラウザで0.0.0.0:80を入力
・ホストの80番が「お、おれの出番だな!ん?dockerの80番に処理はお願いするのね、了解!」
・docker80番「お、ローカルの80から依頼が来てる。なるほど80番からこのリクエストが来てるってことはこっちのアプリのこの処理をすればいいのね。 はい、生成できたからページのデータ返すよ~」
・ブラウザ「ページのデータが返ってきた!」
というイメージをしている。
だから、ホストの8001でリクエストをするときも同じはずだ。
・ブラウザで0.0.0.0:8001を入力
・ホストの8001番が「お、おれの出番だな!ん?dockerの80番に処理はお願いするのね、了解!」
・docker80番「お、ローカルの8001から依頼が来てる。なるほど8001番からこのリクエストが来てるってことはこっちのアプリのこの処理をすればいいのね。 はい、生成できたからページのデータ返すよ~」
・ブラウザ「ページのデータが返ってきた!」
こうなるんだろう。

ただ、その設定をしているのはどこなんだろう?
dockerの80番はどうやって、どのアプリにどの処理を依頼するのかを判断しているのか。
「ホスト8001で動いている者です!このパスにあるこのフォルダ名にあるものに処理を依頼してください!」という挨拶はどこに書いてあるんだろう。
リクエストヘッダーのHostとかに色々パスとか情報が入ってて、docker80番はそれを元に判別しているんだろうか。
う~ん。。。dockerの仕組みが分かっていないって話なのか、そもそもWebサーバーへの理解が不足しているのか。
多分、docker80番で動いてるのはphpのビルトインサーバなのかな。