Deploy Django with Fabric

转自:http://gibuloto.com/blog/deploy-django-with-fabric/

Deploy Django with Fabric

Install

1
2
# 不要安裝在 virtualenv 裡面,不然每次 fab 都要進去 virtualenv 也是很麻煩 $ sudo pip install fabric 

Operations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在 remote 執行指令 run()  # 在 remote 執行需要 sudo 的指令 sudo()  # 在 localhost 執行指令 local()  # 在 remote 執行 change directory,通常會搭配 with 使用 cd()  # 在 localhost 執行 change directory lcd() 

cd()run()sudo() 只能用在 remote SSH 登入,本機的話要用 lcd()local()local('sudo some_command')

run() 默認的工作目錄就是 SSH 登入進去的家目錄,local(), 則是 fabfile.py 所在的目錄。

References:

Example

我把 deploy 環境分成三種,productionstagingdevelopment,分別對應到一個 fabfile。fabfile 實際上就是一個 .py 檔案,因為 Fabric 說穿了就是用 Python 來寫一串 bash 指令。

目錄結構如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
jojogo/ ├── app_product/ ├── fabfile.py ├── fabfiles/ │   ├── __init__.py │   ├── __init__.pyc │   ├── development.py │   ├── development.pyc │   ├── production.py │   ├── production.pyc │   ├── staging.py │   └── staging.pyc ├── jojogo/ ├── manage.py ├── requirements.txt ├── static/ └── templates/ 

in fabfile.py

1
2
3
4
5
from fabric.api import *  from fabfiles import production as pro from fabfiles import staging as sta from fabfiles import development as dev 

Usage:

1
2
3
4
$ fab -l $ fab pro.uwsgi $ fab sta.uwsgi $ fab dev.django 

in production.py (remote: Ubuntu)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import os import sys from datetime import datetime  from fabric.api import * from fabric.colors import *   def set_env():  env.FABFILE_NAME = 'production'  env.PROJECT_NAME = 'jojogo'  env.PROJECT_PATH_REMOTE = '/src/jojogo'  env.PROJECT_PATH_LOCAL = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))  env.SOURCE_VIRTUALENVWRAPPER = 'source /usr/local/bin/virtualenvwrapper.sh'  env.VIRTUALENV_NAME = env.PROJECT_NAME  env.VIRTUALENV_WORKON = '%s && workon %s' % (env.SOURCE_VIRTUALENVWRAPPER, env.VIRTUALENV_NAME)   env.host_string = 'REMOTE SERVER IP'  env.user = 'REMOTE SERVER SSH LOGIN USERNAME'  env.key_filename = 'ABSOLUTE PATH OF KEY PAIR FILE'    @task def checkout():  '''  Checkout project from Subversion  '''   set_env()   sudo('apt-get update')  sudo('apt-get install git mercurial subversion')  run('svn co --username USERNAME https://SVN_REPO_URL/')   @task def setup():  '''  Install all services & apps  '''   def install_postgresql_and_postgis():  sudo('apt-get install binutils gdal-bin libproj-dev postgresql-9.1-postgis postgresql-server-dev-9.1 python-psycopg2')   def install_nginx():  run('wget http://nginx.org/keys/nginx_signing.key')  sudo('apt-key add nginx_signing.key')  put('config/etc/apt/sources.list.d/nginx.list', '/etc/apt/sources.list.d/nginx.list', use_sudo=True)  sudo('apt-get update')  sudo('apt-get install nginx')   # 上傳配置文件  put('config/nginx/nginx.conf', '/etc/nginx.conf', use_sudo=True)  put('config/nginx/conf.d/guangdj.conf', '/etc/nginx/conf.d/guangdj.conf', use_sudo=True)   # 刪除範例的配置文件  sudo('rm /etc/nginx/conf.d/default.conf')  sudo('rm /etc/nginx/conf.d/example_ssl.conf')   sudo('service nginx restart')   def install_pip():  sudo('curl http://python-distribute.org/distribute_setup.py | python')  sudo('curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python')   def install_virtualenvwrapper():  sudo('pip install virtualenvwrapper')   def install_pil():  sudo('apt-get install apt-get build-dep python-imaging')   def install_uwsgi():  sudo('apt-get install build-essential python-dev libxml2-dev')   log_dir = '~/log/uwsgi'   run('mkdir -p %s' % log_dir)  run('touch %s/guangdj.log' % log_dir)   set_env()   install_postgresql_and_postgis()  install_nginx()  install_pip()  install_virtualenvwrapper()  install_pil()  install_uwsgi()   with prefix(env.SOURCE_VIRTUALENVWRAPPER):  '''  必須 source virtualenvwrapper.sh  否則會出現 /bin/sh: workon: command not found  '''   run('mkvirtualenv --no-site-packages %s' % env.VIRTUALENV_NAME)   with prefix(env.VIRTUALENV_WORKON):  with cd(env.PROJECT_PATH_REMOTE):  run('pip install -r requirements.txt')  run('yolk -l')  run('mkdir -p static_root')  run('python manage.py collectstatic --clear --noinput')   @task def syncdb():  '''  Update & migrate Django database  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  run('python manage.py syncdb')   @task def nginx():  '''  Reload nginx  '''   set_env()   sudo('service nginx restart')   @task def celery():  '''  Reload Celery  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  try:  sudo("ps auxww | grep 'celery' | awk '{print $2}' | xargs kill -9")  except:  print(green('雖然有錯誤訊息,但是 celeryd 還是有被 kill'))   sudo('python manage.py celeryd_detach')   @task def uwsgi():  '''  Reload uWSGI  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  run('svn up')  run('python manage.py collectstatic --clear --noinput')  run('killall -9 uwsgi')  run('uwsgi --ini config/uwsgi_conf.ini') 

in development.py (localhost: Mac)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import os import socket import sys from datetime import datetime  from fabric.api import * from fabric.colors import *   def set_env():  env.FABFILE_NAME = 'development'  env.PROJECT_NAME = 'jojogo'  env.PROJECT_PATH_LOCAL = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))  env.EXPORT_POSTGRESQL_BIN = 'export PATH=/usr/local/Cellar/postgresql/9.1.4/bin:$PATH'  env.SOURCE_VIRTUALENVWRAPPER = 'source /usr/local/bin/virtualenvwrapper.sh'  env.VIRTUALENV_WORKON = '%s && workon %s' % (env.SOURCE_VIRTUALENVWRAPPER, env.PROJECT_NAME)  env.CURRENT_IP = socket.getaddrinfo(socket.gethostname(), None)[0][4][0]   @task def setup():  '''  Install all services & apps  '''   def install_postgresql_and_postgis():  local('brew update')  local('brew install postgresql')  local('brew versions postgis')   def install_virtualenvwrapper():  local('sudo pip install --upgrade virtualenvwrapper')   def install_pil():  local('brew install jpeg lzlib')   set_env()   install_postgresql_and_postgis()  install_virtualenvwrapper()  install_pil()   with prefix(env.SOURCE_VIRTUALENVWRAPPER):  '''  必須 source virtualenvwrapper.sh  否則會出現 /bin/sh: workon: command not found  '''   local('mkvirtualenv --no-site-packages %s' % env.PROJECT_NAME)   with prefix(env.VIRTUALENV_WORKON):  local('pip install -r requirements.txt')  local('yolk -l')   @task def postgresql(run_in='backgound'):  '''  Run PostgreSQL  '''   set_env()   with prefix(env.EXPORT_POSTGRESQL_BIN):  if run_in == 'backgound':  local('pg_ctl -D ~/Developer/postgresql/%s -l /tmp/postgresql.%s.log start' % (env.PROJECT_NAME, env.PROJECT_NAME))  else:  local('pg_ctl -D ~/Developer/postgresql/%s start' % (env.PROJECT_NAME))   @task def celery(run_in='backgound'):  '''  Run Celery  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  if run_in == 'backgound':  try:  local('python manage.py celeryd_detach')  except:  print(green('celery 已經在執行了'))  else:  local('python manage.py celery worker --loglevel=info')   @task def django():  '''  Run Django  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  local('python manage.py runserver %s:8000' % env.CURRENT_IP)   @task def run_all():  '''  Run all services in backgound  '''   set_env()   with prefix(env.VIRTUALENV_WORKON):  postgresql()  celery()  django() 
相关文章
相关标签/搜索
每日一句
    每一个你不满意的现在,都有一个你没有努力的曾经。
公众号推荐
   一个历史类的公众号,欢迎关注
一两拨千金