2015-09-11

Ghost を Cloud Foundry で動かす

「Cloud Foundry 百日行」第59日目は,Node.js ベースのブログ・プラットフォーム Ghost です。Markdown で記事が書けて,リアルタイムでプレビューもできるあたりが魅力的です。

基本情報

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

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

1. ソースコードの取得

今回は 公式サイトのインストール手順 に従って,最新版を公式サイトからダウンロードします。検証時点での最新版は 0.7.0 でした。

$ curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip
$ mkdir ghost
$ cd ghost/
$ unzip ../ghost.zip

以下は必須ではありませんが,後の修正のために,Gitで管理します。

$ git init
$ git add .
# git commit -m "Unzipped"

2. Cloud Foundry 向け変更

Deploy Ghost blog to Cloud Foundry を参考に,cfenv パッケージを package.json に追加します。

$ emacs package.json
..
$ git diff -- package.json
diff --git a/package.json b/package.json
index acf20d5..94619dc 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,8 @@
   },
   "optionalDependencies": {
     "mysql": "2.1.1",
-    "pg": "4.1.1"
+    "pg": "4.1.1",
+    "cfenv": "1.0.0"
   },
   "devDependencies": {
     "bower": "1.4.1",

参考記事では cf-env パッケージを使うことになっていますが,cf-env は廃されて cfenv になったので,この記事ではそちらを使いました。

cf. https://www.npmjs.com/package/cf-env

次に,config.example.js をもとに config.js を作成&変更します。変更箇所は以下の通りです。

$ cp config.example.js config.js
$ emacs config.js
..
$ git diff --no-index -- config.example.js config.js
diff --git a/config.example.js b/config.js
index d6813db..197274f 100644
--- a/config.example.js
+++ b/config.js
@@ -6,24 +6,29 @@
 var path = require('path'),
     config;

+var cfenv = require('cfenv');
+var appEnv = cfenv.getAppEnv();
+
 config = {
     // ### Production
     // When running Ghost in the wild, use the production environment.
     // Configure your URL and mail settings here
     production: {
-        url: 'http://my-ghost-blog.com',
+        url: (appEnv.url.replace(/https/, 'http') || 'http://cf-ghost.10.244.0.34.xip.io'),
         mail: {},
         database: {
-            client: 'sqlite3',
-            connection: {
-                filename: path.join(__dirname, '/content/data/ghost.db')
+            client: 'mysql',
+            connection: appEnv.getServiceCreds(/^mysql.*/).uri,
+            pool: {
+                min: 2,
+                max: 4
             },
             debug: false
         },

         server: {
-            host: '127.0.0.1',
-            port: '2368'
+            host: (appEnv.bind || '0.0.0.0'),
+            port: (appEnv.port || process.env.PORT)
         }
     },

この変更は, Deploy Ghost blog to Cloud Foundrycfenv パッケージのドキュメント を参考に行いました。cfenvを使って,アプリのURLの設定,サービスの設定 (名前が mysql で始まるサービスがあれば自動的に設定されます),待ち受けるホスト及びポートの設定を行っています。

さらに,Deploy Ghost blog to Cloud Foundry を参考に Procfile を追加します。

$ echo 'web: NODE_ENV=production npm start' > Procfile
$ cat Procfile
web: NODE_ENV=production npm start

最後に,npm-shrinkwrap.json を削除します。削除の理由は,npm-shrinkwrap.json があると,そちらが優先されて package.json の変更が反映されないためです。本来は npm shrinkwrap して npm-shrinkwrap.json を作り直すのが筋ですが,その場合 node や npm がない環境ではそれらのインストールが必要になります。それを避けてデプロイ手順を単純にするために,本記事では削除を選択しました。削除しても Cloud Foundry 側で package.json に基づいて npm install が行われるので,バージョン間の差異で大きな影響が出なければ問題ありません。

$ git rm npm-shrinkwrap.json
rm 'npm-shrinkwrap.json'

以上で Cloud Foundry 向けの変更は終わりです。

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

アプリを停止状態でプッシュし,サービスを作成してバインドします。

3.1. アプリの作成

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

$ cf push cf-ghost --no-start

3.2. サービスの作成

Ghost では RDBMS として SQLite, MySQL, PostgreSQL の3つが使えますが, 公式ドキュメント には

Support for Postgres is currently second class compared to SQLite & MySQL - There is a build run against it, but very minimal manual testing.

とあるので,ここでは MySQL を使います。

$ cf create-service p-mysql 100mb mysql-ghost

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

$ cf bind-service cf-ghost mysql-ghost

4. アプリの起動

準備ができたので,アプリを起動します。 cf start または cf push で起動できます。

$ cf push cf-ghost
Updating app cf-ghost in org nota-ja / space 100 as nota-ja...
OK
..
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: cf-ghost.10.244.0.34.xip.io
last uploaded: Thu Sep 10 10:13:45 UTC 2015
stack: cflinuxfs2
buildpack: Node.js

     state     since                    cpu    memory           disk      details
#0   running   2015-09-10 07:15:31 PM   0.0%   183.9M of 256M   0 of 1G

起動しました。

5. 動作確認

アプリのURLにブラウザーからアクセスすると最初に表示される画面は↓です:

公式ドキュメント に基づいて /ghost/setup/ にアクセスすると,アカウント作成画面になります:

次の画面に進んでアカウント情報を入力します:

【Invite your team】の画面は,とりあえず画面下部にある【I’ll do it later, take me to my blog!】のリンクをクリックしてスキップします:

すると管理画面のトップに移動するので,右上の【NEW POST】をクリックして,

新規投稿画面に入り,記事を書き込んでみます:

Markdown で入力した記事(左側)が即座にプレビュー(右側)に反映されるので,非常に編集しやすく感じました。

記事を公開するには,右上の【SAVE DRAFT】の右の下向き矢印をクリックすると表示される【Publish Now】をクリックし,

さらにそのあと赤く表示される【PUBLISH NOW】を再度クリックします:

公開された記事を見るには,左下の【VIEW BLOG】をクリックします。

すると別タブが開いて,そこにブログのトップ画面が表示されるので,

今書いた記事へのリンクをクリックすると,

記事が表示されます:

使い勝手はほんとうに良い感じで,可能ならばこのブログも移行したいくらいです。

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