2015-11-06

OpenPNE を Cloud Foundry で動かす

「Cloud Foundry 百日行」第94日目、本日は大学や企業、ファンクラブなど様々な組織にあわせたサイトを作ることを可能にするSNSエンジン OpenPNE です。

公式サイトでは「OpenPNEは誰でも設置・運営ができ、豊富な機能を用いて用途に合わせ自由にカスタマイズすることができるSNS」と紹介されており、プラグインや他のアプリと連携することで様々な形態で運用することが出来るアプリのようです。 このアプリはPHP+MySQLで動作させることが出来ます。

基本情報

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

  • 1) ソースコードの取得
  • 2) アプリのデプロイ
  • 3) 動作確認

1. ソースコードの取得

ソースコードを取得します。
その後、 OpenPNE3.8 の最新安定版の 3.8.17.1checkout します。

$ git clone https://github.com/openpne/OpenPNE3.git
$ cd OpenPNE3/
OpenPNE3$ git checkout release-3.8.17.1
OpenPNE3$ ls
apps  bin  config  data  doc  i18n  lib  LICENSE  log  NOTICE  plugins  README  symfony  templates  test  web

2. アプリのデプロイ

2.1 設定ファイルの準備

セットアップガイド のとおり設定ファイルをコピーします。

OpenPNE3$ cp config/OpenPNE.yml.sample config/OpenPNE.yml
OpenPNE3$ cp config/ProjectConfiguration.class.php.sample config/ProjectConfiguration.class.php

コピーを実施後、 config/OpenPNE.yml を編集します。今回はSMTPサーバにはGmailを利用します。
なおGmailには自身のGmailアカウント情報が必要となります。

OpenPNE3$ vi config/OpenPNE.yml
OpenPNE3$ diff config/OpenPNE.yml.sample config/OpenPNE.yml
7c7
< base_url: "http://example.com"
---
> base_url: "http://openpne3.10.244.0.34.xip.io/"
15c15
< mail_domain: "example.com"
---
> mail_domain: "10.244.0.34.xip.io"
31c31
< #mail_smtp_host: "smtp.example.com"
---
> mail_smtp_host: "smtp.gmail.com"
35,40c35,40
< #mail_smtp_config:
< #  auth:     "login"
< #  username: "myusername"
< #  password: "password"
< #  ssl:      "tls"
< #  port:     587
---
> mail_smtp_config:
>   auth:     "login"
>   username: "<username>@gmail.com"
>   password: "<password>"
>   ssl:      "tls"
>   port:     587

2.2 PHP拡張モジュールの準備

PHPの拡張モジュールがインストールされるように .bp-config/options.json を作成します。
インストールが必要な拡張モジュールは セットアップガイド に記載されていますが、一部の動作(招待メール送信、jpegファイルの表示)に不足が生じたため opensslexif を加えています。

OpenPNE3$ mkdir .bp-config
OpenPNE3$ vi .bp-config/options.json
{
    "PHP_EXTENSIONS": ["mbstring","xml","pdo","pdo_mysql","pcre","json","gd","mcrypt","apc","openssl","exif"],
    "PHP_MODULES": ["fpm","cli"],
    "WEBDIR": "web"
}

2.3 MySQLのDB準備

利用するMySQLのDBを準備します。
手順はいつも通りアプリを --no-start オプションで cf push し、その後、MySQLのDBを作成します。最後にアプリと作成したDBをバインドして環境変数を取得出来るようにしておきます。

OpenPNE3$ cf push openpne3 --no-start
OpenPNE3$ cf create-service p-mysql 100mb opdb
OpenPNE3$ cf bind-service openpne3 opdb

2.4 DB初期化

まずは環境変数から作成したDBへの接続情報を確認します。

OpenPNE3$ cf env openpne3
:
System-Provided:
{
 "VCAP_SERVICES": {
  "p-mysql": [
   {
    "credentials": {
     "hostname": "10.244.7.6",
     "jdbcUrl": "jdbc:mysql://10.244.7.6:3306/cf_ca449fee_2168_4848_9309_8ddefb9a7fdc?user=ZDwelosGrjrqzpAL\u0026password=484s4mJZjWbkjI2W",
     "name": "cf_ca449fee_2168_4848_9309_8ddefb9a7fdc",
     "password": "484s4mJZjWbkjI2W",
     "port": 3306,
     "uri": "mysql://ZDwelosGrjrqzpAL:484s4mJZjWbkjI2W@10.244.7.6:3306/cf_ca449fee_2168_4848_9309_8ddefb9a7fdc?reconnect=true",
     "username": "ZDwelosGrjrqzpAL"
    },
    "label": "p-mysql",
    "name": "opdb",
    "plan": "100mb",
    "tags": [
     "mysql"
    ]
   }
  ]
 }
}
:

DBへの接続情報を取得後に、DB初期化の為に cf push にて一旦アプリを動作させます。

この際、コマンドオプションには3つのコマンドを指定します。
セットアップガイド を参考に

  • 入力事項をコマンドの引数としてデータベースの設定値を指定してインストールできる ./symfony openpne:fast-install
  • 開発環境用ファイルを削除を行う ./symfony project:clear-controllers

を指定します。
そしてプロセスを起動する為に

  • PHP Buildpack を利用した際の detected_start_command で設定される python /home/vcap/app/.bp/bin/start

を指定します。

OpenPNE3$ cf push openpne3 -c './symfony openpne:fast-install --dbms=mysql --dbuser=ZDwelosGrjrqzpAL --dbpassword=484s4mJZjWbkjI2W --dbhost=10.244.7.6 --dbport=3306 --dbname=cf_ca449fee_2168_4848_9309_8ddefb9a7fdc --internet && ./symfony project:clear-controllers && python /home/vcap/app/.bp/bin/start'

2.5 databases.yml の書出し

ここで再デプロイに向けて作業を実施します。上記 cf push によりアプリ内にDBとの接続情報が保存された databases.ymlconfig フォルダに作成されています。このファイルをローカルに書き出し保存しておきます。
これで次回 cf push しても既存DBへアクセス可能となります。

OpenPNE3$ cf files openpne3 app/config/databases.yml | sed -e '1,3d' > config/databases.yml

なおこの際,先頭3行に不要な情報が入ってしまうので | sed -e '1,3d' を使ってその3行を削除しています。

Getting files for app openpne3 in org k-nagai / space work as k-nagai...
OK

all:
  doctrine:
    class: sfDoctrineDatabase
:

2.6 manifest.ymlの作成

デプロイ用の manifest.yml を作成します。
ここで command には既に初期化済のDBが準備されているため、バージョンアップガイド に示されているコマンドを抜き出し指定します。

OpenPNE3$ vi manifest.yml
OpenPNE3$ cat manifest.yml
---
 applications:
 - name: openpne3
   buildpack: php_buildpack
   services:
     - opdb
   command: ./symfony doctrine:build --all-classes && ./symfony cc && ./symfony plugin:publish-assets && ./symfony project:clear-controllers && python /home/vcap/app/.bp/bin/start

2.7 デプロイ

cf push でアプリを再デプロイします。

OpenPNE3$ cf push

:

requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: openpne3.10.244.0.34.xip.io
last uploaded: Mon Oct 26 04:41:06 UTC 2015
stack: cflinuxfs2
buildpack: php_buildpack
 
     state     since                    cpu    memory          disk      details   
#0   running   2015-10-26 01:41:41 PM   1.5%   55.7M of 256M   0 of 1G 

以上で完了です。

3. 動作確認

管理画面用URL( http://openpne3.10.244.0.34.xip.io/pc_backend.php )にアクセスします。
初期のログインIDは adminpassword になります。


ログイン後にメニューの『メンバー管理』から『招待メール送信』画面を開きます。

メールの送信に成功したら受信したメールからアクティベーションを行います。

自身のプロフィールを設定したら一般サイトURL( http://openpne3.10.244.0.34.xip.io/ ) へログインします。


メニューの『コミュニティ検索』より『コミュニティ作成』のリンクを選択しサイトを作成してみます。


最後にアイコンを設定しましょう。
『写真を編集する』よりアップロード画面に移動し画像をアップロードします。


今回の動作確認は以上です。

なお、このアプリには多数のプラグインが準備されています。
プラグインチャンネルサーバ のサイトにはskype連携や日記などもアップされており、追加インストールは ./symfony opPlugin:install [plugin-name] で出来るようです。
必要な機能がある方は是非、 manifest.yml に追加して試してみてはいかがでしょうか。

おまけ

ここでは動作検証に発生したトラブルの解決手段を紹介します。

今回の検証において数回にわたりデプロイを繰り返していると、DBの初期化で以下のようなエラーが発生するようになりました。

2015-10-24T20:47:59.41+0900 [App/0]      ERR   SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`cf_90f2de74_1d84_4030_838a_4063ee9659ef`.`community_member`, CONSTRAINT `community_member_community_id_community_id` FOREIGN KEY (`community_id`) REFERENCES `community` (`id`) ON DELETE CASCA)
2015-10-24T20:47:59.49+0900 [DEA/0]      ERR Instance (index 0) failed to start accepting connections
2015-10-24T20:47:59.51+0900 [API/0]      OUT App instance exited with guid 73103822-6762-4e3f-9943-9eeada11ee5e payload: {"cc_partition"=>"default", "droplet"=>"73103822-6762-4e3f-9943-9eeada11ee5e", "version"=>"aaaee8c0-5028-48d0-9657-5bfcce40fd68", "instance"=>"7091905666e44c70881356ce35ed7d34", "index"=>0, "reason"=>"CRASHED", "exit_status"=>216, "exit_description"=>"failed to accept connections within health check timeout", "crash_timestamp"=>1445687279}

結論からお伝えすると、初期化の中で data/fixtures/011_import_first_community.yml を実行時に作成されたテーブルのAUTO_INCREMENTの値が1以外から開始されることが原因でした。通常、新規のテーブルの場合は1から始まるので問題ないのですが、繰り返していたためカウントだけが保存されてしまったようです。
data/fixtures/011_import_first_community.yml には固定で id が 1 のレコードを外部キーとして参照している箇所がある為、エラーを解消する為には以下の修正を加えることで対応出来ます。

$ git diff
diff --git a/data/fixtures/002_import_first_member.yml b/data/fixtures/002_import_first_member.yml
index f76e464..a230df3 100644
--- a/data/fixtures/002_import_first_member.yml
+++ b/data/fixtures/002_import_first_member.yml
@@ -1,5 +1,6 @@
 Member:
   first_member:
+    id: 1
     name: "OpenPNE君"
     is_active: 1
  
diff --git a/data/fixtures/011_import_first_community.yml b/data/fixtures/011_import_first_community.yml
index 339e8dc..e88e946 100644
--- a/data/fixtures/011_import_first_community.yml
+++ b/data/fixtures/011_import_first_community.yml
@@ -1,5 +1,6 @@
 Community:
   first_community:
+    id: 1
     name: "all"
  
 CommunityConfig:
@@ -30,6 +31,7 @@ CommunityConfig:
  
 CommunityMember:
   first_member:
+    id: 1
     community_id: 1
     member_id: 1
     is_pre: 0

これで必ず外部キーとなるレコードは id が 1 になるのでエラーは発生しなくなります。

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