ElasticBeanstalkで.ebextensionsを利用してnginx+php-fpmの構成にする

ElasticBeanstalkでPHPやるぞ！となると構成はhttpdになります。
が、nginx+php-fpmに変更したいという場合があると思います。
また、他のプログラム言語でもミドルウェアを変えたい場合もあると思います。

今であればDockerを使う、OpsWorksを使うという手も有ると思いますが、ElasticBeanstalkで普通にEC2上でのミドルウェアなどの設定変更を行ったことがなかったので調査がてらやってみたのでメモ。

やってみて構成変更はでき、実際に動いてもいるのですが、ElasticBeanstalkのヘルスチェックでEnhancedの設定では問題ありと表示されてしまいます。。。(basicならOK)
上記あたりの詳細をご存知の方、いらっしゃいましたら教えていただけると嬉しいです。

# 参照

+ [Linux サーバーでのソフトウェアのカスタマイズ](http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/customize-containers-ec2.html)
+ [[AWSマイスターシリーズ] AWS Elastic Beanstalk](http://www.slideshare.net/AmazonWebServicesJapan/aws-aws-elastic-beanstalk)
+ [td-agent2をAWS Elastic Beanstalkにデプロイする](http://dev.classmethod.jp/cloud/td-agent2-elastic-beanstalk/)
+ [AWSのElastic Beanstalkで「php5.4」「nginx」環境を作る](http://lab.sonicmoov.com/development/elastic-beanstalk/)

# 結論

+ .ebextensions配下に設定ファイルを置くことで環境をカスタマイズできる
+ パッケージのインストールや任意のシェルスクリプト実行程度であれば手軽
+ Chefなどの高機能な設定はないので、より細かい設定を行う場合にはOpsWorksの方がメンテナンスしやすい気がする。もしくはカスタムAMIの運用（Packerなどでコード化しつつ）
+ YAMLなどで設定ファイル書くのはつらい
+ httpdを止めたことが原因となり、ElasticBeanstalkのヘルスチェックでエラーとなってしまったよう。Webサーバーを変えるなどの場合にはDockerやOpsWorksの方が楽そう（監視のミドル追加などは楽だと思いますが)

# どうやって環境を変更するのか

大きく分けて2つ方法があると思います。

+ カスタムAMIを使う
+ .ebextensions配下に設定ファイルを配置する。

1点目は記載したとおりで予め、ミドルウェアをインストール、設定しておいたEC2を作成し、そのAMIを取得後、ElasticBeasnstalkで起動するAMIとして使うという話です。Packerなどを使えばカスタムAMIの作成もコード化出来るのでより良いかと思います。

2点目はソースコードのrootディレクトリ配下に **.ebextensions**　というディレクトリを作成し、その配下にファイルを配置して独自の処理を行える機能を使うというものです。

今回は2点目を利用してやってみます。

#  .ebextensionsの仕様

[Elastic Beanstalk 環境設定](http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/customize-containers.html)

仕様としては以下のようです。

+ ファイル形式はYAMLかJSON
+ 拡張子は.configとする
+ ファイルはバンドルするソースコードのroot直下に.ebextensionsディレクトリを作成し、その配下に配置
+ 実行はアルファベット順。.ebextensions/01run.config は .ebextensions/02do.config より先に実行される

なお、実行できる処理は以下があるようです。

[設定ファイルでAWS Elastic Beanstalkをカスタマイズする](http://www.infoq.com/jp/news/2012/11/elastic-beanstalk-config-files)

| 名称 | 詳細 |
|:-----------|:------------|
| packages       |  yum、rubygems、python、および rpmのパッケージインストールが出来る。バージョン指定も可能 |
| groups     |   Linuxグループの追加 |
| users       |  Linuxユーザーの追加 |
| sources         |  アーカイブを取得し、指定されたパスに展開する |
| files       |  ファイルを作成して配置する。インラインもしくは指定URLの内容|
| commands    |    シェルコマンドを実行できる。アプリケーションやWebサーバがセットアップされる前、アプリケーションが展開される前に実行される |
| container_commands    |シェルコマンドを実行できる。commandsと違い、アプリケーションとWebサーバがセットアップされてアプリケーションが展開された後、アプリケーションがデプロイされる前に実行される
| services     |  サービスの起動・停止などが出来る |
| option_settings     |  各環境で設定可能なパラメーターの設定ができる。TomcatのJVMの最大ヒープサイズなど。 |

実行順番は以下のとおりのようです。

1. packages
1. groups
1. users
1. sources
1. files
1. commands
1. services
1. container_commands

# デプロイ時の処理について

上記によって予めミドルウェアの設定やインストールは出来そうです。ただし、それとは別でアプリケーションデプロイ時に実行されるスクリプト群があるようでそれについても変更の必要があります。以下のP58に記載があります。

[[AWSマイスターシリーズ] AWS Elastic Beanstalk](http://www.slideshare.net/AmazonWebServicesJapan/aws-aws-elastic-beanstalk)

内容としては以下で、デプロイ時に実行されるコマンドについて記載されています。

+ commandsに指定された内容
+ /opt/elasticbeanstalk/hooks/appdeploy/pre/*
+ continer_commandsに指定された内容
+ /opt/elasticbeanstalk/hooks/appdeploy/enact/*
+ /opt/elasticbeanstalk/hooks/appdeploy/post/*

実際の環境を見ると/opt/elasticbeanstalk/hooks配下で他のディレクトリ、ファイルもあってhttpdの設定などもありそうですが、仕様が不明のため、そのままとします。。。

今回はhttpdの再起動を行っている以下のファイルを置き換えてnginxを起動するようにします。

```lang:/opt/elasticbeanstalk/hooks/appdeploy/enact/99_reload_app_server.sh
set -e

if [ "$EB_FIRST_RUN" = "true" ]; then
  # Hard restart on first app deploy
  service httpd restart
else
  # Graceful restart on other app deploys
  service httpd graceful
fi
```

# やってみる

以下の記事で同じような事をやっており、とても参考になりました。

[AWSのElastic Beanstalkで「php5.4」「nginx」環境を作る](http://lab.sonicmoov.com/development/elastic-beanstalk/)

実際にサーバー上で変更したファイルは以下の3つです。

+ /etc/php-fpm.d/www.conf
+ /etc/nginx/nginx.conf
+ /opt/elasticbeanstalk/hooks/appdeploy/enact/99_reload_app_server.sh

/etc/php-fpm.d/www.conf ではユーザーをnginxからwebappというElasticBeanstalkでのデプロイ時に利用されるユーザーに変更するようします。

/etc/nginx/nginx.conf　ではDocumentRootを/var/www/htmlとし、アプリケーションのユーザー、グループをwebapp/webappとしました。

/opt/elasticbeanstalk/hooks/appdeploy/enact/99_reload_app_server.sh は先ほど記載したリンクの内容をそのまま利用しています。

それぞれを変更、設定できるように.ebextensions配下にファイルを配置しました。

内容は以下のリポジトリを参照下さい。

[toshihirock/elastic-beanstalk-php56-nginx](https://github.com/toshihirock/elastic-beanstalk-php56-nginx)

上記を利用し、ebコマンドなどでデプロイしてもPHPのWebアプリが動作するのが確認できます。

```bash
$git clone https://github.com/toshihirock/elastic-beanstalk-php56-nginx.git
$cd elastic-beanstalk-php56-nginx

# 対話形式で設定
$eb init

# 対話形式で設定
$eb create
```

起動後、念のため、ログイン後、状態を確認してみます。

```bash
$sudo service --status-all |grep -e nginx -e httpd -e php-fpm
Equivalent Upstart operations: start httpd, stop httpd, restart httpd, status httpd
httpd is stopped
nginx (pid  2668) is running...
php-fpm-5.6 (pid  2683) is running...
php-fpm-5.6 (pid  2683) is running...

$ ls /opt/elasticbeanstalk/hooks/appdeploy/enact/
01_flip.sh  99_reload_app_server.sh  99_reload_app_server.sh.bak
```

filesでファイルを上書きした場合、bakでバックアップも取っているようです。

# ヘルスチェックについて

一応上記によってデプロイができますが、ヘルスチェックで危険状態判定となってしまいます。具体的には **EnvironmentHealth** というものでエラーとなっているようです。(設定をEnhancedからBasicにすればOKになりますが。。）

公式なドキュメントでどのようなチェックを行っているか見つけられなかったのであれですが、httpdのログなどを監視しているようでサービスが起動しておらず、ログも取れないのでエラーとなっているのではないかと思います。上記と判断したのは以下のファイル群からです。

+ /opt/elasticbeanstalk/bin/healthd-configureというファイルがある
+ 上記で/opt/elasticbeanstalk/lib/ruby/bin/healthd-configureを実行
+ beanstalk-core-healthdというGemを呼び出している?
+ /opt/elasticbeanstalk/lib/ruby/lib/ruby/gems/2.2.0/gems/beanstalk-core-healthd-1.1/lib/elasticbeanstalk/healthd.rbをみると/etc/healthd/config.yamlを読み込んでチェックで利用している
+ /etc/healthd/config.yamlではログのパス「/var/log/httpd/healthd/application.log」の記載がありチェックしているよう

/opt/elasticbeanstalk配下をもう少し色々調べればわかるかもしれませんが、S3へのログ送信などもきっとhttpd用になっていると思うのでそれら全て調べるのはかなり大変そうです。。。（ドキュメントもなさそうだし。。）

ebextensionsではfluentdを入れたり、Zabbixを入れるというようなことは良い気がしますが、Webサーバー自体を変えて完全に対応させるのはかなり難しいということが分かりました。このレベルのことをやる場合にはDockerやOpsWorksをやった方が良さそうであるという印象です。