AWS OpsWorksを使ってPHP 5.6の環境構築とLaravel 5.1のデプロイ作業を自動化する。 #opsworks

_top

 

 

こんにちは、エンジニアマンの吉田です。

アルカナではPHPフレームワークとしてZendFrameworkを利用することが多いのですが、最近だとLaravelを使い始めているエンジニアもいるようで、そのWebアプリケーションを稼働させるためのサーバーの環境構築やアプリケーションのデプロイ作業を簡素化できるといいなぁと思い、AWS OpsWorksを使って自動化させることにしてみました。

AWS OpsWorksは、アルカナだと2013年頃から使い始めているのですが、縁あってAmazon目黒オフィスで開催された「AWSプロダクトシリーズ|よくわかるAWS OpsWorks」や「DevLOVE現場甲子園2014 東日本大会」などでお話させていただく機会などもありました。

そんな感じで、かれこれ2年ほど付きあっているOpsWorksですが、デフォルトで提供されている機能でPHPを動かすとバージョンが5.3となってしまうため、Laravelのようなモダンなフレームワークを採用したアプリケーションを動作させることができないのです。昔は気遣いのできる良い子だったのに…。

と、ノスタルジックでブルーな気分になっても仕方ないので、相手の気持ちを察して自分から歩み寄って解決するほかありません。

OpsWorksのサーバーの構築はChefによって自動化されていて、幸いにもソースコードがGithubで公開されているので、サーバー構築時の内部処理がどのようになされているかを知ることができます。

また、OpsWorksでは自分で作成したChef Cookbookを適用させることもできるため、Laravel 5.1で開発されたアプリケーションを動作させるためのサーバー構築作業とソースコードのデプロイ作業は、自分でChef Cookcookを作成してしまえば実現することが可能です。

というわけで、今回はPHP 5.6の環境構築とLaravel 5.1アプリケーションのデプロイ作業を、OpsWorksを使ってどのように自動化できるかを紹介してみたいと思います。

 

前提となる知識

今回はOpsWorksとLaravelを取り扱うため、以下のような知識があると理解がしやすいかもしれません。

Linux、Apache、SSL、PHP、Composer、MySQL、AWS RDS、AWS EC2、Chef、Berkshelf、Git

AWS OpsWorksとLaravelについては細かな言及はいたしませんので、公式サイトを参照くださいませ。

 

OpsWorksで実際に動かしてみよう

細かい説明をするよりも、実際のサーバー構築とアプリケーションのデプロイの手順をみてみましょう。

事前にChef Cookbookは自分で作成しなければなりませんが、それさえ完成すれば手順はとても簡単です。

AWS OpsWorksによるサーバー構築とデプロイのおおまかな手順は以下の通りです。

  • AWS OpsWorksでStackを作成
  • AWS OpsWorksのStackにLayerを作成
  • AWS OpsWorksのLayerにChefのレシピを設定
  • AWS OpsWorksのLayerにインスタンスを追加
  • AWS OpsWorksでインスタンスを起動
  • AWS OpsWorksのStackにAppを作成
  • AWS OpsWorksでAppをデプロイ

 今回は、デプロイするサンプルのアプリケーションとして、 https://github.com/Stolz/Wiki に置いてあるLaravel 5.1で開発されたWikiをデプロイしてみたいと思います。

インフラの構成としては、

  • MySQLサーバー×1台
  • PHPアプリケーションサーバー×1台

という2台構成で構築してみます。

 

Stackの追加

AWS管理コンソールにログインし、「OpsWorks」を選択します。

 

「Add Stack」を選択します。
“Stack”とは、ある一つのシステム構成の一式を管理するための概念で、アルカナではよく、○○案件開発環境、○○案件ステージング環境、○○案件本番環境、といった単位でStackを使用しています。

 

Name項目に「wiki」と入力します。
Default SSH key項目で、キーペアを選択します(EC2の画面から事前にキーペアを登録してください。キーペア設定が無いとSSHログインができません)。
続いて、下部の「Advanced」をクリックします。

 

Use custom Chef cookbooksで「Yes」を選択します。
Repository typeに「Git」を選択し、Repository URLに「https://github.com/yoshida/httpd24_php56_opsworks.git」のURLを入力します。
Manage Berkshelfで「Yes」を選択します。
続いて、Custom JSONに値を入力します。

 

Custom JSONの項目に以下のJSONを入力します。

{
  "apache": {
    "package": "httpd24",
    "service_name": "httpd",
    "version": "2.4",
    "lock_dir": "/var/run/httpd",
    "default_site_enabled": false,
    "listen_addresses": ["*"],
    "listen_ports": [80,443]
  },
  "php": {
    "packages": [
      "php56",
      "php56-devel",
      "php56-mcrypt",
      "php56-mbstring",
      "php56-gd",
      "php56-bcmath",
      "php56-tidy",
      "php56-pdo",
      "php56-mysqlnd",
      "php56-pecl-memcached",
      "php56-pecl-apcu",
      "php56-opcache"
    ],
    "directives": {
      "error_log": "/var/log/httpd/php_errors.log"
    }
  },
  "laravel5_deploy": {
    "dotenv": {
      "APP_ENV": "development",
      "APP_DEBUG": true,
      "APP_KEY": "your-application-key",
      "FACEBOOK_OAUTH_CLIENT_ID": "your-id",
      "FACEBOOK_OAUTH_CLIENT_SECRET": "your-secret",
      "GITHUB_OAUTH_CLIENT_ID": "your-id",
      "GITHUB_OAUTH_CLIENT_SECRET": "your-secret",
      "GOOGLE_OAUTH_CLIENT_ID": "your-id",
      "GOOGLE_OAUTH_CLIENT_SECRET": "your-secret",
      "TWITTER_OAUTH_CLIENT_ID": "your-id",
      "TWITTER_OAUTH_CLIENT_SECRET": "your-secret"
    }
  }
}

 

今回デプロイするWikiアプリケーションでは、ログインを必要とするシステムになっているので、Facebook、Google、Github、TwitterいずれかのOAuthのIDとKeyを取得して、Custom JSONの下記項目の値に設定してください。

 "FACEBOOK_OAUTH_CLIENT_ID": "your-id",
 "FACEBOOK_OAUTH_CLIENT_SECRET": "your-secret",
 "GITHUB_OAUTH_CLIENT_ID": "your-id",
 "GITHUB_OAUTH_CLIENT_SECRET": "your-secret",
 "GOOGLE_OAUTH_CLIENT_ID": "your-id",
 "GOOGLE_OAUTH_CLIENT_SECRET": "your-secret",
 "TWITTER_OAUTH_CLIENT_ID": "your-id",
 "TWITTER_OAUTH_CLIENT_SECRET": "your-secret"

※この設定を行わないと、ログインができずWikiが利用できません。

 

また、Laravelで必要となるAPP_KEYも必要となるので、ご自身で作成してCustom JSONのAPP_KEYの項目に設定してください。

 "APP_KEY": "your-application-key", 

※この設定を適切に行わないと、真っ白の画面が表示されサイトにアクセスできません。
※APP_KEY参考: http://laravel-recipes.com/recipes/283/generating-a-new-application-key 

 

最後に「Add Stack」をクリックします。

 

これでStackが追加されました。

 

Layerの作成と設定

続いて、レイヤーを追加するため、「Add a Layer」を押します。
レイヤーとは、”PHPサーバ” や “MySQLサーバ” といったサーバの役割を管理する概念です。
後述する手順にも出てきますが、EC2インスタンスは必ずどこかのレイヤーに属することになります。

 

Layer typeで「Custom」を選択します。
Nameに「PHP5.6 App Server」、Short nameに「php56app」と入力します。
「Add Layer」をクリックします。

 

PHP5.6 App Serverレイヤーが追加されました。
続いて、MySQLサーバ用のレイヤーを追加するため、「+ Layer」をクリックします。

 

Layer typeでMySQLを選択し、「Add Layer」をクリックします。
OpsWorksでは、デフォルトで用意されているレイヤーがあり、PHPのほかにRailsやJavaやnodeなどのレイヤーもあったりします。

 

これで、MySQLのレイヤーが追加されました。
続いて、MySQLレイヤーの設定変更をするため、MySQLレイヤーのSettingsの右隣にある編集アイコンをクリックします。

 

Custom JSONに以下のJSONを入力し、「Save」をクリックします。

{
  "mysql": {
    "mysql_bin": "/usr/bin/mysql"
  }
}

※この設定は本来は不要なのですが、Deployするとfailすることがあるので、それを避けるためのおまじないです。。

 

これで設定が適用されました。
※もし、デフォルト以外のVPCを使っている場合は、NetworkのPublic IP addressesをyesに設定してください。
続いて、PHP5.6 App Serverの編集をするため、レイヤー一覧画面へ戻ります。

 

PHP5.6 App Serverレイヤーのレシピの設定を行うため、Recipesの右隣りにある編集アイコンをクリックします。

 

Custom Chef Recipesという項目があるので、ここにレシピを設定します。

 

Setup、Configure、Deploy、Undeployの項目に、以下のレシピを入力し [+] をクリックして追加します。
※レシピは、スペース区切りで張り付けるとまとめて登録することができます。

  • Setup :   apache2   php   apache2::mod_php5   apache2::mod_ssl   composer   prompt
  • Configure :   php::configure
  • Deploy :   deploy::php-deploy   deploy::laravel5-deploy
  • Undeploy :   deploy::php-undeploy

レシピを設定したら「Save」をクリックします。

 

これで設定が適用されました。
※もし、デフォルト以外のVPCを使っている場合は、NetworkのPublic IP addressesをyesに設定してください。
続いて、各レイヤーにインスタンスを追加するため、「Instances」をクリックします。

 

Instanceの追加

MySQLレイヤーにインスタンスを追加するため、MySQLレイヤーの「Add an instance」をクリックします。

 

Sizeで「t2.micro」を選択し、「Add Instance」をクリックします。
※ここではコストの低いt2.microを選択していますが、インスタンスタイプは何でも構いません。

 

これで、MySQLレイヤーにインスタンスが追加されました。
続いて、PHP5.6 App Serverレイヤーにインスタンスを追加するため、PHP5.6 App Serverレイヤーの「Add an instance」をクリックします。

 

さきほどと同様に、Sizeで「t2.micro」を選択して「Add Instance」をクリックします。

 

これで、MySQLレイヤーとPHP5.6 App Serverレイヤーに1つずつインスタンスが追加されました。
インスタンスを起動するために、それぞれの「start」 をクリックします。

 

インスタンスの起動が完了するまで、5分~10分かかります。

この時、どのような処理がされているかというと、

  • EC2インスタンスを起動
  • OpsWorksのデフォルトで用意されているChefレシピの実行
  • 自身で設定したChefレシピの実行

といった処理が自動的に実行されてインスタンスが起動します。

MySQLレイヤーに設定したインスタンスは MySQLのインストールや初期設定がされてすぐにDBが使用できる状態で起動され、PHPレイヤーに設定したインスタンスは Apache/PHP/Composerのインストールや初期設定が完了してApacheが起動した状態で起動します。
今回はそれぞれのレイヤーに1台のインスタンスしか設定していませんが、PHPのレイヤーに複数台のインスタンスを追加することで、まったく同じ構成のサーバーを Start ボタンを押すだけで構築することができます。
レイヤーにELBを設定する事もできるので、PHPアプリケーションサーバのスケールアウトも簡単にできます。

サーバーの起動が完了するとこのようにonlineと表示されます。
続いて、アプリケーションの設定を行うため、「Apps」をクリックします。

 

Appの追加

新しくアプリケーションを追加するために「Add an app」をクリックします。

 

それぞれの項目に以下の値を設定します。

  • Settings:
    • Name: wiki
    • Type: PHP
    • Document root: public
  • Data Sources:
    • Data source type: OpsWorks
    • Database instance: db-master1
    • Database name: wiki
  • Application Source:
    • Repository type: Git
    • Repository URL: https://github.com/Stolz/Wiki.git

 

今回デプロイするPHPアプリケーションはSSLの設定が必要なのでSSLの設定を行います。

  • SSL Settings:
    • Enable SSL: Yes
    • SSL certificate: SSL証明書
    • SSL certificate key: SSL証明書の秘密鍵

ここで設定したSSL証明書は、Chefレシピ内で自動的にApacheの設定ファイルに適用してくれます。

実際に運用するアプリケーションではないので適当なオレオレ証明書を適用しています。
参考までに、オレオレ証明書を作成するためのコマンドを載せておきますね。

openssl genrsa 2048 > server.key
openssl req -new -key server.key > server.csr
openssl x509 -days 3650 -req -signkey server.key < server.csr > server.crt
cat server.crt
cat server.key

設定が完了したら、「Add App」をクリックします。 

 

Appのデプロイ

これでアプリケーションが追加されました。
続いて、インスタンスにアプリケーションをデプロイするため、「deploy」をクリックします。

 

デプロイの確認画面が表示されるので、「Deploy」をクリックします。

 

デプロイ中は、このような画面が表示され、おおよそ3~5分程度の時間がかかります。

デプロイ時には、

  • Apacheのバーチャルホストの設定
  • GitリポジトリからソースコードをClone
  • ルートディレクトリをCloneしたディレクトリへ変更
  • composer installの実行
  • Laravelの設定ファイルである.envファイルの設定
  • 書込権限が必要なディレクトリのパーミッション設定

といったようなことが自動的に行われるようにしています。

 

デプロイが完了すると、successfulと表示されます。
続いて、アプリケーションの初期設定に必要なLaravelのmigrateを行うため、「Stack」をクリックします。

 

「Run Command」をクリックします。

 

Commandで「Execute Recipes」を選択し、Recipes to executeに「deploy::laravel5-migrate-refresh」を入力します。
※Execute Recipesでは、Cookbook内にある任意のレシピを手動で実行することができます。
※「deploy::laravel5-migrate-refresh」レシピでは、内部的に php artisan migrate:refresh –seed を実行しています。

Instancesの項目で、「db-master1」のチェックを外し、「php56app1」だけが選択されている状態にして「Execute Recipes」をクリックします。

 

レシピの実行中はこのような画面になります。

 

レシピの実行が完了すると、successfulと表示されます。
アプリケーションを開くために「Instances」をクリックしてインスタンス一覧画面へ遷移します。

 

「PHP5.6 App Server」レイヤーのインスタンス一覧で、Public IPのリンクがあるのでクリックします。

 

このような感じで、Wikiのアプリケーションにアクセスすることができました。やったね!

 

 

もし、サイトにアクセスできない場合は、SSHでログインして以下のエラーログなどを確認すると解決の糸口が見つかるかもしれません。

  • /srv/www/wiki/current/storage/logs/*.log
  • /var/log/httpd/wiki-error.log
  • /var/log/httpd/error.log
  • /var/log/httpd/php_errors.log

 

レイヤーで設定したレシピについて

PHP5.6 App Serverレイヤーで設定したレシピについて、少し説明を補足したいと思います。

OpsWorksでは、ライフサイクルイベントという概念があって、各イベントが発生した時にどのレシピが実行されるのか?を自分で設定することが可能です。

例えば、今回の場合だと、 PHP5.6 App Serverレイヤーで以下のようにレシピを設定をしました。

  • Setup :   apache2   php   apache2::mod_php5   apache2::mod_ssl   composer   prompt
  • Configure :   php::configure
  • Deploy :   deploy::php-deploy   deploy::laravel5-deploy
  • Undeploy :   deploy::php-undeploy

ポイントは Setup と Deploy のイベント時に実行されるレシピなので、それについて簡単に説明します。

 

Setup

Setupライフサイクルイベントは、EC2インスタンスが起動した後に発生するイベントです。なので、このタイミングでミドルウェアのインストールや初期設定を行うレシピを設定しています。

  • apache2
    • Apacheのインストールおよび初期設定をします。
  • php
    • PHPのインストールおよび初期設定をします。今回はStack Custom JSONでphp56等のパッケージを指定して、バージョン5.6をインストールしています。
  • apache2::mod_php5
    • ApacheでPHPモジュールを実行できるように設定します。
  • apache2::mod_ssl
    • ApacheでSSLを利用できるように設定します。
  • composer
    • Composerをインストールします。
  • prompt
    • SSH接続時のプロンプトにStack名が表示されるようにPS1を設定します。

apache2, php, composerのレシピについては、Berkshelfを使ってChef Supermarketから取得するようにしています。
Berksfileファイルはこちらに置いてあるので、興味があればご参考ください。

 

promptレシピは必須ではありませんが、 OpsWorks経由で起動したインスタンスのPS1をカスタマイズするレシピです。
OpsWorksはデフォルトだとホスト名にインスタンス名(php56app1 や db-master1 など)が設定され、プロンプト表示もホスト名が表示されるのですが、Stackが複数になってくると、どのStackのサーバーにSSHログインしているのかがわからなくなりがちです。なので、このレシピを使ってSSHログイン時のプロンプト表示にStack名も表示されるようにしています。
こちらのレシピは以下に置いてあります。

 

Deploy

Deployライフサイクルイベントは、AppsからDeployを行った時に実行されるので、ここでLaravelの初期設定を行っています。

  • deploy::php-deploy: リポジトリからソースコードを取得してOpsWorksの規定のディレクトリに展開し、Apacheバーチャルホストの設定を行います。
  • deploy::laravel5-deploy: Laravel 5.1で必要な初期設定(composer installの実行、.envの設定、パーミッションの設定)を行います。

それぞれのレシピは以下に置いてあるので、興味があればご参考くださいませ。

 

まとめ

今回は、OpsWorksによるサーバー構築とデプロイの自動化を紹介しましたが、いかがだったでしょうか。

もし、新しいインスタンスを起動するたびに手作業で初期設定を行うと、それだけでかなりの時間がかかってしまいます。

OpsWorksを使うことで、必要なChefのレシピさえ作成してしまえば、以降のサーバ構築やデプロイにかかる手間を大幅に削減することが可能です。

もし、まだChefを使ったことがなければ、OpsWorksなら手軽にChefを使うことができるのでオススメです。OpsWorksは利用するにあたっての追加料金もかからないので是非どうぞ☆

 

デワデワ、Enjoy DevOps life with PHP!

 

謝辞

今回のブログを書くにあたっては、以下の記事を参考にさせていただきました。この場を借りてお礼申し上げます。