PythonDjangoFabric3

DjangoプロジェクトをFabric3を使ってデプロイ

概要

CentOS7でDjangoを動かすシリーズシリーズの一つです。

Djangoアプリケーションを、CentOS7 Nginx+Gunicorn にデプロイする例です。

今回は既にサーバー上にDjangoプロジェクトがあり、このブログアプリケーションgit cloneで置いてあったとしましょう。

ブログアプリケーションが更新されれば、それをgit pull origin masterとして更新を取り込み、静的なファイルの更新があればpython manage.py collectstatic、最後にsystemctl restartコマンドでの再起動等をする必要があります。

つまり、以下の作業を自動でやりたいのです。

  1. サーバーへログイン
  2. cd narito.ninja
  3. git pull origin master # 最新のソースコード取り込み
  4. python3.7 manage.py migrate # migrationの適用。モデルに変更があった場合に必要
  5. sudo python3.7 manage.py collectstatic # staticファイルに変更があった場合に必要
  6. sudo systemctl restart narito.ninja # 再起動

という流れです。(narito.ninjaというサービス名です)

Fabric3のインストール

つい最近、Python3系(3.4以降)にもFabricが対応し、PyPIからインストールできるようになりました。しかしながらPython3対応したFabricは以前のAPIとは大幅に違います。

最新のFabricについてはまた今度書くとして、今回は旧FabricをPython3対応したフォーク版を利用することにします。

sudo pip install fabric3

チュートリアル(configファイルを使う場合)

MacやLinuxの方であれば、configファイルを使うと簡単です。

~/.ssh/config ファイルの作成

~/.ssh に、configという名前でファイルを作成します。 これは、sshでの接続をする際に利用されます。

元々は、こんな長ったらしいコマンドだったとして...

ssh -p 11111 -i 公開鍵 ユーザー名@サーバ0

configファイルに記述することで、以下のようにシンプルに書けるのです。

ssh blog

configファイルは、例えばこんな感じに書けます。ポート変更、公開鍵認証を使う例です。

Host blog
    HostName 153.126.216.172
    User narito
    Port 11111
    IdentitiesOnly yes
    IdentityFile ~/.ssh/blog/id_rsa

これで ssh blogでログインできるかを試しましょう。できれば大丈夫です。鍵のパスフレーズは、sshコマンド後に尋ねられます。

fabfile.py

場所はどこでもいいのですが、今回は~/.ssh/blog内にfabfile.pyを作ります。ファイル名は、必ずfabfile.pyにしてください。

中身をとりあえず以下のようにしましょう。

from fabric.api import *

env.hosts = ['blog']
env.use_ssh_config = True

def test():
    sudo("python3.7 -c 'import sys;print(sys.version)'")

env.hosts内のblogという記述ですが、これはconfigファイルに書いたHost名に対応します。use_ssh_configは、~/.ssh/config を読むための指定です。デフォルトはFalseなので、Trueにしないと読み込んでくれません。

env.hosts = ['blog']
env.use_ssh_config = True

sudo関数は、sudoコマンドで引数の中身を実行します。sudoしなくていいなら、run関数で良いです。

def test():
    sudo("python3.7 -c 'import sys;print(sys.version)'")

~/.ssh/blog に移動し(fabfile.pyと同じ階層ということです)、fab test とすることで実行されます。fab 関数名という書式ですね。 実行結果を見ると、よく動いているように見えます。

[blog] Executing task 'test'
[blog] sudo: python3.7 -c 'import sys;print(sys.version)'
[blog] Login password for 'you': 
[blog] out: sudo password:
[blog] out: 3.7.0 (default, Jan  4 2018, 16:40:53) 
[blog] out: [GCC 4.8.5 20150623 (Red Hat 4.8.5-16)]
[blog] out: 


Done.
Disconnecting from ホスト名.ポート... done.

チュートリアル(configファイルを使わない場合)

configファイルを使わない場合は、ユーザー名やポート、鍵のパスなどもfabfile.pyも記述する必要があります。

例えば次のようになるでしょう。

from fabric.api import *

env.hosts = ['153.126.216.172']
env.user = 'narito'
env.port = 11111
env.key_filename = 'id_rsa'

def test():
    sudo("python3.7 -c 'import sys;print(sys.version)'")

アップデートする

それでは、Djangoアプリケーションをアップデートする例を紹介します。

with cd(パス) とすることで、サーバー内のディレクトリを移動できます。

def update_blog():
    with cd('/home/narito/naritoblog'):
        sudo('git pull origin master')
        sudo('python3.7 manage.py migrate')
        sudo('python3.7 manage.py collectstatic')
    sudo("systemctl restart naritoblog")

collectstaticはyesかnoかを求められますが、これは実行側のコンソールに表示がされます。

[blog] sudo: python3.7 manage.py collectstatic
[blog] out: sudo password:
[blog] out: 
[blog] out: You have requested to collect static files at the destination
[blog] out: location as specified in your settings.
[blog] out: 
[blog] out: This will overwrite existing files!
[blog] out: Are you sure you want to do this?
[blog] out: 
[blog] out: Type 'yes' to continue, or 'no' to cancel: yes←これは私が入力した
[blog] out: 
[blog] out: 0 static files copied, 122 unmodified.
[blog] out: 

[blog] sudo: systemctl restart gunicorn
[blog] out: sudo password:
[blog] out: 

Done.
Disconnecting from ホスト名.ポート... done.

Djangoで、静的ファイルを別サーバーから配信するのように静的ファイルは別のサーバーで配信している場合は、update_blog内にcollectstaticを含めず、別にしておくと良いでしょう。