Fabric2を使ったデプロイ

お仕事でデータ分析をすることになって1ヶ月ほど。

データ分析をする上でPythonはとても便利です。

モジュールも整備されており、ドキュメントも充実しています(ほとんど英語だけど)。

データサイエンスを利用したサーバーを組むなら、同じくPythonでやってしまった方が今までの方法を利用できて便利です。

今回は、PythonでWEBサーバーを組んだのでそれをデプロイする方法を整備しました。

Fabricとは?

FabricはSSH越しでリモートPCのコマンドを実行できるモジュールです。

Railsで良く使われるデプロイツールのCapistranoに対して、PythonではFabricな感じみたいですね。

Capistranoよりもお手軽な感じらしく、タスクなどを覚える必要がないということでした。

逆にいうと必要最低限のものしか準備されておらず、デプロイツールというよりは公式ドキュメントが言うとおり、

本当にリモートPCのコマンドを叩くためのライブラリのようですね。

PythonCapistranoを使うのもなんかあれだし、Ansibleを使うのも面倒臭いし手軽にリモートPCの操作できないかな?」って時に便利そうです。

Fabricのバージョン?

注意すべきなのは、Fabric 1.x、Fabric2、Fabric3とあって全部別物レベルに違うことです。

結論として使うべきはFabric2です。

Fabric 1.xはFabric2の旧バージョンであり、公式ドキュメントではFabric2のインストールを強く推奨しています。互換性もありません。

Fabric3はFabric 1.xがPython3に対応していない頃にforkされたもので現在はあまり活発に開発されていないようです。

現行の開発が進んでいる、Fabric2ではきちんとPython3にも対応しており、色々と改善されているようです。

Googleで検索して出てくる日本語化された公式ドキュメントはFabric 1.xのドキュメントなので注意が必要です。

コード

やることはfabfile.pyを置いてfabコマンドを叩くだけです。

fabfile.py

from fabric import task


PROJECT_ROOT = '/path/to/project'
REPO_URL = 'Gitレポジトリ のURL'
PIDFILE = 'run/gunicorn.pid' 


@task
def init(c):
    c.run(f'[ ! -e {PROJECT_ROOT} ] && git clone {REPO_URL} {PROJECT_ROOT}', hide=True)


@task
def deploy(c, version):
    c.run(f'cd {d.project_root} && git fetch origin && git checkout {version}', hide=True)
    c.run(f'cd {d.project_root} && PYENV_VERSION={PYENV_VERSION} pyenv exec pipenv clean', hide=True)
    c.run(f'cd {d.project_root} && PYENV_VERSION={PYENV_VERSION} pyenv exec pipenv install --dev --skip-lock', hide=True)
    c.run(f'cd {d.project_root} && kill -HUP $(cat {PIDFILE})', hide=True)

あとは、リモートPCにSSHできる環境から、

$ pipenv run fab -i 秘密鍵 -H ユーザー名@IPアドレス init deploy --version=Gitのタグ

とするだけです。

色々試行錯誤の末に、シンプルにgit checkoutして、Gunicornをリロードするというものになりました。

今回はPyenvとPipenv両方を使っているのそれを考慮したものになりました。

どっちも使っていなければ、上記のコードから関連する記述を消せば動くと思います。

またWSGIサーバーとしてGunicornを使っているので、更新分をリロードするためにHUPシグナルを送っています。

Gitの理由

最初はCapistranoと同じくreleasesディレクトリを作って、currentへシンボリックリンクを貼るみたいなのをやっていたのですが、

Pipenvとの共存を考えると難しそうだなとなって辞めました。

RubyのBundlerとPythonのPipenvは似ているようで、Pipenvはインタプリタまで隔離環境としてコピーするのが異なりますね。

感想

データ分析のために整備していたコードをそのままサーバー化しちゃえ、というのは自然な発想な気がします。

2018年、Javaを抜いてPythonが人気の理由もなんとなくわかった気がします。