DockerでLaravelの開発環境を作ってみる(6回目練習Ver)

目次

DockerでLaravel 8の環境を作ろうと公式ドキュメントを見ると、“Laravel Sail"というコマンドラインツールの説明があります。 今回はVersion 8 から使えるようになったという"Laravel Sail"を使ってみます。

1回目はここ。

2回目はここ。

3回目はここ。

4回目はここ。

5回目はここ。

作業環境は

  • OS Ubuntu 20.04.2 LTS
  • Docker version 20.10.7
  • docker-compose version 1.29.2

です。

Laravel Sail

“Laravel Sail"はLaravel既定のDocker開発環境を扱うためのコマンドラインツールで、PHP、MySQL、Redisを使用したアプリケーションを簡単に始めることが出来るそうです。

インストールする

公式ドキュメントの「インストール」に説明があります。 今回はUbuntu上で開発するので"Getting Started On Linux"の項目にあるコマンドで初めます。

コマンドはcurl -s https://laravel.build/アプリケーションディレクトリ名 | bashで、今回は"example-app"とします。 途中でパスワードを聞かれるので入力します。

$ curl -s https://laravel.build/example-app | bash
Unable to find image 'laravelsail/php80-composer:latest' locally
latest: Pulling from laravelsail/php80-composer
852e50cd189d: Pull complete 
・・・中略・・・
Status: Downloaded newer image for laravelsail/php80-composer:latest

 _                               _
| |                             | |
| |     __ _ _ __ __ ___   _____| |
| |    / _` | '__/ _` \ \ / / _ \ |
| |___| (_| | | | (_| |\ V /  __/ |
|______\__,_|_|  \__,_| \_/ \___|_|

Warning: TTY mode requires /dev/tty to be read/writable.
    Creating a "laravel/laravel" project at "./example-app"
    Installing laravel/laravel (v8.5.22)
      - Downloading laravel/laravel (v8.5.22)
      - Installing laravel/laravel (v8.5.22): Extracting archive
    Created project in /opt/example-app
    > @php -r "file_exists('.env') || copy('.env.example', '.env');"
    Loading composer repositories with package information
    Updating dependencies
・・・中略・・・
Application ready! Build something amazing.
Sail scaffolding installed successfully.

Please provide your password so we can make some final adjustments to your application's permissions.

[sudo] izumi のパスワード:  ◀パスワードを入力します

Thank you! We hope you build something incredible. Dive in with: cd example-app && ./vendor/bin/sail up

コマンドで指定した"example-app"ディレクトリが作成されます。

とりあえず実行する

最後のメッセージにあるcd example-app && ./vendor/bin/sail upコマンドでいきなり実行することが出来ます。

$ cd example-app && ./vendor/bin/sail up
Creating network "example-app_sail" with driver "bridge"
Creating volume "example-app_sailmysql" with local driver
Creating volume "example-app_sailredis" with local driver
Creating volume "example-app_sailmeilisearch" with local driver
Pulling mysql (mysql:8.0)...
8.0: Pulling from library/mysql
33847f680f63: Pull complete
・・・中略・・・
Creating example-app_mailhog_1     ... done
Creating example-app_redis_1       ... done
Creating example-app_meilisearch_1 ... done
Creating example-app_selenium_1    ... done
Creating example-app_mysql_1       ... done
Creating example-app_laravel.test_1 ... 
Creating example-app_laravel.test_1 ... error

ERROR: for example-app_laravel.test_1  Cannot start service laravel.test: driver failed programming external connectivity on endpoint example-app_laravel.test_1 (64ddadc80cd745b658ecd8b96b583ca1cc1915ce222e1d86b2ae3d0e6d81db49): Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use

ERROR: for laravel.test  Cannot start service laravel.test: driver failed programming external connectivity on endpoint example-app_laravel.test_1 (64ddadc80cd745b658ecd8b96b583ca1cc1915ce222e1d86b2ae3d0e6d81db49): Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use
ERROR: Encountered errors while bringing up the project.

Laravelの実行に失敗する

初回は時間がかかるとのことで10分くらい待たされました。が、結果は"ERROR"であっさり終了してしまいました。 すでに"0.0.0.0:80"が使われているからダメだと言われています。

ポートの使用状況がどうなっているのか確認します。

# ssコマンドで使われているソケットの情報を確認します
$ ss -antu
Netid   State    Recv-Q   Send-Q                        Local Address:Port        Peer Address:Port   Process
udp     UNCONN   0        0                             127.0.0.73%lo:53               0.0.0.0:*
udp     ESTAB    0        0                       192.168.20.107%eth0:68          192.168.20.1:67
udp     UNCONN   0        0                            172.28.255.255:137              0.0.0.0:*
・・・中略・・・
tcp     LISTEN   0        4096                                   [::]:6379                [::]:*
tcp     LISTEN   0        50                                     [::]:139                 [::]:*
tcp     LISTEN   0        511                                       *:80                     *:*
tcp     LISTEN   0        4096                                   [::]:7700                [::]:*
# ポート80がLISTEN待ちしているので、lsofコマンドでどのプロセスか確認します
$ sudo lsof -i :80
[sudo] izumi のパスワード:  ◀パスワードを入力します
COMMAND PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
apache2 781     root    4u  IPv6  26025      0t0  TCP *:http (LISTEN)
apache2 782 www-data    4u  IPv6  26025      0t0  TCP *:http (LISTEN)
apache2 783 www-data    4u  IPv6  26025      0t0  TCP *:http (LISTEN)

Laravel Sailが使おうとしていた80ポートはすでに"apache2"で使われていました。

docker psコマンドで確認するといくつかのコンテナが実行中になっていますがLaravelのサーバーが起動されていないのでどうにもなりません。

$ docker ps
CONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS                    PORTS                                                                                  NAMES
f4569583342c   mysql:8.0                     "docker-entrypoint.s…"   16 minutes ago   Up 46 minutes (healthy)   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp                                   example-app_mysql_1
82e57932cd4b   selenium/standalone-chrome    "/opt/bin/entry_poin…"   16 minutes ago   Up 46 minutes             4444/tcp                                                                               example-app_selenium_1
9ff3afdd0cff   getmeili/meilisearch:latest   "tini -- /bin/sh -c …"   16 minutes ago   Up 46 minutes (healthy)   0.0.0.0:7700->7700/tcp, :::7700->7700/tcp                                              example-app_meilisearch_1
b21d9baad59f   redis:alpine                  "docker-entrypoint.s…"   16 minutes ago   Up 46 minutes (healthy)   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp                                              example-app_redis_1
cce025c406b9   mailhog/mailhog:latest        "MailHog"                16 minutes ago   Up 46 minutes             0.0.0.0:1025->1025/tcp, :::1025->1025/tcp, 0.0.0.0:8025->8025/tcp, :::8025->8025/tcp   example-app_mailhog_1

今回はエラーとなってしまったので全てのコンテナを削除して別のポートを使用するように変更します。sail upコマンドで実行中のコンテナはsail downコマンドでまとめて廃棄することが出来ます。

$ ./vendor/bin/sail down
example-app_laravel.test_1   start-container                  Exit 128
Shutting down old Sail processes...
Removing network example-app_sail
WARNING: Network example-app_sail not found.

使用するポートを変更する

LaraveのDockerコンテナが使用するポートを80番から8080番へ変更します。

Laravel Sailのドキュメントにあるように"docker-compose.yml"ファイルに定義されているので確認します。

https://laravel.com/docs/8.x/sail

“example-app/docker-compose.yml"ファイル

# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.0
            dockerfile: Dockerfile
            args:
                WWWGROUP: '${WWWGROUP}'
        image: sail-8.0/app
        ports:
            - '${APP_PORT:-80}:80'
        environment:
            WWWUSER: '${WWWUSER}'
            LARAVEL_SAIL: 1
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
            - redis
            - meilisearch
            - selenium
    mysql:
        image: 'mysql:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
        volumes:
            - 'sailmysql:/var/lib/mysql'
        networks:
            - sail
        healthcheck:
          test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
          retries: 3
          timeout: 5s
    redis:
        image: 'redis:alpine'
        ports:
            - '${FORWARD_REDIS_PORT:-6379}:6379'
        volumes:
            - 'sailredis:/data'
        networks:
            - sail
        healthcheck:
          test: ["CMD", "redis-cli", "ping"]
          retries: 3
          timeout: 5s
    meilisearch:
        image: 'getmeili/meilisearch:latest'
        ports:
            - '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
        volumes:
            - 'sailmeilisearch:/data.ms'
        networks:
            - sail
        healthcheck:
          test: ["CMD", "wget", "--no-verbose", "--spider",  "http://localhost:7700/health"]
          retries: 3
          timeout: 5s
    mailhog:
        image: 'mailhog/mailhog:latest'
        ports:
            - '${FORWARD_MAILHOG_PORT:-1025}:1025'
            - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
        networks:
            - sail
    selenium:
       image: 'selenium/standalone-chrome'
       volumes:
            - '/dev/shm:/dev/shm'
       networks:
           - sail
networks:
    sail:
        driver: bridge
volumes:
    sailmysql:
        driver: local
    sailredis:
        driver: local
    sailmeilisearch:
        driver: local

Laravelのコンテナ"laravel.test"定義を見るとポートの定義は'${APP_PORT:-80}:80'となっていて環境変数を参照するようになっています。

“${APP_PORT:-80}“は環境変数APP_PORTが未定義の場合80を使用するという意味です。

環境変数APP_PORTを”.env"ファイルに定義します。

“example-app/.env"ファイルに以下の1行を追加します。

APP_PORT=8080

example-appをカレントディレクトリにして、再びsail upコマンドを実行します

~/example-app$ ./vendor/bin/sail up
Creating network "example-app_sail" with driver "bridge"
Creating example-app_meilisearch_1 ... done
Creating example-app_mysql_1       ... done
Creating example-app_selenium_1    ... done
Creating example-app_mailhog_1     ... done
Creating example-app_redis_1       ... done
Creating example-app_laravel.test_1 ... done
Attaching to example-app_meilisearch_1, example-app_mysql_1, example-app_redis_1, example-app_mailhog_1, example-app_selenium_1, example-app_laravel.test_1
mailhog_1       | 2021/07/27 05:48:40 Using in-memory storage
mailhog_1       | 2021/07/27 05:48:40 [SMTP] Binding to address: 0.0.0.0:1025
・・・中略・・・
laravel.test_1  | 2021-07-27 05:48:45,468 INFO Set uid to user 0 succeeded
laravel.test_1  | 2021-07-27 05:48:45,470 INFO supervisord started with pid 18
laravel.test_1  | 2021-07-27 05:48:46,474 INFO spawned: 'php' with pid 19
laravel.test_1  | Starting Laravel development server: http://0.0.0.0:80
laravel.test_1  | [Tue Jul 27 05:48:46 2021] PHP 8.0.8 Development Server (http://0.0.0.0:80) started
laravel.test_1  | 2021-07-27 05:48:48,172 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

今度はDockerコンテナの起動に成功したようです。

ブラウザでhttp://localhost:8080/を参照するとLaravelの画面が表示されました。

ブラウザにLaravelのページが表示されます

ブラウザにLaravelのページが表示されます

docker psコマンドで複数のコンテナが実行中なのが確認できます。

$ docker ps
CONTAINER ID   IMAGE                         COMMAND                  CREATED         STATUS                   PORTS                                                                                  NAMES
3d0f5dfd399d   sail-8.0/app                  "start-container"        2 minutes ago   Up 2 minutes             8000/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp                                        example-app_laravel.test_1
7a9742baf998   mailhog/mailhog:latest        "MailHog"                2 minutes ago   Up 2 minutes             0.0.0.0:1025->1025/tcp, :::1025->1025/tcp, 0.0.0.0:8025->8025/tcp, :::8025->8025/tcp   example-app_mailhog_1
3877622963b8   redis:alpine                  "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp                                              example-app_redis_1
ca3df90e0591   selenium/standalone-chrome    "/opt/bin/entry_poin…"   2 minutes ago   Up 2 minutes             4444/tcp                                                                               example-app_selenium_1
cbb7f7e3d448   mysql:8.0                     "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp                                   example-app_mysql_1
ead5acdaeead   getmeili/meilisearch:latest   "tini -- /bin/sh -c …"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:7700->7700/tcp, :::7700->7700/tcp                                              example-app_meilisearch_1

Laravelコンテナを終了する

終了するときはログが表示されている端末でControl + Cキーを押すことで終了します。

laravel.test_1  | [Tue Jul 27 05:50:19 2021] 172.19.0.1:33656 Accepted
laravel.test_1  | [Tue Jul 27 05:50:21 2021] 172.19.0.1:33656 Closing
^CGracefully stopping... (press Ctrl+C again to force)
Stopping example-app_laravel.test_1 ... done
Stopping example-app_mailhog_1      ... done
Stopping example-app_redis_1        ... done
Stopping example-app_selenium_1     ... done
Stopping example-app_mysql_1        ... done
Stopping example-app_meilisearch_1  ... done
$ 
# Dockerのコマンドで全てのコンテナが終了していることが確認できます
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

Laravelコンテナをバッグラウンドで実行する

-dオプションでデタッチモードで起動することが出来ます。

$ ./vendor/bin/sail up -d
Creating network "example-app_sail" with driver "bridge"
Creating example-app_selenium_1    ... done
Creating example-app_mysql_1       ... done
Creating example-app_mailhog_1      ... done
Creating example-app_meilisearch_1 ... done
Creating example-app_redis_1       ... done
Creating example-app_laravel.test_1 ... done

終了するときは’sail down’コマンドを実行します。

$ ./vendor/bin/sail down
Stopping example-app_laravel.test_1 ... done
Stopping example-app_redis_1        ... done
Stopping example-app_meilisearch_1  ... done
Stopping example-app_mailhog_1      ... done
Stopping example-app_mysql_1        ... done
Stopping example-app_selenium_1     ... done
Removing example-app_laravel.test_1 ... done
Removing example-app_redis_1        ... done
Removing example-app_meilisearch_1  ... done
Removing example-app_mailhog_1      ... done
Removing example-app_mysql_1        ... done
Removing example-app_selenium_1     ... done
Removing network example-app_sail

Larabel 8を使用するのであればsailで簡単にDocker環境を作ることが出来ました。