OpenShift で Crystal を動かす方法

# はじめに

この記事では、無料から使える [OpenShift](https://www.openshift.com/) 上に Crystal で作られたアプリケーションを動作させる方法を説明しています。

## OpenShift とは ?
OpenShift は Red Hat が運営する PaaS (Platform as a Service) です。

Ruby, Python, Node など複数の言語に対応しています。Crytal は正式には対応していませんが、DIY コンテナを使うことにより動作させることができます。

3 つのアプリケーションまで無料で利用でき、試しに利用してみたり、小さなサービスを運用するのに最適です。データベースサーバー (MySQL 等) も無料範囲内で利用できます。

# OpenShift 上で Crystal を動かす
OpenShift は、**何もしない状態では Crystal を動かすことができません**。
OpenShift 上で Crystal を動かすには、以下の様な手順を踏む必要があります。

1. libevent の最新版をインストール
2. git の最新版をインストール
3. Crystal の最新版をインストール

※ 以下は OpenShift 上の DIY コンテナに SSH して行います。
※ コンテナを構築するまでの方法は、[こちらの記事](http://qiita.com/pine613/items/8555df6952e09532bf5a) を参照してください。

## libevent の最新版をインストール
Crystal の動作には libevent が必要ですが、OpenShift 上 (RHEL 6.6) の libevent は古いです。OpenShift は PaaS であり root 権限は無いため、ユーザー空間に自前でビルドしたものを入れます。

```
$ cd $OPENSHIFT_DATA_DIR
$ wget https://sourceforge.net/projects/levent/files/libevent/libevent-2.0/libevent-2.0.22-stable.tar.gz
$ tar xvfz libevent-2.0.22-stable.tar.gz
$ cd libevent-2.0.22-stable
$ ./configure --prefix=$OPENSHIFT_DATA_DIR/libevent
$ make
$ make install
```

## git の最新版をインストール
Crystal は依存モジュールを解決するために git を使いますが、OpenShift 上の git は古く、依存モジュール解決時 (`$ crystal deps`) にエラーになるため、git を自分で入れて上げる必要があります。

```
$ cd $OPENSHIFT_DATA_DIR
$ mkdir -p build
$ cd build
$ wget https://github.com/git/git/archive/v2.5.1.zip
$ unzip v2.5.1.zip
$ cd git-2.5.1
$ autoconf
$ ./configure --prefix=$OPENSHIFT_DATA_DIR/git --with-expat
$ make all
$ make install
```

## Crystal の最新版をインストール
GitHub 上の [Releases](https://github.com/manastech/crystal/releases) より最新版のバイナリを探して、インストールします。

```
$ cd $OPENSHIFT_DATA_DIR
$ wget https://github.com/manastech/crystal/releases/download/0.8.0/crystal-0.8.0-1-linux-x86_64.tar.gz
$ tar xvfz crystal-0.8.0-1-linux-x86_64.tar.gz
$ mv crystal-0.8.0-1 crystal
```

## ヘルパースクリプトを用意
上記で自前でインストールしたライブラリ・コマンド経由で Crystal を実行するためのヘルパースクリプトを作成し、それから Crystal を呼び出すようにします。

### `$ crystal build`
自前で入れた libevent を使うようにコンパイラへ指示する必要があります。`$ crystal-build src/foo.cr` のように呼び出します。

```bash:crystal-build
#!/bin/bash

set -e

CRYSTAL_BIN=$OPENSHIFT_DATA_DIR/crystal/bin/crystal
LIBEVENT_PATH=$OPENSHIFT_DATA_DIR/libevent/lib

exec "$CRYSTAL_BIN" build --link-flags "-L$LIBEVENT_PATH" $*
```

### `$ crystal deps`
`$ crystal deps` コマンドは、Crystal v0.8.0 以降 `shards` コマンドを呼び出すエイリアスとなりました。そのため、`shards` を呼び出せるように PATH を通すスクリプトを用意します。`shards` はこの後ビルドします。

```bash:crystal-deps
#!/bin/bash

set -e

CRYSTAL_BIN=$OPENSHIFT_DATA_DIR/crystal/bin/crystal
SHARDS_PATH=$OPENSHIFT_DATA_DIR/crystal/bin
LIBEVENT_PATH=$OPENSHIFT_DATA_DIR/libevent/lib
GIT_PATH=$OPENSHIFT_DATA_DIR/git/bin

PATH=$GIT_PATH:$SHARDS_PATH:$PATH

LD_LIBRARY_PATH="$LIBEVENT_PATH" exec "$CRYSTAL_BIN" deps
```

### ビルドしたプログラムの実行
上記ヘルパースクリプトでビルドしたファイルを実行するときに使うヘルパースクリプトです。`$ crystal-env ./bin/foobar` のように使います。

```bash:crystal-env
#!/bin/bash

set -e

LIBEVENT_PATH=$OPENSHIFT_DATA_DIR/libevent/lib

LD_LIBRARY_PATH="$LIBEVENT_PATH" exec $*
```

## `shards` のビルド
Crystal のパッケージマネージャーである `shards` を上記で作成したヘルパースクリプト `crystal-build` を使ってビルドします。

※ `crystal-build` が `$OPENSHIFT_DATA_DIR` に作成されているとします

```
$ cd $OPENSHIFT_DATA_DIR
$ wget https://github.com/ysbaddaden/shards/archive/v0.4.0.tar.gz
$ tar xvfz v0.4.0.tar.gz
$ cd shards-0.4.0
$ ../crystal-build src/shards.cr -o bin/shards --release
$ cp bin/shards ../crystal/bin/
```

# まとめ
OpenShift 上で Crystal を動かすのは大変です。しかし、Heroku の無料版のと違い、一日半分スリープするといったことがないので、無料で一日中動かしたいアプリケーションを動作させるときに有効です。OpenShift で楽しい Crystal ライフを!!