お仕事でデータ分析をすることになって1ヶ月ほど。
データ分析をする上でPythonはとても便利です。
モジュールも整備されており、ドキュメントも充実しています(ほとんど英語だけど)。
データサイエンスを利用したサーバーを組むなら、同じくPythonでやってしまった方が今までの方法を利用できて便利です。
今回は、PythonでWEBサーバーを組んだのでそれをデプロイする方法を整備しました。
Fabricとは?
FabricはSSH越しでリモートPCのコマンドを実行できるモジュールです。
Railsで良く使われるデプロイツールのCapistranoに対して、PythonではFabricな感じみたいですね。
Capistranoよりもお手軽な感じらしく、タスクなどを覚える必要がないということでした。
逆にいうと必要最低限のものしか準備されておらず、デプロイツールというよりは公式ドキュメントが言うとおり、
本当にリモートPCのコマンドを叩くためのライブラリのようですね。
「PythonでCapistranoを使うのもなんかあれだし、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はインタプリタまで隔離環境としてコピーするのが異なりますね。
感想
データ分析のために整備していたコードをそのままサーバー化しちゃえ、というのは自然な発想な気がします。