ブログにも書いたのでfabricでデプロイ自動化
独学マンなので、書き方等ご指摘頂けますと幸いです。
背景
- python3.6で書かれたjobを、ec2上に構築
- shceduleでスケジューリング
- supervisorでdaemon化
までできていた。デプロイ作業を失敗しそうなので、自動化した時の備忘録。自動デプロイツールとしてfabricを利用。
ちなみに現状、fabric本家はpython3系をサポートいません。参考: FabricのPython3への対応についてそのためforkされたprojectから、インストールする必要があります。
pip3 install fabric3
ディレクトリ構成はこんな感じ。シンプル。
...
├── fabfile
│ ├── __init__.py # module読み込み
│ ├── deploy.py # 基本処理の記述
│ ├── envs.py # 基本設定を記述
...
基本処理の記述
fabfile/deploy.py
from fabric.api import run, abort, env, cd, local
from fabric.decorators import task
class LocalHandler(object):
"""localでのデプロイ周りの処理"""
def push(self):
"""localの変更をgithubへpushする
commitまではされている想定
"""
self.__check_has_commited()
self.__check_on_master()
self.__update_requirements()
local('git push origin master')
def __update_requirements(self):
"""requirements.txtをupdateするスクリプト"""
req_txt = 'requirements.txt'
local('pip freeze > {}'.format(req_txt))
res = local('git ls-files -m', capture=True)
if res == req_txt:
local('git add {}'.format(req_txt))
local('git commit -m "update requirements.txt"')
def __check_has_commited(self):
"""変更がちゃんとcommitされているかを確認"""
res = local('git ls-files -m', capture=True)
if res:
abort('there are some diff on git supervised files')
def __check_on_master(self):
"""master branchにいるか確認"""
branch = local('git rev-parse --abbrev-ref HEAD', capture=True)
if branch != 'master':
abort('you should call this on master branch')
class RemoteHandler(object):
def pull(self):
"""master branchに移動してソースコードの更新"""
with cd(env.app_path):
self.__check_no_change()
run('git checkout master')
run("git pull origin master")
def restart_daemon(self):
"""svcを使って、restartさせる"""
self.__install_required_package()
res = run('supervisorctl restart {}'.format(env.daemon_name))
if res.failed:
abort('REMOTE: fail restart daemon {}'.format(env.daemon_name))
return res
def __install_required_package(self):
req_txt = 'requirements.txt'
with cd(env.app_path):
run('pip3 install -r {}'.format(req_txt))
def __check_no_change(self):
"""変更がちゃんとcommitされているかを確認"""
res = run('git ls-files -m')
if res:
abort('REMOTE: there are some diff on git supervised files')
@task
def deploy():
LocalHandler().push()
rh = RemoteHandler()
rh.pull()
res = rh.restart_daemon()
if res.succeeded:
print("SUCCESS!! WELL DONE")
else:
print("TRY ONcE MORE :D")
基本設定を記述
fabfile/envs.py
from fabric.api import env
from fabric.decorators import task
@task
def production():
""" 本番 """
env.environment = "production"
env.app_path = '/path/to/project_root'
env.daemon_name = 'supervisor daemon_name'
env.user = 'ec2-user'
env.hosts = ['host_name']
env.key_filename = '~/.ssh/key.pem'
module読み込み
このままだと、プロジェクトルートからfabricのタスクを呼べない。init.pyにimport書いてモジュール化する。
fabfile/__init__.py
from fabfile.envs import production
from fabfile.deploy import deploy
実際に自動デプロイをする
下記のコマンドをローカルで叩く。
$ fab production deploy