2015-07-22

Shaarli を Cloud Foundry で動かす

「Cloud Foundry 百日行」第34日目は,シンプルなソーシャルブックマーク Shaarli です。

基本情報

手順の概要は以下の通りです。

  • 1) ソースコードの取得
  • 2) Cloud Foundry 環境へのプッシュ
  • 3) 動作確認
  • 4) 補足

1. ソースコードの取得

$ git clone https://github.com/sebsauvage/Shaarli/
$ cd Shaarli/
Shaarli$ ls
COPYING  images  inc  index.php  README.md  tpl

いつも通りです。PHPのアプリですね。

2. Cloud Foundry 環境へのプッシュ

公式サイトのドキュメントに従って起動に必要な設定を追加していきます。

Shaarli$ mkdir sessions
Shaarli$ vi sessions/.htaccess
php 1
SetEnv PHP_VER 5

モジュールの追加などは必要なさそうなのでこのままPushしても大丈夫そうです。

Shaarli$ cf push shaarli
(一部略)
-----> Uploading droplet (17M)


1 of 1 instances running

App started


OK

App shaarli was started using this command `$HOME/.bp/bin/start`

Showing health and status for app shaarli in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: shaarli.10.244.0.34.xip.io
last uploaded: Tue Jul 21 06:23:57 UTC 2015
stack: cflinuxfs2
buildpack: PHP

     state     since                    cpu    memory        disk      details   
#0   running   2015-07-21 03:24:16 PM   1.5%   28M of 256M   0 of 1G

起動しました。

3. 動作確認

ブラウザーからアプリにアクセスします。
ユーザの登録を行いログインをしましょう。

メインのページはこちら。

ブックマークリンクの追加は、上部メニューのAdd linkから行います。

登録をしたいページのURLをそのまま貼り付け、

ページの説明やタグ等を追記すれば完了です。

ちなみに上部メニューのToolsにあるShaare linkボタンをブラウザのツールバーなどに配置し、お気に入り登録ボタン感覚でページを追加することも可能です。

登録後のメニュー画面はこのようになります。

Shaarliではブックマークしたページを、画像として一覧することができます。
ブックマークが集まってきたところで上部メニューのPicture wallを押すと・・・

このようにページ内の画像や動画のサムネイルなどを見ることができます。(自力でこれだけの数を登録するのは骨だったためこちらの画像は公式サイトのサンプル画像をお借りしました。)

タイトルやタグだけでなく画像情報からもリンクを探すことができるのは中々に便利そうです。

4. 補足

さて、このアプリ、起動がお手軽なのは良いのですが、DBを使わない仕様となっているためデータの永続性がありません。
つまり再起動をかけると登録したブックマークなどのデータが消えてしまいます。
公式でもその点は意識をしているようで、 公式サイトのドキュメント にもバックアップの取り方が記載されています。

1つ目は、アプリケーションの中にある data/datastore.php というファイルをバックアップしておき、そのファイルを再配置することで復元を図る方法です。
Cloud Foundry環境にあるファイルを取得してくる方法については、 第24日目の記事 でも触れた cf files というコマンドが有効です。

Shaarli$ cf files shaarli app/htdocs/data/datastore.php
Getting files for app shaarli in org ukaji / space default as ukaji...
OK

<?php /* lZNbTxNBFMe/yrA++CLb3W4vdAghgcSERFOwJYIvZLo7Zcdud5adXWoxJOzWNzAajBijPhgTqtx80igvfpgRUr+FZ1pASyDGyWZ2LufMOef3nyHYwo8FNvNYyxqmaZTM3JJZMqBp4wQX1B5sRSzyqDYucDaHtYpLSOgxNIoErQkSr5Jlqvs0UvsW1uLQU6O8gTU3igKcyQybZVqswTIOb8R64AaTzJmAHxaDQ5WnaWLNocIOWRAx7qulMQh7n3o2b1IUcXSewQiqukwg+Aiqcd5okrChoypH1GER4iFyqEcjipr0FmrzGDVjEaE6C6H3+DLzdXV2EWtByFZJBAUybKhoWPOY33D6S9ewERhSisiy6FuUsMYD6gsehzZFgtejFgnBef2St1HM5bPZK8lagO5uG5DaIY2QiOJ6Xdd1gDxLRERrkCxUP4y4dC3iQPlkJsdyVq6WLZasgm2UCrnSjdq94oJYcHmV3bFXpoO5WrMcTDErXMmurc3NT+fdqZnig6pZth6NTVwjRQFqrVRcaCMjCM3cbAL7M35IUUPc99posTyPbOJDOVRHi4BeTS7UAA35FezNf7A/pzfMHlIcQOsz+5t53ihmzSWzYBrm1bc5B/GnPR476DaPfSdsy6R7crgrk69yI5klpCKTI5m8kskzmfzoHbw5Oe5euuTZCwVarZYuPAa0XJC+r8JDYqtbAWoQMVrn4WiNwqXzaSiuYWuqRyM7O7LzSXY6Mv0sO2/PBun3k60dmbyU6ZZMIMMnqt9ITl8fnR596e1uynRTJi9k8lEmYNCVyVOZ7IHZWRU/vx32jvdlug0+5YpaGWyAYQquwxDS7V/vt07fPZfJfq/7obd3IDfS/3kpw9yH1LJgbKtg9UEs1J8gRQj9oQcirv8G */ ?>

再配置については所定の位置に上記のファイルを置き、デプロイを行えばOKです。

2つ目は、アプリのToolメニュー内にあるExport機能、Import機能を使うものです。ワンボタンで状態の保存及び復元ができるため、ブラウザでアプリを閲覧可能な環境であればこちらの方が便利そうです。

さて、このようにDBを使わずファイルベースで状態を保持しているアプリケーションをCloud Foundryで動かす時には、もう一つ重要な事を意識しておく必要があります。
それは、アプリケーションのスケールアウトが正しく行われない、という事です。
スケールアウトを行えばその時の状態ごと複製してくれるように思えますが、実は複製したアプリケーションは初期状態のものとなってしまいます。つまりアプリの各インスタンスによって保持している状態が異なってしまうため、アプリを正しく使うことはできません。

このアプリケーションに限っては、スケールアウトをする必要に迫られないように、負荷が増えすぎない状態で利用をするべきでしょう。

おまけ

さて、PHPのbuildpackはユーザが設定可能なオプションがかなり豊富に用意されており、それに応じて様々な環境を用意することができます。
モジュールの追加、パッケージ管理ツールの適用、バイナリファイルの実行などラインナップは色々で、過去の記事で触れているものもいくつか存在します。

今回はおまけとしてあまり記事の中では触れられなさそうなオプションを試してみます。

A. WebサーバをApacheからNginxにしてみる

PHPのBuildpackで起動しているWebサーバはデフォルトの状態だとApacheなのですが、実はNginxに切り換えることも可能です。
設定ファイルを調整する必要が出た時などは自分の得意な方を選択するとスムーズかもしれません。

設定方法はこちら。

Shaarli$ mkdir .bp-config
Shaarli$ vi .bp-config/options.json
{
        "WEB_SERVER": "nginx"
}

たったこれだけです。後はいつも通りpushをするだけ。お手軽ですね。

B. アプリ起動前にコマンドを動かしてみる

タイトルそのままですがアプリケーション起動前に指定のコマンドを動かすオプションです。
設定方法はこちら。先の設定に追記します。

Shaarli$ mkdir .bp-config
Shaarli$ vi .bp-config/options.json
{
        "WEB_SERVER": "nginx",
        "ADDITIONAL_PREPROCESS_CMDS": "echo -----; printenv; echo -----;"
}

アプリの起動前に環境変数を出力するというだけのコマンドを動かしてみます。

先程のNginxを設定も込みでデプロイを行いましょう。

Shaarli$ cf push shaarli-nginx
(一部略)
App started


OK

App shaarli-nginx was started using this command `$HOME/.bp/bin/start`

Showing health and status for app shaarli-nginx in org ukaji / space default as ukaji...
OK

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: shaarli-nginx.10.244.0.34.xip.io
last uploaded: Tue Jul 21 07:57:45 UTC 2015
stack: cflinuxfs2
buildpack: PHP

     state     since                    cpu    memory          disk      details   
#0   running   2015-07-21 04:58:00 PM   1.3%   27.4M of 256M   0 of 1G 

起動しました。
ログを見てみます。

(一部略)
2015-07-21T16:57:53.87+0900 [STG/0]      OUT Finished: [2015-07-21 07:57:53.872908]
2015-07-21T16:57:56.24+0900 [STG/0]      OUT -----> Uploading droplet (17M)
2015-07-21T16:57:57.84+0900 [DEA/0]      OUT Starting app instance (index 0) with guid d13a2847-c762-48bf-8990-fc87fb816b4c
2015-07-21T16:57:59.85+0900 [App/0]      OUT -----
2015-07-21T16:57:59.85+0900 [App/0]      OUT CF_INSTANCE_ADDR=10.244.0.26:61516
2015-07-21T16:57:59.85+0900 [App/0]      OUT TMPDIR=/home/vcap/tmp
2015-07-21T16:57:59.85+0900 [App/0]      OUT PHPRC=/home/vcap/app/php/etc
2015-07-21T16:57:59.85+0900 [App/0]      OUT VCAP_APP_PORT=61516
2015-07-21T16:57:59.85+0900 [App/0]      OUT USER=vcap
2015-07-21T16:57:59.85+0900 [App/0]      OUT LD_LIBRARY_PATH=:/home/vcap/app/php/lib
2015-07-21T16:57:59.85+0900 [App/0]      OUT PATH=/bin:/usr/bin:/home/vcap/app/php/bin:/home/vcap/app/php/sbin
2015-07-21T16:57:59.85+0900 [App/0]      OUT PWD=/home/vcap
2015-07-21T16:57:59.85+0900 [App/0]      OUT LANG=en_US.UTF-8
2015-07-21T16:57:59.85+0900 [App/0]      OUT CF_INSTANCE_PORT=61516
2015-07-21T16:57:59.85+0900 [App/0]      OUT CF_INSTANCE_IP=10.244.0.26
2015-07-21T16:57:59.85+0900 [App/0]      OUT VCAP_SERVICES={}
2015-07-21T16:57:59.85+0900 [App/0]      OUT CF_INSTANCE_INDEX=0
2015-07-21T16:57:59.86+0900 [App/0]      OUT SHLVL=1
2015-07-21T16:57:59.86+0900 [App/0]      OUT HOME=/home/vcap/app
2015-07-21T16:57:59.86+0900 [App/0]      OUT PYTHONPATH=/home/vcap/app/.bp/lib
2015-07-21T16:57:59.86+0900 [App/0]      OUT CF_INSTANCE_PORTS=[{"external":61516,"internal":61516}]
2015-07-21T16:57:59.86+0900 [App/0]      OUT PORT=61516
2015-07-21T16:57:59.86+0900 [App/0]      OUT VCAP_APP_HOST=0.0.0.0
2015-07-21T16:57:59.86+0900 [App/0]      OUT CF_PROCESS_TYPE=web
2015-07-21T16:57:59.86+0900 [App/0]      OUT MEMORY_LIMIT=256m
2015-07-21T16:57:59.86+0900 [App/0]      OUT _=/usr/bin/printenv
2015-07-21T16:57:59.86+0900 [App/0]      OUT -----
2015-07-21T16:57:59.92+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: using the "epoll" event method
2015-07-21T16:57:59.92+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: nginx/1.6.2
2015-07-21T16:57:59.92+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: built by gcc 4.8.2 (Ubuntu 4.8.2-19ubuntu1) 
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: OS: Linux 3.16.0-41-generic
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: getrlimit(RLIMIT_NOFILE): 16384:16384
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: start worker processes
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: start worker process 39
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: start worker process 40
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: start worker process 41
2015-07-21T16:57:59.93+0900 [App/0]      OUT 07:57:59 nginx   | 2015/07/21 07:57:59 [notice] 35#0: start worker process 42
2015-07-21T16:57:59.95+0900 [App/0]      OUT 07:57:59 php-fpm | [21-Jul-2015 07:57:59] NOTICE: fpm is running, pid 36
2015-07-21T16:57:59.95+0900 [App/0]      OUT 07:57:59 php-fpm | [21-Jul-2015 07:57:59] NOTICE: ready to handle connections
(一部略)

アプリの起動前に printenv が動いているのがわかります。難しいアプリケーションを手探りで動かす時には心強い味方になってくれそうです。
よく見るとWebサーバもNginxが動いてくれていますね。

今回使用したソフトウェア