AWS Elastic Beanstalk+Grav(Flat-File CMS)でお手軽Webサイト構築

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、城内です。だんだん梅雨も明けていき、暑い季節になってきましたね。
今回は、以前WordPressで紹介されていた簡単Webサイト構築のさらなる簡易版、データベース不要のFlat-File CMSのGravを使用したWebサイト構築を紹介したいと思います。

はじめに

Flat-File CMSといえば、このブログでも以前PicoというCMSが紹介されていました。

ちなみに、Picoには虚空(Coqoo)という日本語の拡張版もあるようです。こちらも気になったのですが、今回は現在も開発が盛んに行われているという理由で、Gravを選んでみました。

システム構成

システム構成は以下の通りです。

grab_web

WordPressの時とほぼ同じような構成ですが、Gravはデータベースがないことで、WordPressのサイト更新時に発生していた、Webサーバ上のファイルとデータベース内の情報との一時的な不整合が発生しません。

また、Gravにはプレビュー機能がないのですが、上記の構成にすることで、Masterサーバ上で本番と同じ状態を確認することができるため、安心して更新ができるようになっています。

Grav構築

では、さっそく構築に入りたいと思いますが、システム構成は最初にご紹介したWordPressの構成と同じになりますので、細かいAWS上の操作は省略します。もし操作に迷うようでしたら、上記のWordPressの記事を参考にしてみてください。

EC2インスタンス作成

まず、Masterサーバを構築するため、EC2インスタンスを立ち上げます。
例のごとく、ベースとなる環境はユーザデータで整えてしまいますので、必要な環境要件はこちらの「Requirements | Grav Documentation」で確認してください。

#cloud-config
repo_update: true
repo_upgrade: all
locale: ja_JP.UTF-8
timezone: "Asia/Tokyo"
packages:
 - php56
 - php56-gd
 - php56-mbstring
 - mod24_ssl
 - git
runcmd:
 - cp -p /etc/php.ini /etc/php.ini.org && sed 's%;date.timezone =%date.timezone = "Asia/Tokyo"%' /etc/php.ini.org > /etc/php.ini
 - test -f /etc/sysconfig/httpd && echo "umask 002" >> /etc/sysconfig/httpd
 - service httpd start
 - chkconfig httpd on
 

また、S3やElastic Beanstalkの操作が必要となるため、今回はPower Userロールを付けています。

Gravインストール

Gravのインストールは、先ほどの「Requirements | Grav Documentation」とこちら「Installation | Grav Documentation」のサイトを参考にしてください。

手順は以下の通りです。

$ sudo git clone https://github.com/getgrav/grav.git /var/www/html/
Cloning into '/var/www/html'...
remote: Counting objects: 10511, done.
remote: Compressing objects: 100% (167/167), done.
remote: Total 10511 (delta 60), reused 0 (delta 0), pack-reused 10322
Receiving objects: 100% (10511/10511), 3.93 MiB | 2.11 MiB/s, done.
Resolving deltas: 100% (5836/5836), done.
Checking connectivity... done.
$ (cd /var/www/html && sudo php bin/grav install)
Preparing to install vendor dependencies...

Loading composer repositories with package information
Installing dependencies
  - Installing erusev/parsedown (1.5.3)
    Downloading: 100%

  - Installing erusev/parsedown-extra (0.7.0)
    Downloading: 100%
...
Cloning into 'user/themes/antimatter'...
remote: Counting objects: 1242, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 1242 (delta 3), reused 0 (delta 0), pack-reused 1232
Receiving objects: 100% (1242/1242), 1.63 MiB | 776.00 KiB/s, done.
Resolving deltas: 100% (698/698), done.
Checking connectivity... done.
SUCCESS cloned https://github.com/getgrav/grav-theme-antimatter -> /var/www/html//user/themes/antimatter

$ sudo chown -R apache:apache /var/www/
$ sudo find /var/www/ -type f | xargs sudo chmod 664
$ sudo find /var/www/ -type d | xargs sudo chmod 775
$ sudo find /var/www/ -type d | xargs sudo chmod +s
$ sudo vi /etc/httpd/conf/httpd.conf
...
# Further relax access to the default document root:
<Directory "/var/www/html">
    #
    # Possible values for the Options directive are "None", "All",
    # or any combination of:
    #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # Note that "MultiViews" must be named *explicitly* --- "Options All"
    # doesn't give it to you.
    #
    # The Options directive is both complicated and important.  Please see
    # http://httpd.apache.org/docs/2.4/mod/core.html#options
    # for more information.
    #
    Options Indexes FollowSymLinks

    #
    # AllowOverride controls what directives may be placed in .htaccess files.
    # It can be "All", "None", or any combination of the keywords:
    #   Options FileInfo AuthConfig Limit
    #
    AllowOverride All

    #
    # Controls who can get stuff from this server.
...
$ sudo service httpd restart
Stopping httpd:                                            [  OK  ]
Starting httpd:                                            [  OK  ]

あと、今回の構成では、本番用の画像ファイル等はS3に格納するため、Elastic Beanstalk用のアーカイブに含まれないよう、一工夫入れます。
imagesディレクトリを、アーカイブするディレクトリ外にコピーし、userディレクトリ配下にシンボリックリンクを作成します)

$ sudo cp -pr /var/www/html/images /var/www/
$ sudo ln -s /var/www/images /var/www/html/user/images

投稿用ユーザ作成

記事の投稿は、新しいページ用のディレクトリ作成とMarkdownファイル(.md)のアップロードで行います。
そのため、今回はgrav-userという名前で、Webサーバの実行ユーザと同じグループapacheに所属させたユーザを作成します。

$ sudo useradd -u 501 -g 48 -d /home/grav-user -m -s /bin/bash grav-user
$ sudo cp -pr /home/ec2-user/.ssh /home/grav-user
$ sudo chown -R grav-user:apache /home/grav-user/.ssh

また、権限の調整をするため、umaskの設定を入れます。

$ sudo bash -c "echo 'umask 002' >> /home/grav-user/.bash_profile"
$ sudo cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config.org && sudo bash -c "sed 's%/usr/libexec/openssh/sftp-server%/usr/libexec/openssh/sftp-server -u 002%' /etc/ssh/sshd_config.org > /etc/ssh/sshd_config"
$ sudo service sshd restart
sshd を停止中:                                             [  OK  ]
sshd を起動中:                                             [  OK  ]

動作確認

以下のようなデフォルトのホーム画面が表示されれば成功です。

ec2_01

一応、以降の操作のために、動作確認を兼ねて以下のようなテストページを作成しておきます。

ec2_02

Dillingerのような適当なMarkdownエディタで、以下のようなMarkdownファイルを作成し、

---
title: Test
---

# テストページ

あいうえお

* かきくけこ
* さしすせそ

![classmethod logo](/user/images/cmlogo.png)

以下の場所に格納します(02.testディレクトリは手動で作成します)。

/var/www/html/
┗user
  ┗pages
    ┣01.home
    ┗02.test
      ┗default.md

Elastic Beanstalk構築

次に、Elastic Beanstalkを構築します。

.ebextensions作成

Elastic BeanstalkにてEC2インスタンスが起動される際、必要なセットアップを行うため、.ebextensionsの機能を使用します。

$ sudo mkdir /var/www/html/.ebextensions
$ sudo vi /var/www/html/.ebextensions/01_ossetup.config
packages:
 yum:
  mod24_ssl: []

commands:
 set-timezone-os:
  command: cp /usr/share/zoneinfo/Japan /etc/localtime

 set-timezone-php:
  command: test -f /etc/php.ini.org || cp -p /etc/php.ini /etc/php.ini.org && sed 's%;date.timezone =%date.timezone = "Asia/Tokyo"%' /etc/php.ini.org > /etc/php.ini

 set-umask-httpd:
  command: test -f /etc/sysconfig/httpd && grep "umask" /etc/sysconfig/httpd || echo "umask 002" >> /etc/sysconfig/httpd

 make-directory-images:
  command: test -d /var/www/images || mkdir -m 777 /var/www/images

S3バケット作成

画像データやElastic Beanstalk用のアーカイブを格納するS3バケットを作成します。今回は、cm-grav-testというバケットを作成しました。
(ちなみに、バケットポリシーはCloudFrontでのオリジン設定時に自動で追加してもらうため、ここではあえて設定していません)

そこにuser/imagesディレクトリ配下の画像データと/var/www/htmlディレクトリ配下のファイルやディレクトリをアーカイブしたZIPファイルをアップロードします。

手順は以下の通りです。

$ (cd /var/www/html/ && sudo php bin/grav clear-cache --all)

Clearing cache

Cleared:  cache/*

Touched: /var/www/html/user/config/system.yaml

$ aws s3 sync /var/www/html/user/images s3://cm-grav-test/user/images
upload: user/images/cmlogo.png to s3://cm-grav-test/user/images/cmlogo.png
upload: user/images/.gitkeep to s3://cm-grav-test/user/images/.gitkeep
$ (export _ZIPFILE="grav_$(date '+%Y%m%d%H%M%S')" && cd /var/www/html && sudo zip -ry /tmp/${_ZIPFILE}.zip . && aws s3 cp /tmp/${_ZIPFILE}.zip s3://cm-grav-test/resource/ && sudo rm -f /tmp/${_ZIPFILE}.zip)
  adding: .editorconfig (deflated 43%)
  adding: bin/ (stored 0%)
  adding: bin/gpm (deflated 55%)
...  
  adding: .gitignore (deflated 44%)
  adding: LICENSE (deflated 41%)
upload: /tmp/grav_20150720175026.zip to s3://cm-grav-test/resource/grav_20150720175026.zip

S3バケット上は以下のようになっています。

$ aws s3 ls s3://cm-grav-test/ --recursive
2015-07-20 17:50:32   12565103 resource/grav_20150720175026.zip
2015-07-20 16:31:15          0 user/images/.gitkeep
2015-07-20 16:31:15      12871 user/images/cmlogo.png

Elastic Beanstalkアプリケーション作成

上記のZIPファイルをソースに、Webアプリケーションを作成します。
作成方法やパラメータについては、過去の記事で何度も出てきているので省略します。もし分からない場合は、過去のElastic Beanstalkの関連記事を参考にしてください。

仕上がりは以下の通りです。

$ aws elasticbeanstalk describe-environments --region ap-northeast-1
{
    "Environments": [
        {
            "ApplicationName": "grav-test",
            "EnvironmentName": "grav-test-prod",
            "VersionLabel": "resource.grav_20150720175026.zip",
            "Status": "Ready",
            "EnvironmentId": "e-chtixvc7pa",
            "EndpointURL": "awseb-e-c-AWSEBLoa-1RHRA8A6JP2PZ-600687977.ap-northeast-1.elb.amazonaws.com",
            "SolutionStackName": "64bit Amazon Linux 2015.03 v1.4.3 running PHP 5.6",
            "CNAME": "grav-test-prod.elasticbeanstalk.com",
            "Health": "Green",
            "AbortableOperationInProgress": false,
            "Tier": {
                "Version": " ",
                "Type": "Standard",
                "Name": "WebServer"
            },
            "DateUpdated": "2015-07-20T08:59:45.890Z",
            "DateCreated": "2015-07-20T08:55:27.913Z"
        }
    ]
}
$ aws elasticbeanstalk describe-environment-resources --environment-name "grav-test-prod" --region ap-northeast-1
{
    "EnvironmentResources": {
        "EnvironmentName": "grav-test-prod",
        "AutoScalingGroups": [
            {
                "Name": "awseb-e-chtixvc7pa-stack-AWSEBAutoScalingGroup-YJR62DW6SRV5"
            }
        ],
        "Triggers": [],
        "LoadBalancers": [
            {
                "Name": "awseb-e-c-AWSEBLoa-1RHRA8A6JP2PZ"
            }
        ],
        "Queues": [],
        "Instances": [
            {
                "Id": "i-b53e4040"
            }
        ],
        "LaunchConfigurations": [
            {
                "Name": "awseb-e-chtixvc7pa-stack-AWSEBAutoScalingLaunchConfiguration-13L9CG4AN2QZN"
            }
        ]
    }
}

CloudFront構築

最後に、CloudFrontを作成します。

オリジンには、上記で作成したElastic BeanstalkのURL(grav-test-prod.elasticbeanstalk.com)とS3のバケット名(cm-grav-test.s3.amazonaws.com)を設定します。

なお、上記の手順ではS3バケット作成時にあえてバケットポリシーを設定していないため、S3バケットのオリジンを設定する際は、以下のようにバケットポリシーを追加してもらうようにしてください。

cf_01

[Origins]と[Behaviors]の設定は以下の通りです。

cf_02

cf_03

出来上がり

以下のようにCloudFront経由でアクセスし、画像のリンク切れもなく正常に画面が表示されれば成功です。
(Elastic BeanstalkのURLへのアクセスでは、EC2インスタンス上には画像ファイルがないため、画像は表示されません)

finish_01

finish_02

さいごに

さて、いかがでしたでしょうか?ライトなWebサイトを作成してみたいと思っている方にはお薦めです!
個人的には、Gravはお手軽でなかなか面白いツールだと思ったので、もっとテーマやプラグインを追加してごにょごにょしてみたいと思います。

記事にできるかは分かりませんが(笑)。

おまけ

Masterサーバでサイトを更新した後、本番サーバに反映させるには、以下の手順を実施します(コマンド出力は省略)。

$ (cd /var/www/html/ && sudo php bin/grav clear-cache --all)
$ aws s3 sync /var/www/html/user/images s3://cm-grav-test/user/images
$ export _ZIPFILE="grav_$(date '+%Y%m%d%H%M%S')"
$ (cd /var/www/html && sudo zip -ry /tmp/${_ZIPFILE}.zip . && aws s3 cp /tmp/${_ZIPFILE}.zip s3://cm-grav-test/resource/ && sudo rm -f /tmp/${_ZIPFILE}.zip)
$ aws elasticbeanstalk create-application-version --application-name grav-test --version-label $_ZIPFILE --source-bundle S3Bucket=cm-grav-test,S3Key=resource/${_ZIPFILE}.zip --region ap-northeast-1
$ aws elasticbeanstalk update-environment --environment-name grav-test-prod --version-label $_ZIPFILE --region ap-northeast-1
$ unset _ZIPFILE

参考情報