オープンソースのPaaSソフトウェア CloudFoundry の技術情報やイベント告知などを掲載します

2015-11-11

Moodle を Cloud Foundry で動かす

「Cloud Foundry 百日行」第97日目,今日は初の LMS (Learning Management System), Moodle です。Moodle は PHPで書かれており,OSS の LMS として歴史と人気を誇るアプリケーションのようです。

基本情報

  • 公式サイト
    https://moodle.org/

  • ソースコード
    git://git.moodle.org/moodle.git
    gitプロトコルでのアクセスしか提供されていないようです

  • その他参考情報

    • moodle.net
      Moodle 向けのコンテンツ/コースの共有サイトです
      デモもあります

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

  • 1) ソースコードの取得
  • 2) サービスの作成とバインド
  • 3) 各種設定
  • 4) アプリの起動
  • 5) 動作確認

1. ソースコードの取得

ソースコードを clone して,ディレクトリーを移動します。

今回,リポジトリーのコミット数が多く,処理が重くなるのを避けるために --depth=1 -b MOODLE_29_STABLE を指定していますが,もちろん指定せずに全コミットを取得しても問題ありません。その場合,ディレクトリー移動後に git checkout MOODLE_29_STABLE することを忘れないでください。

$ git clone --depth=1 -b MOODLE_29_STABLE git://git.moodle.org/moodle.git
..
$ cd moodle/

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

本アプリの対応 DBMS は, 公式ドキュメント によると PostgreSQL, MariaDB, MySQL, MSSQL, Oracle ということです。中でも PostgreSQL について,公式サイト上の Arguments in favour of PostgreSQL というページで,PostgreSQLを勧める理由が述べられているので,今回は PostgreSQL サービスを使うことにしました。

以下,サービスを作成し,アプリにバインドします。今回は manifest.yml をあらかじめ作っておき,バインドはアプリのアップロード時に同時に行うようにしました。

manifest.yml の作成

以下のような manifest.yml を作成します。

applications:
- name: <APPNAME>
  buildpack: php_buildpack
  services:
  - <SERVICE-INSTANCE-NAME>

buildpack の項について:このアプリのトップ・ディレクトリーには package.json ファイルがあるので,何も指定しないと nodejs-buildpack が適用されてしまいます。それを避けるために,php_buildpack を使うよう,陽に指定しています。

今回は, <APPNAME> として moodle を, <SERVICE-INSTANCE-NAME> として pg-moodle を用いることにしたので,manifest.yml の内容は以下の通りになりました。

$ cat manifest.yml
applications:
- name: moodle
  buildpack: php_buildpack
  services:
  - pg-moodle

サービスの作成

PostgreSQL サービスを作成します。サービス・インスタンス名は manifest.yml に合わせて pg-moodle とします。

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

アプリのアップロード及びサービスとのバインド

アプリを停止状態で Cloud Foundry 上に push します。manifest.yml があるのでアプリ名のその他の指定は不要です。

$ cf push --no-start
Using manifest file /home/nota-ja/repos/moodle/manifest.yml

Creating app moodle in org nota-ja / space 100 as nota-ja...
OK

Using route moodle.10.244.0.34.xip.io
Binding moodle.10.244.0.34.xip.io to moodle...
OK

Uploading moodle...
Uploading app files from: /home/nota-ja/repos/moodle
Uploading 81.6M, 18768 files
Done uploading
OK
Binding service pg-moodle to app moodle in org nota-ja / space 100 as nota-ja...
OK

manifest.yml にサービス・インスタンスの記述があるので,バインドまで自動的に行われます。

3. 各種設定

アプリの実行に必要な各種の設定を行います。主要な設定項目は以下の通りです。

  • moodledata ディレクトリーの設定
  • データベース接続設定
  • アプリのルート URL の設定
  • PHP 拡張モジュールの設定
  • (optional) アップロード・ファイル・サイズ上限の変更

これらは複数のファイルにまたがっていますが,以下基本的にファイルごとに設定を行っていきます。

moodledata ディレクトリーの作成

「ファイルごと」と書きましたが,その前に事前作業を一つ。

公式ドキュメントの記述 によると,moodle はアップロードされたファイルや一時ファイル,キャッシュの置き場としてデータ・ディレクトリーを必要とします。

今回は,アプリのディレクトリー直下に moodledata というディレクトリーを作り,それをデータ・ディレクトリーとして使うことにします。

$ mkdir -p moodledata

.bp-config/options.json ファイル

Cloud Foundry の php-buildpack では,各種カスタマイズを .bp-config/options.json ファイルで行うことができます。今回は以下の内容のファイルを作成します。

$ cat .bp-config/options.json
{
    "PHP_EXTENSIONS": ["iconv", "mbstring", "curl", "openssl", "tokenizer", "xmlrpc", "soap", "ctype", "zip", "gd", "simplexml", "spl", "pcre", "dom", "xml", "intl", "json", "pgsql", "zlib"],
    "LIBDIR": "moodledata"
}

公式ドキュメントの記述 を参考に,PHP の拡張モジュールを, PHP_EXTENSIONS に設定しました。

なお, zlib はドキュメントに記載がありませんでしたが,初回実行時のチェックで必須とされたので追加しました。また xmlrpcPHP_EXTENSIONS に含まれているにもかかわらず,(後で再度述べますが) なぜか php-buildpack がインストールしてくれませんでした。

また,moodledata ディレクトリーをWeb公開ディレクトリー外におくために, LIBDIR として指定しています。これは, 公式ドキュメント で「このディレクトリーは(セキュリティ上) Web からアクセスできないようにせよ」とされているためです。

config.php ファイル

config.php ファイルを書き換えて,

  • データベース接続設定
  • moodledata ディレクトリーの設定
  • アプリの URL の設定

を行います。

データベース接続設定は, cf env <APPNAME> で得られた VCAP_SERVICES の情報に基づいて行います。

$ cf env moodle
Getting env variables for app moodle in org nota-ja / space 100 as nota-ja...
OK

System-Provided:
{
 "VCAP_SERVICES": {
  "PostgreSQL": [
   {
    "credentials": {
     "uri": "postgres://f6bf5e71-8b6c-4f36-a876-6041abc96f5f:1grrq433t7k81buh8l4iqreqq2@192.168.15.91:5432/f6bf5e71-8b6c-4f36-a876-6041abc96f5f"
    },
    "label": "PostgreSQL",
    "name": "pg-moodle",
    "plan": "Basic PostgreSQL Plan",
    "tags": [
     "PostgreSQL",
     "Database storage"
    ]
   }
  ]
 }
}
..

また,アプリのルート URL としてアップロード時にアサインされた moodle.10.244.0.34.xip.io を,データ・ディレクトリーとして先ほど作成した moodledata ディレクトリーを指定します。最終的には,変更箇所は以下のようになります(デフォルト設定である config-dist.php と比較)。

$ git diff --no-index -- config-dist.php config.php
diff --git a/config-dist.php b/config.php
index df033d9..58154ad 100644
--- a/config-dist.php
+++ b/config.php
@@ -40,10 +40,10 @@ $CFG = new stdClass();

 $CFG->dbtype    = 'pgsql';      // 'pgsql', 'mariadb', 'mysqli', 'mssql', 'sqlsrv' or 'oci'
 $CFG->dblibrary = 'native';     // 'native' only at the moment
-$CFG->dbhost    = 'localhost';  // eg 'localhost' or 'db.isp.com' or IP
-$CFG->dbname    = 'moodle';     // database name, eg moodle
-$CFG->dbuser    = 'username';   // your database username
-$CFG->dbpass    = 'password';   // your database password
+$CFG->dbhost    = '192.168.15.91';  // eg 'localhost' or 'db.isp.com' or IP
+$CFG->dbname    = 'f6bf5e71-8b6c-4f36-a876-6041abc96f5f';   // database name, eg moodle
+$CFG->dbuser    = 'f6bf5e71-8b6c-4f36-a876-6041abc96f5f';   // your database username
+$CFG->dbpass    = '1grrq433t7k81buh8l4iqreqq2';   // your database password
 $CFG->prefix    = 'mdl_';       // prefix to use for all table names
 $CFG->dboptions = array(
     'dbpersist' => false,       // should persistent database connections be
@@ -56,7 +56,7 @@ $CFG->dboptions = array(
                                 //  (please note mysql is always using socket
                                 //  if dbhost is 'localhost' - if you need
                                 //  local port connection use '127.0.0.1')
-    'dbport'    => '',          // the TCP port number to use when connecting
+    'dbport'    => '5432',      // the TCP port number to use when connecting
                                 //  to the server. keep empty string for the
                                 //  default port
 );
@@ -73,7 +73,7 @@ $CFG->dboptions = array(
 // If you need both intranet and Internet access please read
 // http://docs.moodle.org/en/masquerading

-$CFG->wwwroot   = 'http://example.com/moodle';
+$CFG->wwwroot   = 'http://moodle.10.244.0.34.xip.io';


 //=========================================================================
@@ -89,7 +89,7 @@ $CFG->wwwroot   = 'http://example.com/moodle';
 //
 // - On Windows systems you might specify something like 'c:\moodledata'

-$CFG->dataroot  = '/home/example/moodledata';
+$CFG->dataroot  = '/home/vcap/app/moodledata';


 //=========================================================================

.bp-config/php/php.ini ファイル

これはある意味 optional なのですが,今回動作確認に使った「コース」のバックアップ・ファイルをアップロードするために,アップロード・ファイル・サイズの上限の緩和が必要だったので,それを php.ini ファイルで設定しました。

Cloud Foundry の php-buildpack では,デフォルトの php.ini 設定を変更したい場合,変更後のファイルを .bp-config/php/ に置くとその設定が反映されるようになっています。

今回は,

  • https://github.com/cloudfoundry/php-buildpack/blob/62b2fca31516f3b94be84355660835db8269252c/defaults/config/php/5.5.x/php.ini

の php.ini ファイルをベースに,

  • http://www.amulet.co.jp/shop-blog/?p=6507 (section 2.1.)
  • https://docs.moodle.org/29/en/Administration_FAQ#How_do_the_limits_on_uploaded_files_work.3F

などを参考にして,2箇所の変更を行いました。

ベースにしたファイルとの差分は以下の通りです。

$ git diff --no-index -- ../php.ini.62b2fca31516f3b94be84355660835db8269252c .bp-config/php/php.ini
diff --git a/../php.ini.62b2fca31516f3b94be84355660835db8269252c b/.bp-config/php/php.ini
index 94f1511..73327c1 100644
--- a/../php.ini.62b2fca31516f3b94be84355660835db8269252c
+++ b/.bp-config/php/php.ini
@@ -669,7 +669,7 @@ auto_globals_jit = On
 ; Its value may be 0 to disable the limit. It is ignored if POST data reading
 ; is disabled through enable_post_data_reading.
 ; http://php.net/post-max-size
-post_max_size = 8M
+post_max_size = 50M

 ; Automatically add files before PHP document.
 ; http://php.net/auto-prepend-file
@@ -801,7 +801,7 @@ upload_tmp_dir = "@{TMPDIR}"

 ; Maximum allowed size for uploaded files.
 ; http://php.net/upload-max-filesize
-upload_max_filesize = 2M
+upload_max_filesize = 50M

 ; Maximum number of files that can be uploaded via a single request
 max_file_uploads = 20

上限値を 50MB にしたのは,動作確認で利用した「コース」バックアップ・ファイル (Scratch.mbz) のサイズが 47MB だったためです。

4. アプリの起動

準備が整ったので,アプリを起動します。manifest.yml があるので,単に cf push するだけです。

$ cf push
$ cf push
Using manifest file /home/nota-ja/repos/moodle/manifest.yml
..
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: moodle.10.244.0.34.xip.io
last uploaded: Wed Nov 11 09:30:10 UTC 2015
stack: cflinuxfs2
buildpack: php_buildpack

     state     since                    cpu    memory        disk      details
#0   running   2015-11-11 06:31:47 PM   1.3%   90M of 256M   0 of 1G

起動しました。

5. 動作確認

アプリ起動後,ブラウザーでアプリのURLにアクセスすると,まず著作権に関する注意が表示されます:

【Continue】をクリックして先に進みます。

次に表示されるのはサーバー・チェックの画面です:

おそらく xmlrpc に関するものと opcache.enable に関するもの,2つの警告が出ていると思いますが,今回は気にしないことにして,スクロール・ダウンして【Continue】をクリックします。

※xmlrpc については,options.json の PHP_EXTENSIONS に記述しているにもかかわらず,インストールされていないようです。今回は時間がなく原因の分析は断念しました。

すると処理中で画面が止まったままになり,しばらくすると「Service Unavailable」というメッセージが表示されると思います:

しかし,これは恐らく処理が重いためにリクエストがタイムアウトしてしまったことが原因と考えられ,アプリが止まってしまったわけではありません。

数分後にリロードすると,次のような画面が現れるはずです:

必須項目 (【Username】【New password】【First name】【Surname】【Email address】) のみ設定し,後はデフォルトのままで,スクロール・ダウンして【Update profile】をクリックします:

そうすると “Front page settings” 画面になるので,適当に入力:

スクロール・ダウンして【Save changes】をクリックします。

これでようやく初期作業が終わり,adminとしてログイン済みの画面に遷移します:

左の【Administration】ペインで【Site administration】-【Users】-【Accounts】と navigate し,【Add a new user】をクリックして新規ユーザー作成画面に移動し,ユーザーを作成します:

必須項目 (【Username】【New password】【First name】【Surname】【Email address】) 以外はとりあえずデフォルトのままで,スクロール・ダウンして【Create user】をクリックします。

ユーザーが作成されました:

次に,学習の「コース」を作成します。コースは「大学の学習単位のような一連の講義のシーケンス」というのが私の理解です。今回は,CC-BY-SA ライセンスで配布されている作成済みのコース Basic Scratch (プログラミング言語 Scratch の学習コース) を試してみることにしました。

上記リンク先ページの下方にある【ダウンロード】をクリックし,Scratch.mbz ファイルをダウンロードします。

次に,Moodleに戻って,左の【Administration】ペインで【Site administration】-【Courses】と navigate し,【Restore course】をクリックしてコースのリストア画面に移動し,今ダウンロードしたコースをリストアします:

Scratch.mbz ファイルを【Files】下のエリアにドラッグ&ドロップし,アップロード終了後【Restore】ボタンをクリックします。

以下,7ステップにわたるリストアを開始します (長いので全ての画面は記載せず省略):

リストアが完了すると,この画面に遷移します:

このコースの受講者を設定するために,左の【Administration】ペインで【Course administration】-【Users】と navigate し,【Enrolled users】をクリックして,コースのユーザー管理画面に遷移し,右上の【Enrol users】をクリックしてダイアログを出し, “Noburou Taniguchi” を “Student” に,”admin” を “Manager” に enrol します:

ここで一旦ログアウトし,先ほど Student にアサインしたユーザーでログインします:

ログイン直後の画面はこんな感じになっているはずです:

【Basic Scratch】をクリックして,コースのトップ画面に遷移します:

左の【Navigation】ペインで【Dashboard】-【Current course】-【Scratch】-【Topic 1】と navigate し,【Lesson Plan】をクリックしてみます。

Lesson Plan 画面に遷移し,講義の概要が表示されます:

まだまだコースの続きはあるのですが,動作確認はこれで終わりとします。

この後【Video tutorial: Bad joke】なども試してみたのですが,動画の再生は途切れ途切れになっていたので,動画コンテンツを使う場合は,bosh-lite 環境より性能的にリッチな環境で動かしたほうが良さそうです。

また,今回ユーザー・アカウント等の永続性については確認したのですが,moodledata の永続性については時間がなくて十分調査できませんでした。基本的には, 公式ドキュメントの Backup に関する記述 を参考に,必要に応じて 第65日目の UNICALE の回 で使用した sshfs を活用すればいいのではないかと考えていますが,今後リクエストがあればその辺りも調査したいと思います。

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