Travis CIでCommon Lisp Webアプリを自動デプロイするメモ

TravisCIを用いてcavemans2で作成したCommon Lisp製Webアプリのテストを回し、サーバーに自動デプロイするまでのメモです。

自動テスト

まずは自動テストを試します。
4. Roswell as a Testing Environment (Travis CI and Coverall) · snmsts/roswell Wiki · GitHub
Roswellを用いることで簡単にテストすることができます。TravisCIでCommon Lispをネイティブにサポートしようとする動きもあるようですが、どちらにせよRoswellを用いるのが一番簡単なのではないでしょうか。

language: common-lisp
sudo: required

install:
  - curl -L https://raw.githubusercontent.com/snmsts/roswell/release/scripts/install-for-ci.sh | sh

script:
  - ros -s prove -e '(or (prove:run :quri-test) (uiop:quit -1))'

が基本で、quri-testをテストを含むプロジェクト名に書き換えればテストが走ります。
テストフレームワークにはfukamachi/prove · GitHubが使用されています。現状、テストコードは全く書いていません。テストに関する勉強も必要ですね。

このままではテストを回すたびにRoswellや処理系等のインストールが走るので時間がかかります。そこで、TravisCIは処理系等をキャッシュしたりできるようです。
Caching Dependencies and Directories - Travis CI
sudo: falseを指定し、適切にパスを設定すれば以前インストールされた処理系などでテストが走り、時間短縮になります。このやり方もRoswellのwikiに載っているので参照してみてください。

自動デプロイ

ここの記事を参考にしました。
neemzy - Deploy to your own server through SSH with Travis CI - A blog by Tom Panier, web developer

テストが通るのを確認したら自動デプロイの作業に入ります。基本的にはテストが通った後にSSHのパスワード認証でサーバーにログインし、デプロイ用のシェルスクリプトを実行するだけです。

環境変数の設定

デプロイ先のホストや、ユーザー名を環境変数として設定します。travisCIのWebサイトでも設定できるみたいですが、さすがにパスワードとかをおいておくのはアレですかね。そのために、それらの環境変数を暗号化します。これは、gemで入るtravis encryptコマンドを使用します。僕はWindows環境で用意するのが大変そうだったのでVPSに入れて実行しました。

yum install gem
yum install ruby-devel
gem install travis

で入ります。ruby-develなしではtravisのビルドが通りませんでした。
後はいくつかの環境変数を暗号化し、.travis.ymlに環境変数として貼り付けます。上記のサイトには書いていなかったのですがリポジトリのユーザー名とリポジトリ名を入れなければ暗号化できませんでした。ここら辺は詳しくわかりません。

travis encrypt -r soma-arc/travis-test DEPLOY_HOST=123.45.67.8
travis encrypt -r soma-arc/travis-test DEPLOY_PATH=~/common-lisp/project
travis encrypt -r soma-arc/travis-test DEPLOY_USER=hogehoge
travis encrypt -r soma-arc/travis-test DEPLOY_PASS=foobar

それぞれ実行すると長い文字列が得られます。それらを以下のように貼り付けると、環境変数として使用できます。

env:
    global:
        - secure: "長い文字列"
デプロイ処理の記入

あとはテスト終了後の処理を書きます。デプロイはmasterブランチにプッシュされたときだけ行って欲しいので$TRAVIS_BRANCHを見ています。

addons:
    apt:
        packages:
            - sshpass

after_success:
    - if [[ "$TRAVIS_BRANCH" == "master" ]]; then
        export SSHPASS=$DEPLOY_PASS;
       sshpass -e ssh -o "StrictHostKeyChecking"=no $DEPLOY_USER@$DEPLOY_HOST $DEPLOY_PATH/deploy.sh 1>/dev/null 2>/dev/null;
      fi

sshpassはあらかじめパスワード等を指定してログインできるコマンドだそうです。
デプロイ先のdeploy.shを実行することでデプロイします。-o "StrictHostKeyChecking"=noはホストを知らない場合に出るホスト鍵のチェックプロンプトを抑制するためにつけています。
これに関してはknown hostを加えればいらなくなるのかと思い、

addons:
    ssh_known_hosts: $DEPLOY_HOST
    apt:
        packages:
            - sshpass

を加えてみたのですが、どうにもログインに失敗しているみたいで駄目でした。
また、

1>/dev/null 2>/dev/null

をつけることでいらない入出力は切り捨てています。

デプロイ用のスクリプトの用意
#!/bin/sh
killall sbcl
cd ~/common-lisp/travis-test
git pull
nohup ~/.roswell/bin/clackup --server :woo --port 80 app.lisp 1>/dev/null 2>/dev/null &
chmod a+rwx deploy.sh

を使って実行属性をつけるのと、読み書きもできるようにしておきます。
Linuxコマンド集 - 【 chmod 】 ファイルやディレクトリのアクセス権を変更する:ITpro

~/common-lispに配置しましたが、アプリのリポジトリに配置してしまった方が良いかもしれませんね。
現在動いているサーバーはkillallで落としています。本来ならばフォークして云々とかがあるのかもしれませんが、そこら辺の知識が全くないので、とりあえずsbclを強制終了し、git pullで更新した後に再びclackupでアプリを起動しています。
killallはCentOS7の場合yum install psmiscで入れる必要があります。
また、clackupは~/.roswell/binにパスを通していたはずなのですが、通らなかったので絶対パスを通しています。
nohupはsshログアウトした後もプロセスを残すために使用します。
ログアウトしてもバックグラウンド ジョブを継続する方法

最後の&はプロセスをバックグラウンドで実行するためにつけます。
clackupでも入出力を切り捨てていますが、こうしないとサーバーからの応答を延々と待ち続けてしまい、ログアウトされません。当然TravisCIの実行もここで止まり続けてしまうので注意が必要です。

最終的な.travis.yml
language: common-lisp
sudo: false

install:
  - curl -L https://raw.githubusercontent.com/snmsts/roswell/release/scripts/install-for-ci.sh | sh

cache:
    directories:
        - $HOME/.roswell

script:
  - ros -s prove -e '(or (prove:run :travis-test-test) (uiop:quit -1))'

env:
    global:
        - secure: "......"
        - secure: "......"
        - secure: "......"
        - secure: "......"
        - PATH=~/.roswell/bin:$PATH
        - ROSWELL_INSTALL_DIR=$HOME/.roswell

addons:
    apt:
        packages:
            - sshpass

after_success:
    - if [[ "$TRAVIS_BRANCH" == "master" ]]; then
        export SSHPASS=$DEPLOY_PASS;
        sshpass -e ssh -o "StrictHostKeyChecking"=no $DEPLOY_USER@$DEPLOY_HOST $DEPLOY_PATH/deploy.sh 1>/dev/null 2>/dev/null;
      fi

これでmasterにpushがあった時にテストが走り、成功すればデプロイ用のコマンドが実行されます。

公開鍵認証

公開鍵認証する方法もあるみたいです。これもいつかそのうち…
Travis-CI でコミットして GitHub にプッシュする - 公開鍵認証を利用してみる | そんなこと覚えてない

おわり

Linuxコマンドに関する知識が乏しかったため、自動デプロイは結構つっかかりました。しかし、自動テスト自体は非常に簡単でした。僕はRoswell登場以前の状況は分かりませんが、Roswellのおかげですね。
現状あまりセキュアではありませんが、これで自動デプロイ環境が整いました。便利ですね、ありがとうございます。