こんにちはjunです。laravelの開発環境をDockerで構築した機会がありました。よくlaravelぐらいならば apcheイメージを入れたりして構築すると思います。その場合大体イメージのosがUbuntuになったりしますが、本番環境のosはcentosだったりと「osから構築したいなー」と思ったので今回はDockerfileとdocker-composeを用いてosからlaravelまで構築しようと思います。
この記事で使用したOSとdockerのバージョン docker:19.03.13 maxOS Catalina 10.15.5
centos_laravel
├── docker-compose.yml
├── laravel
│
├── web
├── Dockerfile
├── httpd.conf
└── php.ini
ディレクトリは上記の様な感じです。docker-compose.ymlは以下の様になっています。
version: '3'
services:
web_1:
image: centos8_apache:1.0
depends_on:
- db
volumes:
- ./laravel/:/var/www/html/
- /sys/fs/cgroup:/sys/fs/cgroup:ro
ports:
- "9000:80"
- "3000:3000"
privileged: true
command: /sbin/init
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: larvel_docker
MYSQL_USER: test
MYSQL_PASSWORD: testtest
MYSQL_ROOT_PASSWORD: rootroot
ports:
- "3306:3306"
volumes:
- laravel_data:/var/lib/mysql
volumes:
laravel_data: {}
構築の流れとしては
と行った流れで行います。
web
ディレクトリ配下にはcentos8、apache、php、nodeがインストールされたイメージを作成するDockerfile
とapacheの設定ファイル、phpの設定ファイルがあります。
laravelでは実運用の際にドキュメントルート を変更する必要があるのでhttpd.conf
を編集して、それをコンテナのhttpd.conf
にコピーしています。php.ini
はタイムゾーン を書き足すぐらいですけど同じ様にエディタ上で設定ファイルを変更できる様にしています。
larvelディレクトリはlaravelソースが予めインストールされています。そのソースをコンテナのドキュメントルート 配下にボリュームすることでローカルのエディタで編集してコンテナ環境でレビューすることができます。
それではまずwebサーバーイメージを作成していきます。と言っても以下のDockerfileの内容で事足ります。
FROM centos:8
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN yum install -y epel-release && yum clean all
RUN rpm -ivh http://ftp.riken.jp/Linux/remi/enterprise/remi-release-8.rpm
RUN yum -y update && yum clean all
RUN yum -y install httpd && yum clean all
COPY ./httpd.conf /etc/httpd/conf/httpd.conf
RUN yum -y install php74-php php74-php-mysqli php74-php-gd php74-php-mbstring php74-php-opcache php74-php-xml php74-php-pear php74-php-devel php74-php-pecl-imagick php74-php-pecl-imagick-devel php74-php-pecl-zip
RUN ln /usr/bin/php74 /usr/bin/php
COPY ./php.ini /etc/opt/remi/php74/php.ini
RUN chown -R apache:apache /var/www/html
RUN systemctl enable php74-php-fpm
RUN systemctl enable httpd
VOLUME [ "/var/www/html" ]
RUN chown -R apache:apache /var/www/html
RUN dnf -y module enable nodejs:12
RUN dnf -y install nodejs
EXPOSE 80
もう少し細かく解説していきます。
FROM centos:8
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == \
systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
FROM centos:8
で書かれている様に、centos8自身のイメージは公式のdockerHubからpullします。そしてこれらの記述は公式の手順のソースを貼り付けた感じです。
以前dockerにcentos8の環境を作ろうとして詰まった時がありました(こちらの記事)。その際はこの以下の部分だけを書いていました。
FROM centos:8
RUN /bin/cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
#..以下同じ
純粋に公式のcentosイメージはデフォルトでsystemdがアクティブにならず、コンテナを立てても応答しません。docker-composeの際にも一工夫必要になりますが、まずは上の方の記述でcenotsのイメージ設定をしましょう。
RUN yum -y install httpd && yum clean all
COPY ./httpd.conf /etc/httpd/conf/httpd.conf
こんだけです。yum -y install httpd
をRUN
してhttpdを入れているだけですね。ちなみにdockerコンテナ内でyumなどを用いてインストールする際は-y
オプションをつけましょう。-y
オプションは全てyesで答えるというオプションです。これがないとインストール時に「本当にインストールしますか?(Yes/No)」と聞かれ、ビルドがとまります。
そしてDockerfile
と同じディレクトリにいるhttpd.conf
をコンテナ内のhttpd.conf
にCOPYします。httpd.conf
は別途にapache2.4コンテナを立ててコピーするか、最初はこのCOPY部分をコメントアウトして一度このDockerfile
をビルドしてコピーしても大丈夫です。
例えば別途にapache2.4という名前でコンテナを立ち上げている場合、以下の様にしてhttpd.confをコピーします。
docker container cp apache2.4:/etc/httpd/conf/httpd.conf ./
こうするとコンテナ内のソースが手元にコピーされます。インストールする環境によってhttpd.conf
の置き場所が変わったりもするのでまずはCOPY無しでビルドして、パスを確認してから手元にコピーするといいです。
RUN rpm -ivh http://ftp.riken.jp/Linux/remi/enterprise/remi-release-8.rpm
RUN yum -y install php74-php php74-php-mysqli php74-php-gd php74-php-mbstring php74-php-opcache php74-php-xml php74-php-pear php74-php-devel php74-php-pecl-imagick php74-php-pecl-imagick-devel php74-php-pecl-zip
RUN ln /usr/bin/php74 /usr/bin/php
COPY ./php.ini /etc/opt/remi/php74/php.ini
remi
リポジトリをインストールしてyum
を通じてphp7.4を入れます。RUN ln /usr/bin/php74 /usr/bin/php
で php
コマンドを使用できる様にします。
そしてhttpd.conf
と同じ様にphp.ini
を手元からコピーします。
RUN chown -R apache:apache /var/www/html
RUN systemctl enable php74-php-fpm
RUN systemctl enable httpd
VOLUME [ "/var/www/html" ]
webサーバーとphpを入れたのでドキュメントルート をapacheが触れる様に権限を変更します。そしてwebサーバーとphp-fpmが自動で起動する様にします。最後にlaravelプロジェクトをドキュメントルート配下にボリュームできる様にボリュームの設定をします。
node.jsをいれるのはフロントの開発でnuxt.jsを用いるためです。ここは飛ばしても構いません。
RUN dnf -y module enable nodejs:12
RUN dnf -y install nodejs
webサーバーのDockerfileが書き終わったのでまずビルドしてイメージを作りましょう。Dockerfileがあるディレクトリで以下のコマンドを唱えます。
$ docker build -t centos_apache:1.0 .
.
は「現在のディレクトリ」という意味です。そして -t でタグをつけを有効にします。今回作成したイメージは centos_apache
で1.0
というタグをつけておきます。ビルドは少し時間がかかりますが、完了すればローカルにこのイメージが登録されます。dockerhubなどに置いておけば、他の人にがpullできる様になります。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos_apache 1.0 54784hkjdfjk 17 hours ago 941MB
それではosから調整したwebサーバーイメージは作成できたので、次はdocker-composeを使用してDBコンテナとの連携などをしていきます。docker-compose.yml
は以下の通りです。
version: '3'
services:
web_1:
image: centos_apache:1.0
depends_on:
- db
volumes:
- ./laravel/:/var/www/html/
- /sys/fs/cgroup:/sys/fs/cgroup:ro
ports:
- "9000:80"
- "3000:3000"
privileged: true
command: /sbin/init
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: trend_system
MYSQL_USER: trend
MYSQL_PASSWORD: trendtrend
MYSQL_ROOT_PASSWORD: rootroot
ports:
- "3306:3306"
volumes:
- laravel_data:/var/lib/mysql
volumes:
laravel_data: {}
コンテナはwebサーバーとDBサーバーの二つをたて、それらをdepends_onを通じて連携します。そして手元にはlaravelとnuxtをインストールしたプロジェクトディレクトリを置いておき、それをコンテナのドキュメントルートに置くと行った手順です。
それでは詳細を解説していきます。
web_1:
image: centos_apache:1.0
depends_on:
- db
volumes:
- ./laravel/:/var/www/html/
- /sys/fs/cgroup:/sys/fs/cgroup:ro
ports:
- "9000:80"
- "3000:3000"
privileged: true
command: /sbin/init
この箇所は先ほどビルドしたwebサーバーイメージを用いたコンテナに関する記述です。depends_on: -db
とすることでDBと連携ができる様になります。そして./laravel/:/var/www/html/
でプロジェクトソースをコンテナに入れ込んでいます。
そして先述の通りcenots8のイメージを使用している場合はコンテナがきちんと起動するために以下のコードが必要です。
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:ro
privileged: true
command: /sbin/init
詳細はこちらの記事にて解説します。centos8はデフォルトでコンテナ内でアクティブにならずwebサーバーも起動しません。ホストマシンのsystemd
をマウントし、そしてprivileged: true
にてコンテナにroot権限を与えることで、コンテナのcentos8が動きます。
ports:
- "9000:80"
- "3000:3000"
ここでホストマシンのlocalhost:9000
とlocalhost:3000
をコンテナのlocalhost
、localhost:3000
につなげる様にします。ホストマシンを9000にしたのは気分です。干渉しなければ他のポートでも大丈夫です。
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: laravel_test
MYSQL_USER: test
MYSQL_PASSWORD: testtest
MYSQL_ROOT_PASSWORD: rootroot
ports:
- "3306:3306"
volumes:
- laravel_data:/var/lib/mysql
volumes:
laravel_data: {}
DBはmysql:5.7の公式イメージを使用します。パスワードの設定なども簡単に行ってくれます。そしてデータ内容は永続化したいのでlaravel_data:{}をボリュームしておきます。
DBはこれでOKです。もしDBにあるデータをまっさらにしたい場合はコンテナを止めて、ボリュームを削除すれば大丈夫です。
以上でwebサーバーとDBサーバーの準備は整いました。次はlaravel
ソースと細かい調整を行います。まずはlaravelディレクトリにプロジェクトを入れます。今回はバージョン6を入れます。ローカルにはcomposerが入っているものとします。
$ cd laravel
$ composer create-project "laravel/laravel=6.*" .
laravelのソースが並んだら.env
を以下の様にDBの設定を書き込みます。docker-compose.yml
で設定した通りのパスワード、ユーザーです。
...
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_test
DB_USERNAME=root
DB_PASSWORD=rootroot
...
DB_HOST
はdocker-compose.yml
のserviceで定義した名前db
で大丈夫です。こうすればマイグレーションができる様になります。
Laravelではドキュメントルート を /public
配下にする様に言われています。httpd.conf
のデフォルトのドキュメントルートは /var/www/html
なので以下の様に変更しておきます
DocumentRoot "/var/www/html/public"
<Directory "/var/www/html/public">
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
こうするとapacheは/var/www/html/public
をドキュメントルートとして見てくれます。
php.iniはタイムゾーン をAsia/Tokyoにするだけです。
それではdocker-compose
で起動します。docker-compose.yml
がある場所にて以下の様に唱えます。
$ docker-compose up -d
ビルドがうまくいけばdocker ps
で2つのコンテナが起動しているのが確認できます。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3e121d905e5e centos_apache:1.0 "/sbin/init" 5 seconds ago Up 3 seconds 0.0.0.0:3000->3000/tcp, 0.0.0.0:9000->80/tcp centos_apache_web_1_1
ea5076e310e9 mysql:5.7 "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp centos_apache_db_1
localhost:9000
をブラウザでアクセスすると
はい。おなじみのLaravelの画面が表示されました。マイグレーションをするためにコンテナに入ります。
$ docker exec -it centos_apache_web_1_1 /bin/bash
プロジェクトルートに移動してphp artisan migrate
を唱えるとDBコンテナへマイグレーションされます。
$ cd /var/www/html
$ ls
README.md artisan client composer.lock database nuxt.config.js package.json public routes storage vendor
app bootstrap composer.json config node_modules package-lock.json phpunit.xml resources server.php tests webpack.mix.js
$ php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.03 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.02 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.01 seconds)
本当に入ったかはDBコンテナに入ってmysqlコマンドを通じて中身を見ると確認できます。ここまでくればLaravelの環境構築は完了です。phpのバージョンを変えてみたりで、OS環境による検証もある程度楽になるでしょう。
一応私のプロジェクトではnuxt.jsを入れていたので、せっかくなので解説します。larvelディレクトリにてnuxt.jsのプロジェクトを作成します。(ローカルでも、コンテナ内でもどちらでも。私はローカルで作成)
$ cd laravel
$ npx create-nuxt-app client
以下の様なディレクトリになりました。
.
├── README.md
├── app
├── artisan
├── bootstrap
├── client # nuxt ソース
├── composer.json
├── composer.lock
├── config
├── database
├── phpunit.xml
├── public
├── resources
├── routes
├── server.php
├── storage
├── tests
├── vendor
└── webpack.mix.js
ちなみにLaravelに初期にあったpackage.json
は削除しています。client
ディレクトリ配下にnuxtのソースがありますが、これだと管理がしにくいので以下の様に変更します。
.
├── README.md
├── app
├── artisan
├── bootstrap
├── client
├── composer.json
├── composer.lock
├── config
├── database
├── node_modules #clientから
├── nuxt.config.js #clientから
├── package-lock.json #clientから
├── package.json #clientから
├── phpunit.xml
├── public
├── resources
├── routes
├── server.php
├── storage
├── tests
├── vendor
└── webpack.mix.js
client
から4つのファイルを引っ張り出し、そしてnuxt.config.js
に以下を追記します。
srcDir: 'client/',
こうすることでclient
配下はnuxtのソースだけを置いて設定ファイルやdist
はLaravelのプロジェクトルートに出される様にします。この辺はチームの好みによるので自由に変更してください。
そしてコンテナ内に入って npm run dev
をすればnuxtの開発サーバーが立ち上がるのですが、その前にまたnuxt.config.js
に以下の内容を記述します。
server: {
host: '0.0.0.0'
},
dockerコンテナを使用しない場合はこの設定は要らないのですが、コンテナ内でnpm run dev
をしてそれに接続するには上記の設定が必要です。コンテナ内のlocalhost:3000に開発サーバーが立ち上がります。docker-compose.yml
で
ports:
- "9000:80"
- "3000:3000
この様にホストの3000とコンテナの3000ポートをつないでいたので、localhost:3000にアクセスすると
nuxtの画面が現れました。(UIフレームワークにvuetifyを選択するとこの画面になります。)これでnuxtの開発もコンテナ内で実行できます。