まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:buildpack

以前からずっと悩んでいたのが、PHP と IBM DB2 の相性の悪さ(苦笑)でした。

知らない方が多いと思うので補足すると、PHP からデータベースにアクセスする場合には PDO(PHP Data Object) の拡張モジュールが必要になります。更に PDO に加えてデータベースの種類毎(例えば MySQL とか PostgreSQL とか)に接続するための拡張モジュールをシステムに導入しておく必要があります。

CentOS での例を書いておくと、例えば MySQL や PostgreSQL を使う場合はそれぞれ以下のようにして、これらのモジュールをインストールすることができます(PDO 拡張モジュールごとインストールできます):
(MySQL の場合)
# yum install php-mysql
(PostgreSQL の場合)
# yum install php-postgresql

さて IBM DB2 のケースです。普通に "yum install php-db2" などと入力しても「何それ?」みたいな扱いになります(苦笑)。
# yum install php-db2
  :
  :
パッケージ php-db2 は利用できません。
エラー: 何もしません

ではどこから拡張モジュールをインストールするのか・・・ と思って調べてみたのですが、かなりハードル高そうです:
http://php.net/manual/ja/ibm-db2.installation.php


↑リンク先を読んでいただくとわかりますが、自分でヘッダファイルやライブラリファイルを用意して、ビルドしろ、ということになっています。ということは DB2 のインストールモジュールが必要になるわけで・・・ 普通に PHP から使いたいだけなのですが、クラウドの DBaaS として使うにはかなりハードルが高めに設定されているように見えますね。。


一方で IBM Bluemix 環境であれば、このハードルはぐっと下がります。なにしろ「用意されたビルドパックを使うだけ」です。

前提として、IBM Bluemix 上に dashDB のインスタンスを1つ作成し、以下のようなテーブル(names)を定義しておきます:
2016111401
↑ID(int) と NAME(varchar(20)) だけのテーブル定義

2016111402
↑3つのレコードを入力済み


この dashDB インスタンスを、IBM Bluemix 上に作成した PHP ランタイムからバインドしてアクセスする、というアプリケーションを作ります:
2016111401



ビルドパックはこちらにあるものをそのまま利用します:
https://github.com/ibmdb/db2heroku-buildpack-php

ソースコード(index.php)はこんな感じで用意します(ホスト名やユーザー名、パスワードなどは Bluemix の接続情報を参照して取得します):
<html>
<head>
<title>DB2</title>
</head>
<body>
<table border="1">
<tr><th>ID</th><th>NAME</th></tr>
<?php
$host = "xxxxx.services.dal.bluemix.net"; # DB2(dashDB) のホスト名
$port = 50000; # ポート番号
$db = "BLUDB"; # データベース名
$username = "(username)"; # ユーザー名
$password = "(password)"; # パスワード

$conn_str = "DRIVER={IBM DB2 ODBC DRIVER};DATABASE=" . $db . ";HOSTNAME=" . $host . ";PORT=" . $port . ";PROTOCOL=TCPIP;UID=" . $username . ";PWD=" . $password . ";";
$conn = db2_connect( $conn_str, $username, $password );
if( $conn ){
  $sql = "SELECT * FROM \"names\"";
  $stmt = db2_prepare( $conn, $sql );
  $result = db2_execute( $stmt );
  if( $result ){
    while( $row = db2_fetch_array( $stmt )){
?>
<tr><td><?php print_r($row[0]); ?></td><td><?php print_r($row[1]); ?></td></tr>
<?php
    }
  }else{
    $error = db2_stmt_error( $stmt );
    $errormsg = db2_stmt_errormsg( $stmt );
?>
<tr><td><?php print_r($error); ?></td><td><?php print_r($errormsg); ?></td></tr>
<?php } } ?> </table> </body> </html>

PHP 内で dashDB のインスタンスに接続して SQL を実行し、全レコードを取り出して表示する、という内容になっています。PHP としては非常にシンプルですが、"db2_" で始まる拡張関数が数か所使われており、DB2 用のコードになっていることがわかると思います。

こいつを cf コマンドでプッシュします。その際に -b オプションで上記のビルドパックを指定します:
# cf push (アプリ名) -b https://github.com/ibmdb/db2heroku-buildpack-php

この方法で作成したアプリケーションにアクセスすると、PHP の IBM DB2 拡張が読み込まれて実行され、期待通りの結果が表示されます:
2016111403


PHPer の皆さん、IBM Bluemix と dashDB であれば面倒な手続きなく PHP からも使えます。是非アプリを作ってみましょう!


なお、PHP の IBM DB2 拡張機能については公式ドキュメントが存在しているので、関数リファレンスも含めて詳しくはこちらを参照ください:
http://php.net/manual/ja/book.ibm-db2.php


前回までの続きです:
Bluemix のビルドパックを作る(1/3)
Bluemix のビルドパックを作る(2/3)


このシリーズは3回に分けて IBM Bluemix 用のビルドパックをゼロから作成する手順を説明するもので、今回はその3回目です:
(1) ビルドパックを作る上で知っておくべきこと
(2) ビルドパックを作るための準備作業    
(3) ビルドパックを作成して、実際に動作確認
  ←今回はここ

前回までに、ビルドパックを作成する上で知っておくべき仕組みや制限事項についてをまとめ、実際に PHP + Apache HTTP Server 環境のビルドパックを作る上で必要になるモジュール(ビルドパック実行時の権限では作れないモジュール)の作成を終えました。

では今回はこれらのモジュールを使って、実際のビルドパックを作成し、実際に IBM Bluemix 上のランタイムとして起動し、動作を確認するまでを紹介します。

ではビルドパック作成環境にログインします。前回の作業は Ubuntu 環境下で行う必要がありましたが、ここからは Ubuntu である必要はありません(Windows や Mac, Ubuntu 以外の Linux でも構いません)。が、以下はそのまま Ubuntu を使って作業する前提(つまり前回の作業で出来上がったモジュールもローカル内にあるという前提)で紹介をします。 というわけで改めて Ubuntu 環境に SSH 等でログインします:
2015100901


作業用のディレクトリを用意します。今回は /tmp/buildpack というディレクトリを新たに作成して、この中で作業することにします:
$ mkdir -p /tmp/buildpack
$ cd /tmp/buildpack


上記作業内容の (1) で紹介したように、ビルドパックは3つのスクリプトを用意することで作成します。この3つのスクリプトを /tmp/buildpack/bin 以下に作成します。3つのスクリプトは Ruby などのスクリプト言語を利用することもできますが、今回は(個人的な慣れもあって)シェルを使って記述することにします:
$ mkdir bin
$ cd bin
$ touch detect
$ touch compile
$ touch release
$ chmod 775 detect
$ chmod 775 compile
$ chmod 775 release
$ cd ..


また、このスクリプト(具体的には compile スクリプト)の中では、前回の作業 (2) で作成した PHP と Apache HTTP Server 2つのモジュールを使うことになります。これらのモジュールをあらかじめビルドパックのディレクトリ内にコピー(または移動)しておきます。前回の作業 (2) と異なる環境で今回の作業をしている場合は、前回の環境からこれらのモジュールを SFTP などで転送して取得してください:
$ mkdir -p download/httpd/2.4
$ mv /app/apache-2.4.16.tar.gz download/httpd/2.4
$ mkdir -p download/php/5.6
$ mv /app/php-5.6.14.tar.gz download/php/5.6


また、PHP および Apache HTTP Server の動作設定とも言える php.ini と httpd.conf ファイルもあらかじめ用意しておきます:
$ mkdir config
$ vi config/httpd.conf
   :

$ vi config/php.ini
   :


これらのファイルの内容は皆さんが作成していただいても構わないのですが、今回は日本語を使う前提で、比較的緩めの条件設定で環境構築をするような内容にしています。具体的な内容は以下のリンク先と同じものです。これらと同じ内容で2つのファイルを用意/編集しておくと、かなりゆるゆるで、本番環境としてはともかく、開発テスト用に便利な PHP ランタイムができます:
https://github.com/dotnsf/php-apache-buildpack/tree/master/config

なお、注意事項として Apache HTTP Server が動作するポートは固定値ではなく、必ず環境変数 PORT から取得して起動させる必要があることに注意してください。したがって httpd.conf 内の Listen ディレクティブの指定は必ず以下の様な指定になっている必要があります:
  :
  :
Listen ${PORT}
  :
  :


あらためて、ここから3つのスクリプトを作っていきます。まずは detect スクリプトを作ります。このスクリプトはビルドパックの適用に適した環境が整っているかどうかを判断して、ふさわしいと判断した場合だけ次にすすめるようにする、というためのスクリプトです。 今回は PHP + Apache HTTP Server のビルドパックなので、選択肢としては「無条件にふさわしいと判断する」というのもアリですが、勉強目的もあるので多少強引に何らかの条件を付けるようにしてみましょう。

というわけで、今回の detect スクリプトでは
 ドキュメントルートに index.php ファイルが存在していたらビルドパック適用条件を満たしている、
 index.php が存在していない場合はビルドパックを適用しない

という条件判断をさせることにします。

また、これも (1) の中で説明していますが、detect スクリプトは実行ディレクトリ("cf push" を実行した時のカレントディレクトリ)を引数に受け取ります。この引数を使って、detect スクリプトを以下のような内容で編集します:

※ bin/detect の中身
#!/usr/bin/env bash
################################################################################
# bin/detect <build-dir>                                                       #
################################################################################

# ---------------------------------------------------------------------------- #
# ドキュメントルートに index.php が存在している時だけ有効                      #
# ---------------------------------------------------------------------------- #
if [ -f $1/index.php ]; then
  echo "My PHP Env"
  exit 0
else
  exit 1
fi


これで detect スクリプトによって、カレントディレクトリに index.php ファイルが存在している時だけ実行結果として 0 を返して compile スクリプト続行、存在してない場合は 1 が返されて処理が止まる、という実装にしました。


続いて compile スクリプトを作ります。ここがいわば「ビルドパックの本体」といえる部分で、実際のサーバー環境を、このスクリプト1つだけで構築していくことになるものです。

この compile スクリプトの中では前回の作業 (2) で作成したモジュールを使います:

※ bin/compile の中身
#!/usr/bin/env bash
################################################################################
# bin/compile <build-dir> <cache-dir>                                          #
################################################################################

# ---------------------------------------------------------------------------- #
# 変数を設定                                                                   #
# ---------------------------------------------------------------------------- #
BIN_DIR=$(dirname $0)
BUILDPACK_DIR=`cd $(dirname $0); cd ..; pwd`
BUILD_DIR=$1
CACHE_DIR=$2

APACHE_VERSION="2.4.16"
APACHE_PATH="apache"
PHP_VERSION="5.6.14"
PHP_PATH="php"

# ---------------------------------------------------------------------------- #
# ドキュメントルート(/app/www/)の設定                                          #
# ---------------------------------------------------------------------------- #
cd $BUILD_DIR

mkdir -p $CACHE_DIR/www
mv * $CACHE_DIR/www
mv $CACHE_DIR/www .

# ---------------------------------------------------------------------------- #
# コンパイル済みの Apache HTTP Server を展開                                   #
# ---------------------------------------------------------------------------- #
APACHE_DIR="${BUILDPACK_DIR}/download/httpd/2.4/apache-$APACHE_VERSION.tar.gz"
echo "-----> Bundling Apache version $APACHE_VERSION"
tar -xvf $APACHE_DIR

# ---------------------------------------------------------------------------- #
# コンパイル済みの PHP を展開                                                  #
# ---------------------------------------------------------------------------- #
PHP_DIR="${BUILDPACK_DIR}/download/php/5.6/php-$PHP_VERSION.tar.gz"
echo "-----> Bundling PHP version $PHP_VERSION"
tar -xvf $PHP_DIR 

# ---------------------------------------------------------------------------- #
# httpd.conf と php.ini を上書き                                               #
# ---------------------------------------------------------------------------- #
ls -al $BUILDPACK_DIR
cp $BUILDPACK_DIR/config/httpd.conf $APACHE_PATH/conf
cp $BUILDPACK_DIR/config/php.ini $PHP_PATH

# ---------------------------------------------------------------------------- #
# php のパスを設定                                                             #
# ---------------------------------------------------------------------------- #
mkdir -p bin
ln -s /app/php/bin/php bin/php

# ---------------------------------------------------------------------------- #
# Apache HTTP Server 起動スクリプト(boot.sh)作成                               #
# ---------------------------------------------------------------------------- #
cat >> boot.sh <<EOF
for var in \`env|cut -f1 -d=\`; do
echo "PassEnv \$var" >> /app/apache/conf/httpd.conf; done touch /app/apache/logs/error_log touch /app/apache/logs/access_log tail -F /app/apache/logs/error_log & tail -F /app/apache/logs/access_log & export LD_LIBRARY_PATH=/app/php/ext export PHP_INI_SCAN_DIR=/app/www echo "Launching apache" exec /app/apache/bin/httpd -DNO_DETACH EOF chmod +x boot.sh # ---------------------------------------------------------------------------- # # キャッシュディレクトリをクリア # # ---------------------------------------------------------------------------- # rm -rf $CACHE_DIR

最後に release スクリプトを作ります:

※ bin/release の中身
#!/usr/bin/env bash
################################################################################
# bin/release <build-dir>                                                      #
################################################################################

# ---------------------------------------------------------------------------- #
# boot.sh を実行するような YAML ファイルを生成                                 #
# ---------------------------------------------------------------------------- #
cat << EOF
config_vars:
    MYENV: myphp
default_process_types:
    web: sh boot.sh
EOF

これでビルドパックは完成です。作業した /tmp/buildpack 以下のディレクトリ/ファイル構成は以下の様な状態になっているはずです:
/tmp/buildpack/
 |- bin/
 |   |- compile
 |   |- detect
 |   |- release
 |- config/
 |   |- httpd.conf
 |   |- php.ini
 |- download/
     |- httpd/
     |   |- 2.4/
     |   |    |- apache-2.4.16.tar.gz
     |- php/
         |- 5.6/
              |- php-5.6.14.tar.gz


ではこのビルドパックを実際に使ってみます。が、そのためにはこのビルドパックをインターネット上の Git リポジトリに公開する必要があります。普段お使いの環境にオリジナルの Git 環境があればそこを使ってもいいのですが、今回は GitHub 上に公開しましょう。GitHub のアカウントを取得できていない場合は取得して、ログインまでを済ませておきます:
2015101002


画面右上の "+" 印をクリックし、"New repository" を選択して、新しいソースリポジトリを作成します:
2015101003


リポジトリの名前、説明(オプション)、そして Public リポジトリか Private リポジトリかを選択します。名前は何でもいいのですが、わかりやすいように "php-apache-buildpack" としました。説明はオプションで加えます。GitHub の有料アカウントであれば Private リポジトリを選ぶこともできますが、せっかくなので(というか、この後の話がややこしくならないように)Public を選択して公開しちゃいましょう。最後に "Create Repository" ボタンをクリックします:
2015101004


するとこんな感じの画面になり、ソースリポジトリが新規に追加できました。この時の URL (https://github.com/(ユーザー名)/(リポジトリ名)) を後で使うのでメモしておいてください。今はまだ中身が空ですが、ここに先程作ったビルドパックを転送します:
2015101005


改めて作業環境に戻ります。ここからは git クライアントによる作業になるため、git が必要です。git コマンド未導入の場合はコマンドラインで以下のように入力して git をインストールしておきます:
$ sudo apt-get install git

そしてビルドパックを作成したディレクトリ(/tmp/buildpack)に移動して、以下のコマンドを入力し、上記で作成した GitHub 上のリポジトリに転送します:
$ cd /tmp/buildpack
$ git init
$ git add .
$ git commit -m 'first commit'
$ git remote add origin https://github.com/****(先程メモしたリポジトリのURL)****.git
$ git push -u origin master
(GitHub 上のユーザー名を入力)
(GitHub のパスワードを入力)

転送完了後、改めてリポジトリの URL にブラウザでアクセス(まだ開いていればリロード)すると、作成したビルドパックが転送され、中身が入ったリポジトリになっているはずです。これでビルドパックの公開もできました:
2015101006



では最後にこのビルドパックを使って、実際に Bluemix 上にランタイムを1つ構築してみます。cf ツールをインストールしたマシンのあるディレクトリに index.php という名前で、以下のような phpinfo(); を実行するだけの内容のファイルを作成します:
<?php phpinfo(); ?>

また Bluemix 上にランタイムを1つ作ります。言語は(この後に変えるので)何を指定しても構いません。この例では dotnsf-php-20151010 という名前で作成していますが、実際には一意になるような名前を指定してください:
2015101001


そしてこの index.php ファイルが存在しているディレクトリから cf ツールで Bluemix 上にログインし、作成したビルドパックを指定してこのランタイムにプッシュします:
> cf login -a https://api.ng.bluemix.net/
(Bluemix のユーザー名を指定)
(パスワードを指定)

> cf push dotnsf-php-20151010 -b https://github.com/dotnsf/php-apache-buildpack.git
   :
   :
#0   running   2015-10-10 08:37:34 PM   0.2%   61.9M of 128M   163.5M of 1G


プッシュが成功したら、実際にこのランタイムの URL にアクセスして、phpinfo() の結果が表示されることを確認します。ちゃんと PHP のアプリケーションサーバーとして動いていることが確認できました:
2015101002


この中身をよく見ると、ビルドパックを作成した際に指定した内容で稼働していることが確認できます。というわけで元の(Bluemix の)PHP ランタイム環境ではなく、カスタマイズして作成した PHP ランタイムが動いていることも分かります:
2015101003


長い連載になりましたが、これで Bluemix のビルドパックを作って、公開して、実際に使ってみる所までが確認できました。PHP 以外のビルドパックを作る場合も、(権限の問題がないものであれば)この応用で作れると思います。是非色々チャレンジしていただけると嬉しいです。

前回の続きです:
Bluemix のビルドパックを作る(1/3)


このシリーズは3回に分けて IBM Bluemix 用のビルドパックをゼロから作成する手順を説明するもので、今回はその2回目です:
(1) ビルドパックを作る上で知っておくべきこと
(2) ビルドパックを作るための準備作業      ←今回はここ
(3) ビルドパックを作成して、実際に動作確認


前回は、ビルドパックを作成する上で知っておくべき仕組みや制限事項についてをまとめました。おおまかには次のような仕組み/条件でビルドパックを作ります:
- ビルドパック自体は detect, compile, release の3つのスクリプトからなる。
- これら3つのスクリプトは一般ユーザー権限で実行される。su や sudo は使えない。
- 素の Ubuntu Linux に対して、これら3つのスクリプトが実行された後に必要な環境が整っているようにする。

今回と次回の2回に分けて、実際にビルドパックをゼロから作成します。正確には実際にビルドパックそのものを作る手順は次回紹介しますが、今回はそのための準備作業を紹介します。具体的には実際にビルドパックを作るスクリプトは一般ユーザー権限でしか実行できないため、ビルドなどの root 権限が必要な作業はあらかじめ(Ubuntu 環境下で)済ませておく必要があります。そのための作業の説明を今回のブログエントリの中で紹介します。

また、今回作成するビルドパックの内容は「比較的緩めな日本語対応 PHP アプリケーションサーバーを作る」こととします。具体的には以下の様なスペック PHP アプリケーションサーバーのビルドパックを作ります:
・ PHP 5.6.14
・ Apache HTTPD 2.4.16
・ PHP の MySQL モジュールと Postgresql モジュールを追加
・ PHP の設定は日本語 UTF-8 ベースで、エラー発生時のエラー内容を出力、ファイルアップロードは1ファイル10MB まで許可、・・・などなど php.ini を緩めに設定
・ Apache HTTPD も .htaccess での設定上書きを許可するなど、ゆるゆるにする

簡単にいえば「php.ini と httpd.conf を緩めに設定するような環境で PHP のビルドパックを作成する」ということです。


では本エントリでの作業に入ります。まずは 64bit の Ubuntu Linux 14.02 環境を用意します。デスクトップ環境は必須ではありません。SSH 等でログインしてターミナル上での操作ができれば大丈夫です:
2015100900



この Ubuntu の中に PHP と Apache HTTPD 環境を構築していきます。といっても、ただインストールすればいいというわけではありません。インストールだけなら "sudo apt-get install php5 apache2 libapache2-mod-php5" とかを実行すればいいのですが、これは sudo が使える前提での話です。上記のようにビルドパック作成時の権限は sudo の使えないユーザー権限なので、この apt-get による簡単なインストール方法は使えないのです。

ではどうするか? その答は (2) まず Ubuntu 内で必要なモジュールを、ソースからのコンパイルなど全て手作業で作り、 (3) 作ったモジュールを tar などでまとめておき、ビルドパック作成時は一般ユーザーが展開してコピーすればよい、という状態にしておく 必要があるのでした。要は root 権限が必要な部分((2))と、不要な部分((3))に作業を分断し、ビルドパック作成時は root がなくてもできる作業だけを行います。そしてそのような作業だけで済むように、root 権限が必要な作業は(ビルドパック作成作業の前)あらかじめ済ませてまとめておく、という作業を行うようにします。これが全体作業でいうところの (2) と (3) を分けた理由でもあります。

では、あらためて今回行う作業の内容をまとめておきます:
(2-1) Apache HTTPD 2.4.16 をソースからビルドして /app/apache/ 以下にインストール
(2-2) PHP 5.6.14 をソースからビルドして /app/php/ 以下にインストール
(2-3) 出来上がった Apache HTTPD 2.4.16 および PHP 5.6.14 のモジュールを /app/apache/ および /app/php/ 以下からそれぞれ取り出してアーカイブ

こうして出来上がったアーカイブファイルは、Ubuntu 環境の /app/apache/ & /app/php/ 以下であれば動くように作られているので、同じ状態を作り出すようにビルドパックを構成(次回)すればよい、ということになります。今回はそのための準備を行います。


では具体的な作業手順の説明です。まずは Ubuntu 14.02(64bit) のターミナル環境に SSH 等でログインします:
2015100901


まずは作業ディレクトリを作成します。今回は /tmp/build を作業ディレクトリとします:
$ mkdir -p /tmp/build
$ cd /tmp/build


(2-1) Apache HTTPD 2.4.16 のソースコード一式をダウンロードし、作業ディレクトリ内に展開します:
$ curl -L http://www.carfab.com/apachesoftware/httpd/httpd-2.4.16.tar.gz | tar xzf -


Apache HTTP のビルドに必要な apr-1.5.2 および apr-util-1.5.2 をそれぞれダウンロードし、作業ディレクトリ内の srclib/ ディレクトリ内に展開します:
$ cd httpd-2.4.16/srclib
$ curl http://www.us.apache.org/dist/apr/apr-1.5.2.tar.gz | tar xzf -
$ mv apr-1.5.2 apr
$ curl http://www.us.apache.org/dist/apr/apr-util-1.5.4.tar.gz | tar xzf -
$ mv apr-util-1.5.4 apr-util
$ cd ..


Apache HTTP のビルドに必要なライブラリ(libpcre3, libpcre3-dev)を apt-get で入手します:
$ sudo apt-get install libpcre3 libpcre3-dev


Apache HTTP ビルド後のインストールディレクトリを /app/apache/ とする前提でビルド(configure して make して make install )します:
$ ./configure --prefix=/app/apache --with-included-apr --enable-rewrite
$ sudo mkdir -p /app/apache
$ sudo chmod -R 777 /app/
$ make && make install


(2-2) PHP インストール先のディレクトリ(/app/php/)を用意します:
$ sudo mkdir -p /app/php


(2-1) の作業でビルドしたモジュールの一部を PHP のライブラリとしてコピーします:
$ sudo mkdir -p /app/php/ext
$ sudo chmod -R 777 /app/php
$ cp /app/apache/lib/libapr-1.so.0 /app/php/ext
$ cp /app/apache/lib/libaprutil-1.so.0 /app/php/ext
$ cd /app/php/ext
$ ln -s libapr-1.so.0 libapr-1.so
$ ln -s libaprutil-1.so.0 libaprutil-1.so


PHP のビルドに必要なライブラリ(libxml2, libxml2-dev, libssl-dev, ...)を apt-get で入手します。平行して PostgreSQL をサポートするために必要な環境を整えます:
$ cd /tmp/build
$ sudo echo “deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main”> /etc/apt/sources.list.d/pgdg.lis
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc |  sudo apt-key add -OK
$ sudo apt-get update
$ sudo apt-get install libxml2 libxml2-dev libssl-dev libvpx-dev libjpeg-dev libpng12-dev libXpm-dev libbz2-dev libmcrypt-dev libcurl4-openssl-dev libfreetype6-dev postgresql-server-dev-9.4


PHP のソースコード一式をダウンロードし、作業ディレクトリ内に展開します:
$ curl -L http://php.net/get/php-5.6.14.tar.gz/from/us1.php.net/mirror | tar xzf -


PHP ビルド後のインストールディレクトリを /app/php/ とする前提でビルド(configure して make して make install )します:
$ cd php-5.6.14
$ ./configure --prefix=/app/php --with-apxs2=/app/apache/bin/apxs --with-mysqli --with-pdo-mysql --with-pgsql --with-pdo-pgsql --with-iconv --with-gd --with-curl=/usr/lib --with-config-file-path=/app/php --enable-soap=shared --enable-libxml --enable-simplexml --enable-session --with-xmlrpc --with-openssl --enable-mbstring --with-bz2 --with-zlib --with-gd --with-freetype-dir=/usr/lib --with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --with-xpm-dir=/usr/lib
$ make && make install


MySQL クライアントライブラリを apt-get で入手して、PHP / Apache のライブラリとしてコピーします:
$ sudo apt-get install libmysqlclient-dev
$ cd /app/php/ext
$ cp /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.0.0 ./
$ ln libmysqlclient.so.18.0.0 libmysqlclient.so.18
$ ln libmysqlclient.so.18.0.0 libmysqlclient.so
$ cp /tmp/build/php-5.6.14/.libs/libphp5.so /app/apache/modules/


(2-3) コンパイルが終了した Apache HTTP のモジュールをアーカイブします:
$ cd /app
$ echo '2.4.16' > apache/VERSION
$ tar -zcvf apache-2.4.16.tar.gz apache


コンパイルが終了した PHP のモジュールをアーカイブします:
$ echo '5.6.14' > php/VERSION
$ tar -zcvf php-5.6.14.tar.gz php




これで (2) の作業が完了して、ビルドパックを作るための作業準備が整いました。今回の作業で出来上がった apache-2.4.16.tar.gz および php-5.6.14.tar.gz はどちらも /app/ 以下にコピーすれば正しく動く前提で作られているので、これらのモジュールを使い、この条件でビルドパックを作ってあげればよい、ということになります。

次回はいよいよ実際にビルドパックを作って、動作確認までしてみます。ゴールは目前!


(注 2015/Oct/16 追記)
続きはこちら

 

IBM Bluemix 上のランタイムとして使えるビルドパックを自分でゼロから作る、ということに挑戦してみます。今回は作業は行わず、その仕組とか概要の説明になります。 とはいえ、ここで知っておかないと作ったり、うまく動かなかった時の調整に困ったり、一度作ったものを自分なりに再カスタマイズする際に手間取ったりすると思ったので、一応知っておくべきことをまとめておきます。

予定としてはこんな感じで、3回に分けて説明するつもりです:
(1) ビルドパックを作る上で知っておくべきこと ←今回はここ
(2) ビルドパックを作るための準備作業
(3) ビルドパックを作成して、実際に動作確認



ビルドパックとは?

ビルドパックとは Bluemix 上で動作するランタイムの実行基盤を準備するための仕組みです。元々は Heroku 用に開発されたカスタマイズのための仕組みで、CloudFoundry では V2 から採用されています。Bluemix のランタイムメニューからも、GitHub 上に公開されたコミュニティー提供のものも、多くのビルドパックが公開され、利用可能です。


ビルドパックの環境

Bluemix 上に作成されるランタイムには Ubuntu Linux が使われます。2015年10月時点では Bluemix のスタックは Ubuntu 14.04.2 trusty (x86_64) です。

ビルドパックで用意した環境は、最終的にこの Ubuntu サーバー上にコピーされて動くことになります。つまり、Ubuntu 14.04.2 上で動くようなものを作る必要があるわけです。

ビルドパックを構築する作業の中で C のコンパイルなどの作業を行いますが、それらは Ubuntu 14.04.2(x86_64) 上で動くようなモジュールにする必要があります。作ったビルドパックの動作確認時の手間などを考えると、ビルドパックのカスタマイズは事実上 Ubuntu 環境上で作業する必要があります。

というわけで、次回以降で実際に行う作業は全て Ubuntu 14.04 環境上で行います。この環境を用意しておく必要があります:
2015101001



ビルドパックの構成

ビルドパックは detect, compile, release という3つのスクリプトから構成され、これらが順次実行されます:
スクリプト説明
bin/detectアプリケーションの構造をチェックして、導入可能な構成か(次に進んでいいか)をチェックする
bin/compileランタイム環境を作成する
bin/release起動時のコマンド等を作成する


注意点として、これら3つのスクリプトは vcap という一般ユーザー権限で実行される、ということです(セキュリティ上の制約)。なお、この vcap ユーザーには sudo 権限はありません。つまり、これら3つのスクリプトは一般ユーザー権限で実行できるようなものにする必要があります。管理者権限が必要な作業はこれらのスクリプト実行の前に全て終わらせておく必要があり、これらのスクリプトの中では一般ユーザー権限で実行できるものしか使えません。

具体的には、例えば apt-get install などはこれらのスクリプトの中では使えません。ただし wget であれば使える、などです。

したがって例えば Apache HTTP Server をビルドパックに含めるには、bin/compile スクリプトの中で Apache HTTP Server を apt-get install して・・・というわけにはいきません。予め Apache HTTP Server のソースファイル一式を入手しておいて、コンパイルして Ubuntu 上で動くバイナリを作っておいて、それを bin/compile スクリプトで実行ディレクトリにコピーして使う、という流れになります。共有ライブラリなどを使う場合にも同様の注意が必要です。

また、各スクリプトで生成したり、配置したりするファイルは "/app/" 以下に配置するようなスクリプトにする必要があります。"/tmp" や "/var/tmp" 以下には永続性保証がありません。

これら3つのスクリプト、それぞれについて詳細を以下で紹介します。


detect スクリプト

このスクリプトはビルドパックの実行条件を判断するためのスクリプトです。プッシュしようとしている内容が、このビルドパックで用意された環境向けの内容としてふさわしいかどうかを判断し、(例えば PHP ランタイムなのに PHP ファイルが含まれていないなど)ふさわしくないと判断したら compile には進みません。

このスクリプトには引数が1つ渡されて実行されます。渡される引数はプッシュされるアプリケーションのパスです。

そしてその引数を参照して(しなくてもいいけど) detect スクリプトが実行され、ビルドパック実行にふさわしいと判断したら標準出力に 0 を出力します。ビルドパック実行にふさわしくないと判断したら標準出力に 1 を出力します。detect スクリプトは 0 か 1 を標準出力に出力して完了します。


compile スクリプト

実際のビルドパック環境を構築するスクリプトです。実際に動くアプリケーションサーバー環境を作り上げるスクリプトとなり、いわば、ここがビルドパックの肝になる部分です。

このスクリプトは detect スクリプトの出力結果が 0 だった場合のみ実行されます。

このスクリプトには引数が2つ渡されて実行されます。第一引数はプッシュされるアプリケーションのパス、第二引数はキャッシュディレクトリのパスです。detect スクリプトとは違い、標準出力への内容がルール化されているわけではありません。

繰り返しになりますが、このスクリプトは一般ユーザー権限で実行されます。なので、例えば HTTP サーバーを導入する場合、apt-get install では導入できません。あらかじめソースファイルからバイナリを生成しておいて、compile スクリプト内では生成済みバイナリを実行パスにコピーする、といった形で環境構築を行う必要があります。


release スクリプト

アプリケーション起動時の動作を指定するスクリプトです。

このスクリプトには引数が1つ渡されて実行されます。渡される引数はプッシュされるアプリケーションのパスです。

このスクリプトの実行結果は、以下の様な YAML フォーマットで出力する必要があります。最後の commandLine の部分にアプリケーションサーバーを稼働させるためのスクリプトを記述します:
config_vars:
 name: value
default_process_types:
 web: commandLine



今回の内容はここまでです。ビルドパックを作る上での制限というか、制約というか・・・は理解できたでしょうか? 普通に Bluemix を使う上では知らなくてもいいことが多かったと思いますが、ビルドパックという低レベルなカスタマイズを行おうとすると、こういった知識も必要になってきます。ちょっと面倒に感じるところがあるかもしれませんが、勝手に変なスクリプトが実行されることのないよう、現状のような(比較的制限の大きな)仕様になっているのでした。

次回は、実際にビルドパックをゼロから作るための、その準備段階を紹介する予定です。 実際の作業はプログラミングというよりも「どれだけ Linux に詳しいか」を痛感するような内容になります(苦笑)。がんばって着いてきてくださいっ!

(2015/Oct/15 追記)
続きはこちら


IBM Bluemix 環境に cf ツールでアプリケーションを push した後にログが表示されますが・・・
2015021601



このログを詳しく調べて、「コマンド実行後に何をやっているのか?」の説明をします。

なお、今回の説明内容の前提として、2015/02/16 時点の、Liberty Java アプリケーション(war ファイル)1インスタンスをデプロイしています。このアプリケーションでは MySQL をデータストアとしてバインドしています。その条件下でのログを紹介します:

まずログ全文はこんな感じです:
$ cf push dotnsf-20150212 -p GeoImgWeb.war
Updating app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
OK

Uploading dotnsf-20150212...
Uploading app files from: GeoImgWeb.war
Uploading 2.4M, 258 files
Done uploading
OK

Stopping app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
OK

Starting app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
-----> Downloaded app buildpack cache (224K)
-----> Retrieving IBM 1.7.1_sr2fp1ifx-20141220 JRE (ibm-java-jre-7.1-2.1-pxa6470
_27sr2fp1ifx-20141220_02-sfj.tgz) ... (0.0s)
         Expanding JRE to .java ... (0.8s)
-----> Retrieving App Management Agent 2015.02.04_102631 (com.ibm.ws.cloudoe.app
-mgmt-proxy-agent.zip) ... (0.0s)
         Expanding App Management to .app-management (0.0s)
-----> Downloading and installing client jar(s) from https://download.run.pivota
l.io/mariadb-jdbc/mariadb-jdbc-1.1.8.jar (0.0s)
-----> Auto-configuration is creating config for service instance 'mysql-x3' of
type 'mysql'
-----> Liberty buildpack is done creating the droplet



-----> Uploading droplet (116M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started


OK

App dotnsf-20150212 was started using this command `.liberty/initial_startup.rb`


Showing health and status for app dotnsf-20150212 in org (ユーザー名) / spa
ce dev as (ユーザー名)...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: dotnsf-20150212.eu-gb.mybluemix.net
package uploaded: Mon Feb 16 01:15:44 +0000 2015

     state     since                    cpu    memory           disk
#0   running   2015-02-16 10:16:46 AM   2.8%   149.4M of 512M   182M of 1G

$ 

まず、push コマンド:
$ cf push dotnsf-20150212 -p GeoImgWeb.war

で「dotnsf-20150212 という Bluemix アプリケーションに、GeoImgWeb.war という Java アプリケーションをデプロイする」という命令をしています。この GeoImgWeb.war はカレントディレクトリに存在しているものとします。

その直後のログは以下のようになっています:
Updating app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
OK

Uploading dotnsf-20150212...
Uploading app files from: GeoImgWeb.war
Uploading 2.4M, 258 files
Done uploading
OK

Stopping app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
OK

デプロイ先のアプリケーションを更新するため、GeoImgWeb.war をアップロードして、そして dotnsf-20150212 を一旦停止しています。ここまではまあ一般的というか、Bluemix / Cloud Foundry 環境に特化した内容ではないのでわかりやすいと思います。

この後から少し特殊な処理になります:
Starting app dotnsf-20150212 in org (ユーザー名) / space dev as (ユーザー名)...
-----> Downloaded app buildpack cache (224K)
-----> Retrieving IBM 1.7.1_sr2fp1ifx-20141220 JRE (ibm-java-jre-7.1-2.1-pxa6470
_27sr2fp1ifx-20141220_02-sfj.tgz) ... (0.0s)
         Expanding JRE to .java ... (0.8s)
-----> Retrieving App Management Agent 2015.02.04_102631 (com.ibm.ws.cloudoe.app
-mgmt-proxy-agent.zip) ... (0.0s)
         Expanding App Management to .app-management (0.0s)
-----> Downloading and installing client jar(s) from https://download.run.pivota
l.io/mariadb-jdbc/mariadb-jdbc-1.1.8.jar (0.0s)
-----> Auto-configuration is creating config for service instance 'mysql-x3' of
type 'mysql'
-----> Liberty buildpack is done creating the droplet

dotnsf-20150212 を起動する処理の中身です。Java アプリケーションとしての基板となる Liberty Buildpack をダウンロードし、IBM Java 1.7.1 & App Management Agent & MariaDB JDBC 1.1.8 を続けてビルド(実際にはダウンロード)しています。これらはビルドパック内で定義されている処理です。これで droplet と呼ばれる実行可能なアプリケーションが作成されます。

その後、作成した droplet をアップロードしてアプリケーションインスタンスを起動します。ここでちょっと時間がかかります:
-----> Uploading droplet (116M)

0 of 1 instances running, 1 starting
1 of 1 instances running

App started

OK

実はここまでの段階でアプリケーションとしては利用可能になっています。最後にアプリケーションやサーバーリソースの状態を確認するためのコマンドが実行され、その結果が表示されています:
App dotnsf-20150212 was started using this command `.liberty/initial_startup.rb`


Showing health and status for app dotnsf-20150212 in org (ユーザー名) / spa
ce dev as (ユーザー名)...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: dotnsf-20150212.eu-gb.mybluemix.net
package uploaded: Mon Feb 16 01:15:44 +0000 2015

     state     since                    cpu    memory           disk
#0   running   2015-02-16 10:16:46 AM   2.8%   149.4M of 512M   182M of 1G

CPU やメモリ、ディスクリソースの状態と合わせてアプリケーションの状態が最後に表示されています。この例ではサーバーは1インスタンスなので1行だけで表示されていますが、複数インスタンスで起動している場合は複数行の結果になります。



 

このページのトップヘ