2015-08-13

Tiny Tiny RSS を Cloud Foundry で動かす

「Cloud Foundry 百日行」中休み前の最終日である50日目は,個人的に探しているフィード・リーダーの第2弾,PHPベースの Tiny Tiny RSS です。

このアプリはかなりの人気を誇っているようで, AltenativeTo でも同種のアプリの中では一番人気ですし,開発も非常に活発で今回の記事で動作確認を行ったバージョンの後にもどんどんコミットが積まれています。またデフォルトのフィードとして入っている このアプリのフォーラム でも活発に投稿が行われていました。またこれまで百日行で紹介してきたアプリとしては珍しく操作メニュー等も含めて日本語対応が行われており,ソフトウェアとしての成熟を感じました。

そういうことで,私も動かして実際に見てみたいという期待があり,動作確認を頑張ってみた結果,本来の予定である昨日に間に合わず,記事公開が今日になってしまいました。繰り上げを承諾していただいた @tnaoto さんに感謝します。

基本情報

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

  • 1) ソースコードの取得
  • 2) サービスの作成とバインド
  • 3) Cloud Foundry 向け設定
  • 4) アプリの起動
  • 5) 初期設定&動作確認

1. ソースコードの取得

いつも同様 Git のリポジトリーなのですが,このアプリのソースコードは独自に立てたと思われる GitLab 上で提供されています。

$ git clone https://tt-rss.org/gitlab/fox/tt-rss.git
$ cd tt-rss

2. サービスの作成とバインド

2.1. サービスの作成

このアプリはデータベースを使用するので,データベース・サービスを作成します。 https://tt-rss.org/gitlab/fox/tt-rss/wikis/home#server-side には,「PostgreSQL と MySQL (InnoDB必須) が使えるけど,PostgreSQL の方が tt-rss の性能はいいはず」(意訳) と書いてあるので,PostgreSQL を使います。

$ cf create-service PostgreSQL "Basic PostgreSQL Plan" pg4ttrss
Creating service instance pg4ttrss in org nota-ja / space 100 as nota-ja...
OK
..

2.2. アプリの作成

サービスとバインドするために,アプリを停止状態で Cloud Foundry 環境にプッシュします。

$ cf push tt-rss --no-start
Creating app tt-rss in org nota-ja / space 100 as nota-ja...
OK
..
Done uploading
OK

2.3. アプリとサービスのバインド

$ cf create-service PostgreSQL "Basic PostgreSQL Plan" pg4ttrss
Creating service instance pg4ttrss in org nota-ja / space 100 as nota-ja...
OK
..

3. Cloud Foundry 向け設定

アプリが Cloud Foundry 上で動作するよう,設定を行っていきます。今回は全て PHP Buildpack の機能である options.json の範囲内で対応できました。

PHP Buildpack 用の設定を格納するディレクトリー .bp-config を作り,そこに options.json ファイルを作ります。

$ mkdir .bp-config
$ touch .bp-config/options.json

options.json ファイルを編集します。

$ emacs .bp-config/options.json

できあがったファイルがこちらです。

$ cat .bp-config/options.json
{
    "PHP_EXTENSIONS": ["mbstring", "curl", "gd", "pgsql"],
    "ADDITIONAL_PREPROCESS_CMDS": "pushd $HOME/htdocs; ln -s ../lib .; ls -l; popd"
}

上の行の PHP_EXTENSIONS については, このページ を参考に必要/推奨される拡張モジュールを記述しています。 JSONposix については,それぞれ ここここ で「拡張ライブラリーの導入は不要」(意訳) と書かれていたので記載しませんでしたが,特に問題は起きませんでした。

下の行, ADDITIONAL_PREPROCESS_CMDS は,アプリの起動コマンドの前に実行したいコマンドを記述するためのものです。百日行では, 第34日目の Shaarli の記事 で一度紹介されていました。

今回は,アプリ内の PHP 及び JavaScript のライブラリーの参照関係が Cloud Foundry の PHP Buildpack によって壊されてしまうため,それを修復するシンボリック・リンクを作るのにこの機能を利用しています。

話が若干横道に逸れますが,なぜ PHP Buildpack によって参照関係が壊されることになったかというと,その理由は PHP Buildpack が持つ WEBDIR と LIBDIR という機能にあります。

WEBDIR は,アプリのドキュメント・ルートを指定する機能です。Cloud Foundry の PHP Buildpack のデフォルト動作では,アプリのルート・ディレクトリーの htdocs ディレクトリーがそれに該当し,存在しなければ作成されて,その中にルート・ディレクトリー内のファイルは原則として全て移動されます。

LIBDIR は,アプリのライブラリーを格納する場所を指定する機能です。Cloud Foundry の PHP Buildpack のデフォルト動作では,アプリのルート・ディレクトリーの lib ディレクトリーがそれに該当します。アプリのルート・ディレクトリーに lib ディレクトリーが存在する場合,それは htdocs 内には移動されません。これは,ライブラリーを外部から参照可能なドキュメント・ルートに置くことは,セキュリティ的にあまり良くないとされているためです。

以上をまとめると,以下の図のようになります。

ところが本アプリでは,アプリのルート・ディレクトリー=ドキュメント・ルートであり,かつ lib ディレクトリーはその直下にあるという前提で PHP / JavaScript のコードが書かれているので,いざライブラリーを参照しに行こうとすると,そこにそんなファイルはない,ということになってしまい,エラーが発生しました。

そこで今回は,(セキュリティ上はあまり良くない解決策ですが) ドキュメント・ルートである htdocs 内に,一つ上の階層にある lib へのシンボリック・リンクを張り,アプリが想定しているのと同じ状態を再現することで,エラーを回避することにしました。

4. アプリの起動

先ほど作成した .bp-config/options.json の内容を反映させるため,アプリをプッシュします。このとき同時にアプリの起動が行われます。

$ cf push tt-rss
..
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: tt-rss.10.244.0.34.xip.io
last uploaded: Wed Aug 12 07:31:33 UTC 2015
stack: cflinuxfs2
buildpack: PHP

     state     since                    cpu    memory          disk      details
#0   running   2015-08-12 04:35:03 PM   0.0%   38.9M of 256M   0 of 1G

起動しました。

5. 初期設定&動作確認

アプリのURLにブラウザーからアクセスすると,初期設定画面が表示されます:

cf env の情報

$ cf env tt-rss
..
 "VCAP_SERVICES": {
  "PostgreSQL": [
   {
    "credentials": {
     "uri": "postgres://6f48a232-6a74-46ec-9554-37756d0d07c2:n42qc10tb30u1q6lvq6nvo9pcr@192.168.15.91:5432/6f48a232-6a74-46ec-9554-37756d0d07c2"
    },
    "label": "PostgreSQL",
    "name": "pg4ttrss",
    "plan": "Basic PostgreSQL Plan",
    "tags": [
     "PostgreSQL",
     "Database storage"
    ]
   }
  ]
 }
..

をもとにデータベース接続情報を入力し,

【Test Configuration】ボタンを押します。

設定に問題がなければ,この後順次【Initialize database】でデータベースを初期化し,【Save configuration】で今行った設定をファイル (config.php) に保存します。最後に【loading tt-rss now】のリンクをクリックするとログイン画面が表示されるので, InstallationNotes の以下の記述

  1. After finishing with the installer, open your Tiny Tiny RSS installation at http://your.site.com/tt-rss/ and login with default credentials (username: admin, password: password).

を参考に,ユーザー名とパスワードを入力してログインします。

この後,場合によっては「データベース・アップデーター」のフローに入ることもありますが,指示に従って【更新の実行】, 【OK】を押したのち再ログインすることで,利用画面に到達できます。

ログイン後最初の画面はこんな感じです:

右側の【操作…】ボタンから【フィードを購読する…】をクリックして本ブログのフィードを追加し,

左の【カテゴリー割り当てなし】の中の,追加したフィードの名前をクリックすると,フィードの読み込み及び記事の表示もできました。

おまけ: config.php の保存

本アプリでは,データベース接続その他の設定がドキュメント・ルートの config.php ファイルに保存されています。

以前他の PHP アプリの記事( SugarCRM, Simple Machines Forum, Shaari )でもありましたが,Cloud Foundry ではファイルシステムが揮発性 (アプリが停止/再起動するとファイルが消えてしまう) なので,このファイルを保存しておかないと再起動時に初期設定のやり直しになります。

そこで再起動時に楽をするために,config.php ファイルを保存しておきます。ファイルの取得は cf files コマンドで行います。

$ cf files tt-rss app/htdocs/config.php > config.php

先頭3行ほど不要な情報が混ざってしまっているので消します。

$ emacs config.php
$ git diff --no-index -- config.php~ config.php
diff --git a/config.php~ b/config.php
index af838d8..c8488ad 100644
--- a/config.php~
+++ b/config.php
@@ -1,6 +1,3 @@
-Getting files for app tt-rss in org nota-ja / space 100 as nota-ja...
-OK
-
 <?php
        // *******************************************
        // *** Database configuration (important!) ***

これをアプリのルート・ディレクトリーに置いておけば,次回以降アプリを更新するときも初期設定を回避することができます。

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