猫でもわかるWeb開発・プログラミング

本業エンジニアリングマネージャー。副業Webエンジニア。Web開発のヒントや、副業、日常生活のことを書きます。

Ansibleを使ってPHP7環境をVagrant上に構築してLaravelに入門

この記事は Laravel Advent Calender 2017 7日目の記事です。

昨日の記事は LaravelのControllerクラスって何やってるの? - Qiita でした

Laravel DI からはじまり何もかもが揃っていてグッドなフルスタックフレームワークLaravelを使っていきましょう。Ansibleで環境構築してLaravelが動くまでをやっていきたいと思います。

なんでHomestead使わないの?

Laravel Homestead っていう、Laravelがいい感じに動くVagrant Boxみたいなのがあるんですが

  • Homestead ブラックボックスすぎてよく分かってないからちゃんと理解した
  • Ansible 勉強したい
  • 実際動かす際には仮想環境じゃないときもある

とまあれこれあるので、AnsibleでPHP7 + Laravelが動く環境を頑張って作ってみたいなとおもいます。

(Vagrant使ってますが、Ansible流れればいいのでVagrantである必要は)ないです。

とりあえずVagrantつくる

まずは最小構成で。 vagrant up できて vagrant ssh できる程度のもの適当に作ります。Cent OS 7.1 で。

$ cat Vagrantfile
# coding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "centos/7"
  config.vm.hostname = "vagrant"

  # ipアドレス ipは適当に変更しておk
  config.vm.network :private_network, ip: "192.168.33.11"
  config.ssh.insert_key = false
  config.ssh.forward_agent = true
end

$ vagrant up
# なんやかんや

$ vagrant ssh
[vagrant@vagrant ~]$

できた。

Vagrant に Ansible を流せるようにする

ディレクトリ構成こんな感じで

Vagrantfile
ansible/
 └playbook.yml

VagrantfileにAnsibleの設定を追記

$ cat Vagrantfile
# coding: utf-8
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  config.vm.box = "centos/7"
  config.vm.hostname = "vagrant"

  # ipアドレス ipは適当に変更しておk
  config.vm.network :private_network, ip: "192.168.33.11"
  config.ssh.insert_key = false
  config.ssh.forward_agent = true

  # ansibleの設定
  config.vm.provision "ansible" do |ansible|
    ansible.playbook = "ansible/playbook.yml"
  end
end

vagrantが起動している状態で

$ ls
Vagrantfile   ansible/

$ cat ansible/playbook.yml
- hosts: all
  sudo: true
  user: vagrant

$ vagrant provision
==> default: [vagrant-hostsupdater] Checking for host entries
==> default: [vagrant-hostsupdater]   found entry for: 192.168.33.11 vagrant
==> default: Running provisioner: ansible...
    default: Running ansible-playbook...
[DEPRECATION WARNING]: Instead of sudo/sudo_user, use become/become_user and
make sure become_method is 'sudo' (default).
This feature will be removed in a
future release. Deprecation warnings can be disabled by setting
deprecation_warnings=False in ansible.cfg.

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [default]

PLAY RECAP *********************************************************************
default                    : ok=1    changed=0    unreachable=0    failed=0

まあ何も書いてないので changed=0 ですがとりあえずOKになるのを確認。

このタイミングで初めて知ったのですが、 sudo: true はAnsible 1.9 からはDeprecatedらしいので become: true に書き換えます。

$ cat ansible/playbook.yml
- hosts: all
  become: true

Ansible で gitを入れてみる

Ansibleでgitを入れます。ほんとはソースをダウンロードしてビルドすると、バージョンが固定されて良い気がするのですが、めんどいのでyumで入れてしまいます。Ansibleの動作確認も兼ねてます。

Ansibleはだいたいディレクトリ構成が決められています。基本的には「gitのインストール」「Apacheのインストール」といった単位でモジュール化して、roles というディレクトリ以下に置きます。以下のリポジトリに実際に出来たAnsibleを置いておいたので、これをみてもらうと分かりやすいかと思います。

github.com

ansible/
+playbook.yml
+roles/
 +tasks/
  +git/
   +main.yml

roles/git/tasks/main.yml *1 にgitのインストール用のAnsibleを書きます。

$ cat ansible/roles/git/tasks/main.yml
- name: install git
  yum: name=git state=installed

yumを使ってgitをinstalledな状態にするということです。

続いてplaybook.ymlに以下を追記します。

$ cat ansible/playbook.yml
- hosts: all
  become: true
  user: vagrant
  roles:
  - git

roles に git を追加することで。roles/git/tasks/main.yml が実行されます。

$ vagrant provision
==> default: [vagrant-hostsupdater] Checking for host entries
==> default: [vagrant-hostsupdater]   found entry for: 192.168.33.11 vagrant
==> default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY [all] *********************************************************************

TASK [Gathering Facts] *********************************************************
ok: [default]

TASK [git : install git] *******************************************************
changed: [default]

PLAY RECAP *********************************************************************
default                    : ok=2    changed=1    unreachable=0    failed=0

changed=1 となりました。gitが入っているか確かめてみます。

$ vagrant ssh
Last login: Mon Dec  4 22:57:06 2017 from 10.0.2.2
[vagrant@vagrant ~]$ git

AnsibleでPHP7

PHPはgitと違って、デプロイしたコードの動作に差異が出る可能性があるので、これこそソースからビルドしたほうがいいのですが、やはり面倒なのでyumで入れてしまいます。

roles以下にphp7を作成します。

$ cat ansible/roles/php7/tasks/main.yml
---
- name: yum install epel-repease
  yum: name=epel-release state=installed

- name: add remi-repo repository
  command: rpm -ih http://rpms.famillecollet.com/enterprise/remi-release-7.rpm creates=/etc/yum.repos.d/remi.repo

- name: install php 7.1
  yum: name={{ item }} enablerepo=remi,remi-php71 state=installed
  with_items:
    - php
    - php-devel
    - php-fpm
    - php-gd
    - php-mbstring
    - php-mcrypt
    - php-mysqlnd
    - php-pdo
    - php-xml
    - php-zip

$ cat ansible/playbook.yml
- hosts: all
  become: true
  user: vagrant
  roles:
  - git
  - php7

$ vagrant provision

パッケージはなんとなく使いそうなのを適当にチョイスしてインストールしています。 vagrant ssh して php -v すると php がインストールされているはずです。phpの設定ファイル php.ini もAnsibleで管理されているのが望ましいので、ansible管理するようにします。

roles/php7/templates/php.ini.j2 に php.ini のテンプレートを配置して、roles/php7/tasks/main.yml に、このテンプレートをデプロイするコマンドを書きます。

基本的にはデフォルトのテンプレートでよいのですが、timezoneだけちゃんと設定されていることを確認してください https://github.com/yoshikyoto/php7-ansible/blob/41c103ef61ee6488c2293ff2327eb7c2ebb372aa/roles/php7/templates/php.ini.j2#L903

- name: deploy php.ini
  template:
    src: php.ini.j2
    dest: /etc/php.ini

詳しくは先程紹介したリポジトリを見て下さい。 php.ini をデプロイして php が正しく動くことを確認します。

$ vagrant provision

$ vagrant ssh
[vagrant@vagrant ~]$ ls -la /etc/php.ini
-rw-r--r-- 1 root root 62433 Dec  4 23:21 /etc/php.ini # きっとタイムスタンプが更新されている

[vagrant@vagrant ~]$ php -i
# ちゃんと設定ファイルが読み込まれているか

AnsibleでApache

AnsibleでApacheをソースからビルドして入れようと思ったのですが、Vagrantの centos/7 は最初からApacheが入っているらしく、ソースからビルドしようとするとちょっと複雑なことに...ということで、ソースのビルドのあたりはなんとなく適当に書きました。。。まあconfigさえちゃんとデプロイできれば問題ないので...

ソースのビルド&インストールは https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/roles/apache2_4/tasks/install.yml みたいな感じですね。

roles/apache2_4/tasls/main.yml には以下を書いておきます。

---
- name: check if exist apache
  command: service httpd status
  ignore_errors: True
  register: check_apache

# Apacheのインストール
- include: install.yml
  when: check_apache|failed

- name: enable apache
service: name=httpd enabled=yes

service httpd status 叩いてみて Apache がインストールされて無さそうだったらインストールします。そして、OS起動時にApacheも起動するように設定しておきます。

ApacheのconfigをAnsibleで管理する

roles/apache2_4/templates 以下に Apache の config のテンプレートを置いておきます。

https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/roles/apache2_4/templates/httpd.conf.j2

基本的にはデフォルトのままですが、Apacheの起動ユーザーだけvagrantに変更しています。*2

https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/roles/apache2_4/templates/httpd.conf.j2#L66-L67

User vagrant
Group vagrant

さて、このconfigをデプロイします。

ここで問題があります。ソースからビルドした場合、 ApacheのConfigファイルは /usr/local/apache2/conf 以下にあったりするのですが、もとから入っているやつとかyumで入れたやつは /etc/httpd/conf 以下にあったりします。一応両方に対応しておきます。

#####
# httpd.confのデプロイ
#####
- name: check existance /etc/httpd/conf
  stat: path=/etc/httpd/conf
  register: etc_httpd_conf

- name: deploy /etc/httpd/conf/httpd.conf
  template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
  when: etc_httpd_conf.stat.exists

- name: check existance /usr/local/apache2/conf
  stat: path=/usr/local/apache2/conf
  register: usr_local_apache_conf

- name: deploy /usr/local/apache2/conf/httpd.conf
  template: src=httpd.conf.j2 dest=/usr/local/apache2/conf/httpd.conf
  when: usr_local_apache_conf.stat.exists

Apache動作確認

Apacheがインストールされていることを確認します。

[vagrant@vagrant ~]$ service httpd status
Redirecting to /bin/systemctl status httpd.service
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2017-12-05 02:52:01 UTC; 1min 32s ago
     Docs: man:httpd(8)
           man:apachectl(8)
 Main PID: 19685 (httpd)
   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"
   CGroup: /system.slice/httpd.service
           ├─19685 /usr/sbin/httpd -DFOREGROUND
           ├─19686 /usr/sbin/httpd -DFOREGROUND
           ├─19687 /usr/sbin/httpd -DFOREGROUND
           ├─19688 /usr/sbin/httpd -DFOREGROUND
           ├─19689 /usr/sbin/httpd -DFOREGROUND
           └─19690 /usr/sbin/httpd -DFOREGROUND

さてここで、Apacheを入れたので、Webページにアクセスしてみたいところです。Vagrantfileに以下を追記したうえで vagrant reload します。

config.vm.network "forwarded_port", guest: 80, host: 58080

これを行うと、hostの58080ポートがvagrantの80ポートにフォワーディングされるようになります。 localhost:58080 にアクセスしてみまよう。

f:id:yoshiki_utakata:20171207134409p:plain

Apacheが動いていることがわかりました。

Apache で php7 が動いていることを確認する

vagrantのbox centos/7の設定がそうなっているのか、すでにPHP7がApache上で動いているみたいです。 vagrant ssh してみて、Apache上でphpが動いているか軽く確認します。

vagrant@vagrant ~]$ sudo su -
Last login: Thu Dec  7 01:45:48 UTC 2017 on pts/1
[root@vagrant ~]# vi /var/www/html/test.php
[root@vagrant ~]# cat /var/www/html/test.php
<?php

phpinfo();

これで http://localhost:58080/test.php にアクセスしてみます。

f:id:yoshiki_utakata:20171207134620p:plain

PHPのバージョンなどが確認できます。

composer のインストール

PHP開発するならcomposerもインストールしておきたいです。PHP7をインストールする時に composer も同時にインストールされるようにしました。以下をAnsibleのrole/php7以下のタスクに追加します。((本当はshell: curlじゃなくてちゃんとインストールしたい...)

- name: install composer
  shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin && mv /usr/bin/composer.phar /usr/bin/composer
         creates=/usr/bin/composer

Laravelのプロジェクト作成

composerを入れたことにより、Laravelプロジェクトを作成できるようになりました。vagrantのホームディレクトリ以下に適当なLaravelプロジェクトを作成してみます。 vagrant ssh して以下のコマンドで作成できます。

[vagrant@vagrant ~]$ composer create-project laravel/laravel myapp 5.5.*

これで Laravel 5.5 でプロジェクトが作成されます。初回はパッケージのインストールなどで時間がかかります。

ApacheでLaravelを動かすための設定を入れる

ApacheでLaravelを動かすための設定を入れます。

今回は、 roles/apache2_4/templates/laravel.conf.j2 というものを作成しました。

<VirtualHost *:80>
        DocumentRoot /home/vagrant/myapp/public

        ErrorLog /etc/httpd/logs/laravel_error.log
        CustomLog /etc/httpd/logs/laravel_access.log combined

        <Directory "/home/vagrant/myapp/public">
                AllowOverride All
                Require all granted
        </Directory>
</VirtualHost>

ApacheでLaravelのプロジェクトを動かすためには、 AllowOverride All の設定を入れる必要があるので注意です。

この config を apache の conf.d ディレクトリにデプロイするようにします。

https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/roles/apache2_4/tasks/config.yml#L22-L39

#####
# laravel.conf のデプロイ
#####
- name: check existance /etc/httpd/conf.d
  stat: path=/etc/httpd/conf.d
  register: etc_httpd_conf_d

- name: deploy /etc/httpd/conf.d/laravel.conf
  template: src=laravel.conf.j2 dest=/etc/httpd/conf.d/laravel.conf
  when: etc_httpd_conf_d.stat.exists

- name: check existance /usr/local/apache2/conf.d
  stat: path=/usr/local/apache2/conf.d
  register: usr_local_httpd_conf_d

- name: deploy config
  template: src=laravel.conf.j2 dest=/usr/local/apache2/conf.d/laravel.conf
when: usr_local_httpd_conf_d.stat.exists

これで http://localhost:58080/ にアクセスすると... Forbidden になってしまいます

SELinuxを無効化する

SELinuxというのがジャマをしているらしいです。これを無効化するのが良いのかドウか微妙ですが…とりあえず無効化します。

適当にlaravelというroleを作成して(ドンドン雑になってきましたが気にしない...)、SELinuxを無効化する設定を Ansible にいれます。

https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/roles/laravel/tasks/main.yml

####
# Laravel動かすためにSELinuxを無効化したほうがよさげ
####
- name: install libselinux-python
  yum: name=libselinux-python state=latest

- name: disable SELinux
selinux: state=disabled

最終的に playbook.yml はこうなりました。

https://github.com/yoshikyoto/php7-ansible/blob/1ebf06244a94ee02cbe7a66996c4fecb4a6b807e/playbook.yml

これを vagrant provision で流して、 http://localhost:58080/ にアクセスすると...

f:id:yoshiki_utakata:20171207135701p:plain

Laravelが動くようになりました!

ここから開発とかしていくにはどうしたらいいのか

とりあえずAnsibleでLaravel環境を構築するまでを書きましたが、実際に開発する際には、Vagrantのsynced_folderとかを使って開発していくのが良いと思います。長くなってしまいましたのでここまで。synced folder については別記事でかくかもしれないです!これでLaravelの開発環境が整ったぞ!

*1:ディレクトリは必ず複数形に!

*2:本当はvagrantじゃなくてちゃんとapache用のユーザーを作ったほうがいいのですが、今回は簡単のためにvagrantユーザーで起動します。