Yesodで作ったWebアプリをketerでデプロイする

stackが出現してYesod開発が飛躍的に安定するようになり、Webアプリ作成が現実的な選択肢になりました。実際、私も仕事で１つ、Webアプリをリリースした経験があります（ごく小規模ではありますが）。

Webアプリは作っただけでは当然使うことができず、サーバにデプロイする必要があります。

今回はHaskell製のデプロイツールであるketerをご紹介します。

# keterとは

[keter](https://github.com/snoyberg/keter)はYesodの作者（の一人？）である[Michael Snoyman](http://www.snoyman.com)氏が開発している、デプロイを支援するツールです。Haskellで作られています。
恐らくYesodで作られたWebアプリをデプロイすることを念頭に置かれているとは思いますが、それに縛られるものではありません。

ソースは[GitHubで公開](https://github.com/snoyberg/keter)されています。


# keterの機能

[本家のREADME.md](https://github.com/snoyberg/keter/blob/master/README.md)から抜粋すると・・・

* 80番ポートにバインドし、リバースプロキシとして動作する。所定のホスト名でのリクエストをWebアプリにブリッジする
* 必要があればSSLを提供する
* 自動的にWebアプリを起動し、監視し、プロセスが死んでいたら再度起動する
* グレイスフルな再デプロイのサポート。現在のプロセスは活かしたまま別のWebアプリプロセスを起動。正常に起動したらリバースプロキシの向き先を変えることで、Webアプリがダウンする時間帯を無くす
* ログファイルを管理


# keterによるデプロイサイクル

* Webアプリをビルド、実行可能ファイルを作る
* keterファイルを作成
  * keterファイルとは、 ``` config/keter.ym. ```、実行可能ファイル、静的リソースをtar形式にまとめてgzipしたファイルです。
  * Yesodの場合、``` yesod keter ``` というコマンドでketerファイルが作れます。stackを併用していることがほとんどだと思うので、実際に実行するコマンドは  
    ``` stack exec -- yesod keter ```  
    となります。
* keterファイルをscpコマンドなどで ``` /opt/keter/incoming ``` に送る  

以上の操作で、keterは再デプロイを実施してくれます。

# Yesodとketer

stackのテンプレートを使ってYesodプロジェクトを作ると、``` config/keter.yml ``` というファイルが作られます。
keterを使ってデプロイしてね、と言われているようなものですね。

ただ、環境によってはstackが生成するketer.ymlの中に書かれている実行ファイルのパスが、実際にビルドして作られる実行ファイルのパスと異なることがあります。
この場合、「zipファイルの解凍に失敗したよー」みたいなエラーが報告されてしまいます。実行ファイルのパスがおかしいとは、まず分からないエラーですので、ご注意を・・・

# keterの設定

keterの設定ファイルは、各Webアプリが持つ ``` keter.yml ``` に加え、サーバ側が持つ ``` keter-config.yaml ``` があります。

## keter.ymlの設定内容

Yesodで作ったプロジェクトであれば ``` config/ ``` ディレクトリの中にあります。
下記が設定例です。

```yaml
user-edited: true # trueにしておかないと編集が有効になりません
stanzas:
  - type: webapp
    exec: ../dist/bin/<実行ファイル> # keter.ymlから見た時の相対パスで記載しています
    args: []
    hosts:   # keterでブリッジするホスト名を列挙します
      - localhost  
      - example.com
    requires-secure: true # HTTPSのみ許可する場合にtrueにします. HTTPへのリクエストはHTTPSにリダイレクトされます
plugins:
  postgres: false  # PostgreSQLを使っていてもfalseにしないと動きません. 理由はよく分からない・・・
```

## keter-config.yamlの設定

デフォルトでは ``` /opt/keter/etc/ ```ディレクトリの中にあります。
重要なのは、SSLを使う際のキーファイルの設定と、環境変数の設定です。
下記が設定例です。

```
# Directory containing incoming folder, where to store logs, etc. Relative to
# the config file directory.
root: ..
listeners:
    # HTTP
    - host: "*4" # Listen on all IPv4 hosts
      port: 80 # Could be used to modify port
    # HTTPS
    - host: "*4"
      port: 443
      key: /etc/certs/private.key
      certificate: /etc/certs/app.cer
      chain-certificates:
          - /etc/certs/middle-ca.cer
env:
  PGHOST: host
  PGUSER: user
  PGPASS: pass
  PGDATABASE: dbname
```

# ログを確認する

ログファイルは ``` /opt/keter/log/ ``` ディレクトリの下に作られます。このディレクトリの下には、更に次の２種類のディレクトリが作られます。
* app-<アプリ名>：Webアプリが出力するログ
* keter：keter自体が出力するログ

最新のログは ``` current.log ``` というファイルに出力され、それ以前のファイルは日付と時刻から成るファイル名が付けられます。

```
-rw-r--r-- 1 root root  1292 Jul 20 02:48 20160719_175032.log
-rw-r--r-- 1 root root  1954 Jul 20 02:59 20160719_181326.log
-rw-r--r-- 1 root root  1616 Jul 20 09:40 20160727_022327.log
-rw-r--r-- 1 root root   368 Jul 27 11:23 20160727_023041.log
-rw-r--r-- 1 root root  5642 Jul 27 14:03 20160727_051719.log
-rw-r--r-- 1 root root   261 Jul 27 14:17 20160727_051739.log
-rw-r--r-- 1 root root   764 Jul 27 14:28 20160727_053155.log
-rw-r--r-- 1 root root  2592 Jul 27 16:34 20160727_080003.log
-rw-r--r-- 1 root root 18918 Jul 28 20:05 20160729_013832.log
-rw-r--r-- 1 root root   432 Jul 29 10:38 20160729_015712.log
-rw-r--r-- 1 root root   432 Jul 29 10:57 20160729_024933.log
-rw-r--r-- 1 root root 60455 Nov 16 12:32 20161116_050953.log
-rw-r--r-- 1 root root  4406 Dec 22 07:29 current.log
```