Dockerを用いてPHP+MySQL+Nginx環境の構築

投稿者: | 2020年11月10日

バイト先で使うツールとして問題を自動生成するwebアプリケーションを作ろうとしています。しかし、C++やPythonは書いたことがあるものの、フロントエンドやwebというのは今までほとんど触ってきていないので苦労しそうです。

さて、とりあえずPHPを使うことが決まっているので、PHPの環境構築をしていきます。構築中にtwitterで「docker使って」って言われたのでdockerを用いて構築しました。

1.構築したPC環境

  • CPU: Intel Core i7 9700K
  • M/B: ROG STRIX Z390-F Gaming
  • OS: windows10 Pro(1909)

その他の構成は環境構築に必要ないと思ったので省略しています。

2.Docker for Windowsをインストール

Docker Desktopからインストーラーをダウンロードして、インストール。

アカウントを作らなくてもインストールはできますが、Docker Desktopを起動したときにログインしてって言われるので同時に作っておきます。

2-1.Hyper-Vの有効化

インストール後にエラーメッセージが出てくることがあります。まずは、Hyper-Vが有効化されていないとダメなので、Hyper-Vを有効にします。

コントロールパネル→プログラム→windowsの機能の有効化と無効化

または、

コントロールパネル→プログラムのアンイストール→windowsの機能の有効化と無効化(サイドバー)

2-2.CPUの仮想化の有効化

Hyper-Vが有効になってもエラーが出ることがあります。まずはタスクマネージャーを開いて、パフォーマンスタブの仮想化が有効になっているか確認します。

仮想化

仮想化が無効になっている場合は、BIOSの設定を変える必要があります。

各種メーカーによってBIOSへの入り方が違うので、使用しているマザーボードのメーカーのマニュアルに従って下さい。

今回使用しているのはASUSのマザーボードですので、Delキーを押すと入れます。

BIOS、最近のマザーボードはUEFIに変わっていますが、そこから仮想化を有効にする設定を探します。

UEFI

Intel (VMX) Virtualization Technologyなど仮想化に関するものをEnableにします。

この設定項目はCPUに関わるものですので、詳細などのタブからCPUの設定に入るとあると思います。

設定を変更したら、設定を保存してBIOSを出ます。

PCを再起動したら、仮想化に関わるエラーは出なくなるはずです。

2-3.WSL2の更新

仮想化が有効化できた後、WSL2のカーネルをアップデートしろというエラーメッセージが出ることがあります。

WSL2

エラーメッセージに書かれているリンクからアップデーターをダウンロードして、WSL2のLinuxカーネルをアップデートしてください。

3.Docker Desktopを起動

エラーが全て解決すれば、Docker Desktopが起動します。

Docker Desktop

チュートリアルが始まりますので、チュートリアルをクリアしてください。

さて、チュートリアルが終わったら、一度Docker Composeがインストールされているか確認します。

PowerShellを開いて、次のコマンドを実行します。そして次のようにComposeのバージョンが表示されれば大丈夫です。

docker-compose --version
docker-compose version 1.27.4, build 40524192

[雑談]Windows PowerShellとPowerShell

現在Windows PowerShellを開くと次のような表示がされます。

windows powershell

そして、新しいPowerShellをお試しくださいの横のURLから、新しいPowerShellをダウンロード、インストールすると"別の"PowerShellがインストールされます。

元々Windowsに入っていたPowerShell(Windows PowerShell)は互換性のために残りますが、今後はPowerShell(PowerShell Core)へ移行し、そちらを開発していくようです。

PowerShell Core、次のバージョンから「PowerShell 7」に変更

つまり、この2つは別物なので、Windows Terminalから起動するときは間違えないようにしましょう。

windows terminal

4.必要なディレクトリやファイルを作成する

今回構築した環境は、参考にさせていただいた記事をそのまま行っています。

DockerによるPHP開発環境構築(PHP + MySQL + Nginx)

次のようにディレクトリやファイルを作成します。

|
|--docker-compose.yml
|
|--nginx
|   nginx.conf
|--php
|   Dockerfile
|   php.ini
|--mysql
|   data
|--www
    |--html
        index.php

4-1.docker-compose.yml

version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./www/html:/var/www/html
    depends_on:
      - php

  php:
    build: ./php
    volumes:
      - ./www/html:/var/www/html
    depends_on:
      - db

  db:
    image: mysql:5.7
    ports:
      - 13306:3306
    volumes:
      - ./mysql/data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret

  phpmyadmin:
    image: phpmyadmin/phpmyadmin:latest
    ports:
      - 8888:80
    depends_on:
      - db

VScodeで書くとサジェストされるので便利です。

最初のversionだけ、シングルクォーテーションで囲むのを忘れないようにしましょう。

4-2.nginx.conf

server {
    listen 80;
    server_name _;

    root  /var/www/html;
    index index.php index.html;

    access_log /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;    
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include       fastcgi_params;
    }
}

15行目からはphpをNginxで動かす設定を書いてあります。

参考:NginxでPHPを動かす

[雑談]Nginxって何?

Nginx(エンジンエックス)はOSSのwebサーバです。Apacheは動的コンテンツ処理が得意(らしい)ですが、Nginxは静的コンテンツの処理が得意です。

世界で2番目に使われており、Apacheと双璧を成す有名なWebサーバです。

4-3.Dockerfile

FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

参考:Docker入門(第4回~Dockerfileについて~)

4-4.php.ini

date.timezone = "Asia/Tokyo"

4-5.index.php

<?php
echo "Hello World!";
phpinfo();

5.コンテナの起動と確認

まず、docker-compose.ymlのあるディレクトリまで移動します。そして、そのディレクトリで次のコマンドを実行します。

docker-compose up -d

[Error]docker-compose.ymlがないディレクトリでコマンドを実行したとき

ERROR:
        Can't find a suitable configuration file in this directory or any
        parent. Are you in the right directory?

        Supported filenames: docker-compose.yml, docker-compose.yaml

[Error]docker-compose.ymlに文法エラーがあったとき

ERROR: yaml.parser.ParserError: while parsing a block collection
  in ".\docker-compose.yml", line 14, column 7
expected <block end>, but found '?'
  in ".\docker-compose.yml", line 15, column 7

何もなければ必要なものがインストールされます。

コンテナが起動されたら確認するために次のコマンドを実行して確認します。

docker ps

全てupになっていたらOKです。

CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                                NAMES
058734a1b896        nginx:latest                   "/docker-entrypoint.…"   23 seconds ago      Up 20 seconds       0.0.0.0:8080->80/tcp                 php_nginx_1
090e164379c7        php_php                        "docker-php-entrypoi…"   23 seconds ago      Up 21 seconds       9000/tcp                             php_php_1
4786c0e65699        phpmyadmin/phpmyadmin:latest   "/docker-entrypoint.…"   23 seconds ago      Up 21 seconds       0.0.0.0:8888->80/tcp                 php_phpmyadmin_1
c28103e98d71        mysql:5.7                      "docker-entrypoint.s…"   24 seconds ago      Up 22 seconds       33060/tcp, 0.0.0.0:13306->3306/tcp   php_db_1

最後に、ローカルホストにアクセスして、Hello,Worldとphpinfoが表示されていることを確認します。

このときアクセスするURLはdocker-compose.ymlに記述した通りですので、localhost:8080とブラウザに打ち込んでください。

php.info

6.コンテナの停止と実行

6-1.コンテナの停止

コンテナを停止させる場合は次のコマンドを実行します。

docker-compose stop

次のように表示されてコンテナが停止します。

Stopping php_nginx_1      ... done
Stopping php_php_1        ... done
Stopping php_phpmyadmin_1 ... done
Stopping php_db_1         ... done

6-2.コンテナの起動

停止させたコンテナを起動する場合、次のコマンドを実行します。

docker-compose up

すると、次のように表示されます。

Starting php_db_1 ... done
Starting php_phpmyadmin_1 ... done
Starting php_php_1        ... done
Starting php_nginx_1      ... done
Attaching to php_db_1, php_phpmyadmin_1, php_php_1, php_nginx_1
db_1          | 2020-11-10 09:49:12+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.32-1debian10 started.
db_1          | 2020-11-10 09:49:12+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
nginx_1       | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
nginx_1       | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
nginx_1       | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
nginx_1       | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
nginx_1       | 10-listen-on-ipv6-by-default.sh: error: /etc/nginx/conf.d/default.conf differs from the packaged version
nginx_1       | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
db_1          | 2020-11-10 09:49:12+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.32-1debian10 started.
db_1          | 2020-11-10T09:49:13.432711Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
db_1          | 2020-11-10T09:49:13.446377Z 0 [Note] mysqld (mysqld 5.7.32) starting as process 1 ...
db_1          | 2020-11-10T09:49:13.451131Z 0 [Warning] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
db_1          | 2020-11-10T09:49:13.458010Z 0 [Note] InnoDB: PUNCH HOLE support available
db_1          | 2020-11-10T09:49:13.458069Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
db_1          | 2020-11-10T09:49:13.458075Z 0 [Note] InnoDB: Uses event mutexes
db_1          | 2020-11-10T09:49:13.458077Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
db_1          | 2020-11-10T09:49:13.458079Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
db_1          | 2020-11-10T09:49:13.458095Z 0 [Note] InnoDB: Using Linux native AIO
db_1          | 2020-11-10T09:49:13.459424Z 0 [Note] InnoDB: Number of pools: 1
db_1          | 2020-11-10T09:49:13.460519Z 0 [Note] InnoDB: Using CPU crc32 instructions
php_1         | [10-Nov-2020 09:49:18] NOTICE: fpm is running, pid 1
php_1         | [10-Nov-2020 09:49:18] NOTICE: ready to handle connections
nginx_1       | /docker-entrypoint.sh: Configuration complete; ready for start up
db_1          | 2020-11-10T09:49:13.471277Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
db_1          | 2020-11-10T09:49:13.505398Z 0 [Note] InnoDB: Completed initialization of buffer pool
db_1          | 2020-11-10T09:49:13.517407Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
db_1          | 2020-11-10T09:49:13.581392Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
phpmyadmin_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
db_1          | 2020-11-10T09:49:13.757069Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
db_1          | 2020-11-10T09:49:13.759062Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
db_1          | 2020-11-10T09:49:13.827625Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
db_1          | 2020-11-10T09:49:13.833631Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
db_1          | 2020-11-10T09:49:13.833660Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
db_1          | 2020-11-10T09:49:13.840165Z 0 [Note] InnoDB: Waiting for purge to start
phpmyadmin_1  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.18.0.3. Set the 'ServerName' directive globally to suppress this message
phpmyadmin_1  | [Tue Nov 10 09:49:18.236627 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.11 configured -- resuming normal operations
phpmyadmin_1  | [Tue Nov 10 09:49:18.236681 2020] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
db_1          | 2020-11-10T09:49:13.890778Z 0 [Note] InnoDB: 5.7.32 started; log sequence number 12605687
db_1          | 2020-11-10T09:49:13.896949Z 0 [Note] Plugin 'FEDERATED' is disabled.
db_1          | 2020-11-10T09:49:13.898636Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
db_1          | 2020-11-10T09:49:13.945556Z 0 [Note] InnoDB: Buffer pool(s) load completed at 201110  9:49:13
db_1          | 2020-11-10T09:49:13.963333Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
db_1          | 2020-11-10T09:49:13.963374Z 0 [Note] Skipping generation of SSL certificates as certificate files are present in data directory.
db_1          | 2020-11-10T09:49:13.983517Z 0 [Warning] CA certificate ca.pem is self signed.
db_1          | 2020-11-10T09:49:13.984574Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory.
db_1          | 2020-11-10T09:49:13.995746Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
db_1          | 2020-11-10T09:49:13.996034Z 0 [Note] IPv6 is available.
db_1          | 2020-11-10T09:49:13.996156Z 0 [Note]   - '::' resolves to '::';
db_1          | 2020-11-10T09:49:13.996274Z 0 [Note] Server socket created on IP: '::'.
db_1          | 2020-11-10T09:49:14.004624Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
db_1          | 2020-11-10T09:49:15.100262Z 0 [Note] Event Scheduler: Loaded 0 events
db_1          | 2020-11-10T09:49:15.100477Z 0 [Note] mysqld: ready for connections.
db_1          | Version: '5.7.32'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
php_1         | 172.18.0.5 -  10/Nov/2020:09:50:15 +0000 "GET /index.php" 200
nginx_1       | 172.18.0.1 - - [10/Nov/2020:09:50:15 +0000] "GET / HTTP/1.1" 200 84907 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0"
nginx_1       | 172.18.0.1 - - [10/Nov/2020:09:50:15 +0000] "GET /favicon.ico HTTP/1.1" 499 0 "http://localhost:8080/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0"

コンテナ起動時は58行目までですが、そこからlocalhost:8080にアクセスしたところ、このようなログが流れてきました。

この状態ではコマンド入力は受け付けていないので、コンテナを停止させる場合には、Ctrl+Cを押してください。

Gracefully stopping... (press Ctrl+C again to force)
Stopping php_nginx_1      ... done
Stopping php_php_1        ... done
Stopping php_phpmyadmin_1 ... done
Stopping php_db_1         ... done

このようにコンテナが停止します。

6-3.コンテナをバックグラウンドで起動

バックグラウンドで起動する場合は次のコマンドを実行します。

docker-compose up -d

最後の-dがバックグラウンドで実行するオプションになっています。

このコマンドで実行した場合は、次のように表示されます。

Starting php_db_1 ... done
Starting php_php_1        ... done
Starting php_phpmyadmin_1 ... done
Starting php_nginx_1      ... done

ログは流れてきません。なので、コンテナを停止させるときはコマンドを実行することもできます。

7.おわりに

今までめんどくさそうで避けてきましたが、YAMLファイルを記述して準備するだけで簡単に環境を構築できるのは便利だと思いました。私は家のPC(windows)、ノートPC(Mac)、研究室のPC(windows,ubuntu)といろいろなOSで作業をすることが多いので、毎回環境構築に時間を取られていました。

しかし、Dockerの場合一度コンテナを作成してしまえば、pullしてcloneすれば環境がすぐに手に入るのはすごい便利です。さらに全て同じ環境ですし、環境ごとの差を考えなくていいです。

環境ごとと差といえば、卒研で書いたコードをコンパイルして実行したら、MinGWのgccによってコンパイルしたファイルは、その他gccによってコンパイルしたファイルより実行速度が10倍遅かったのを思い出しました。それがあってMinGWは二度と使わないと心に決めました。

今回PHP+MySQL+Nginx環境を作ってみましたが、便利そうならC++環境もDockerに載せたいなと思いました。

しかし、今まで書いたソースコードがコンテナ外にあるため、コンテナ内のディレクトリにマウントする必要があります。コンテナ起動時にオプションに書けばマウントはしてくれますが、ディレクトリのフルパスが長くてめんどくさい。

MacやLinuxならエイリアスを張りますが、windowsはそういう事ができない。なんかいい方法が無いかなあと思っています。

8.参考文献

DockerによるPHP開発環境構築(PHP + MySQL + Nginx)

Dockerを利用してPHP実行環境を構築してみた

Docker-docs-ja イメージの構築と実行

Docker-docs-ja Docker for Windows を始めよう

NginxでPHPを動かす

Dockerで簡単にUbuntu,C/C++言語の開発環境を作る

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください