Dockerでosから作るcentos8+apache2.4+laravel 6 開発環境構築
技術スタック DockerLaravel

Dockerでosから作るcentos8+apache2.4+laravel 6 開発環境構築

2020.11.28

こんにちは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は以下の様になっています。

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: {}

構築の流れとしては

  • centos8、apache2.4、php7.4、nodejsが入ったwebサーバーイメージを作成
  • webサーバーイメージとmysqlイメージで作られた2つのコンテナをdocker-composeで連携する
  • laraevelのマイグレーションを行う。

と行った流れで行います。

webサーバーイメージ

webディレクトリ配下にはcentos8、apache、php、nodeがインストールされたイメージを作成するDockerfileとapacheの設定ファイル、phpの設定ファイルがあります。

laravelでは実運用の際にドキュメントルート を変更する必要があるのでhttpd.confを編集して、それをコンテナのhttpd.confにコピーしています。php.iniはタイムゾーン を書き足すぐらいですけど同じ様にエディタ上で設定ファイルを変更できる様にしています。

laravelディレクトリ

larvelディレクトリはlaravelソースが予めインストールされています。そのソースをコンテナのドキュメントルート 配下にボリュームすることでローカルのエディタで編集してコンテナ環境でレビューすることができます。

webサーバーイメージを作成

それではまず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

もう少し細かく解説していきます。

centos8をいれ、設定

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のイメージ設定をしましょう。

apache2.4をいれる

RUN yum -y install httpd && yum clean all

COPY ./httpd.conf /etc/httpd/conf/httpd.conf

こんだけです。yum -y install httpdRUNしてhttpdを入れているだけですね。ちなみにdockerコンテナ内でyumなどを用いてインストールする際は-yオプションをつけましょう。-yオプションは全てyesで答えるというオプションです。これがないとインストール時に「本当にインストールしますか?(Yes/No)」と聞かれ、ビルドがとまります。

そしてDockerfileと同じディレクトリにいるhttpd.confをコンテナ内のhttpd.confにCOPYします。httpd.confは別途にapache2.4コンテナを立ててコピーするか、最初はこのCOPY部分をコメントアウトして一度このDockerfileをビルドしてコピーしても大丈夫です。

コンテナ内からソースを手元にコピーするためにはdocker cp コマンドを用います。

例えば別途にapache2.4という名前でコンテナを立ち上げている場合、以下の様にしてhttpd.confをコピーします。

docker container cp apache2.4:/etc/httpd/conf/httpd.conf ./

こうするとコンテナ内のソースが手元にコピーされます。インストールする環境によってhttpd.confの置き場所が変わったりもするのでまずはCOPY無しでビルドして、パスを確認してから手元にコピーするといいです。

php をいれる

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/phpphpコマンドを使用できる様にします。

そして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をいれる(おまけ)

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_apache1.0というタグをつけておきます。ビルドは少し時間がかかりますが、完了すればローカルにこのイメージが登録されます。dockerhubなどに置いておけば、他の人にがpullできる様になります。

$ docker images                                           
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
centos_apache                   1.0                54784hkjdfjk        17 hours ago        941MB

docker-composeを作成

それではosから調整したwebサーバーイメージは作成できたので、次はdocker-composeを使用してDBコンテナとの連携などをしていきます。docker-compose.ymlは以下の通りです。

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サーバーコンテナの記述

docker-compose.yml
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/でプロジェクトソースをコンテナに入れ込んでいます。

centosのための記述

そして先述の通りcenots8のイメージを使用している場合はコンテナがきちんと起動するために以下のコードが必要です。

docker-compose.yml
volumes: 
    - /sys/fs/cgroup:/sys/fs/cgroup:ro
privileged: true
command: /sbin/init

詳細はこちらの記事にて解説します。centos8はデフォルトでコンテナ内でアクティブにならずwebサーバーも起動しません。ホストマシンのsystemdをマウントし、そしてprivileged: trueにてコンテナにroot権限を与えることで、コンテナのcentos8が動きます。

ポートを通す

docker-compose.yml
ports: 
    - "9000:80"
    - "3000:3000"

ここでホストマシンのlocalhost:9000localhost:3000をコンテナのlocalhostlocalhost:3000につなげる様にします。ホストマシンを9000にしたのは気分です。干渉しなければ他のポートでも大丈夫です。

DBの記述

docker-compose.yml
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にあるデータをまっさらにしたい場合はコンテナを止めて、ボリュームを削除すれば大丈夫です。

laravelのプロジェクトソースの調整

以上でwebサーバーとDBサーバーの準備は整いました。次はlaravelソースと細かい調整を行います。まずはlaravelディレクトリにプロジェクトを入れます。今回はバージョン6を入れます。ローカルにはcomposerが入っているものとします。

$ cd laravel
$ composer create-project "laravel/laravel=6.*" .

laravelのソースが並んだら.envを以下の様にDBの設定を書き込みます。docker-compose.ymlで設定した通りのパスワード、ユーザーです。

.env
...
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel_test
DB_USERNAME=root
DB_PASSWORD=rootroot
...

DB_HOSTdocker-compose.ymlのserviceで定義した名前dbで大丈夫です。こうすればマイグレーションができる様になります。

httpd.confとphp.iniの微調整

Laravelではドキュメントルート を /public 配下にする様に言われています。httpd.confのデフォルトのドキュメントルートは /var/www/htmlなので以下の様に変更しておきます

httpd.conf
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にするだけです。

composeを起動!

それでは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を起動させる

一応私のプロジェクトでは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に以下を追記します。

nuxt.config.js
srcDir: 'client/',

こうすることでclient配下はnuxtのソースだけを置いて設定ファイルやdistはLaravelのプロジェクトルートに出される様にします。この辺はチームの好みによるので自由に変更してください。

そしてコンテナ内に入って npm run devをすればnuxtの開発サーバーが立ち上がるのですが、その前にまたnuxt.config.jsに以下の内容を記述します。

nuxt.config.js
server: {
    host: '0.0.0.0'
},

dockerコンテナを使用しない場合はこの設定は要らないのですが、コンテナ内でnpm run devをしてそれに接続するには上記の設定が必要です。コンテナ内のlocalhost:3000に開発サーバーが立ち上がります。docker-compose.yml

docker-compose.yml
ports: 
    - "9000:80"
    - "3000:3000

この様にホストの3000とコンテナの3000ポートをつないでいたので、localhost:3000にアクセスすると

nuxtの画面が現れました。(UIフレームワークにvuetifyを選択するとこの画面になります。)これでnuxtの開発もコンテナ内で実行できます。

Copyright © 2021 jun. All rights reserved.