Linux端(服务器)Ubuntu18.04.3:
安装:
ssh服务;
Nginx (web服务器);
Supervisor(python3)监控服务,管理进程;
Mysql;
jinjia2;
aiomysql;
aiohttp;
python3;
1 2 3
| $ sudo apt-get install nginx supervisor python3 mysql-server
$ sudo pip3 install jinja2 aiomysql aiohttp
|
初始化Mysql数据库:
进入mysql命令行,使用source + sql文件路径执行脚本创建表;
定义目录结构:
/
+- srv/
+- awesome/ <– Web App根目录
+- www/ <– 存放Python源码
| +- static/ <– 存放静态资源文件
+- log/ <– 存放log
使用虚拟环境:
安装:
1
| sudo apt install virtualenv
|
创建:
1
| virtualenv .env --python=python3
|
激活:
1
| source .env/bin/activate
|
安装supervisor
生成配置文件:
1
| echo_supervisord_conf > supervisord.conf
|
配置:
1 2
| awesome.conf(位于etc/supervisor/conf.d): command = /home/such/.env/bin/python3 /srv/awesome/www/app.py runserver
|
注意:supervisor不要添加多个command,如果其中一个command出错,而另一个正常,则整体还是可以运行的!!
即:command = 。。。
command =。。。
编写一个Supervisor的配置文件awesome.conf,存放到/etc/supervisor/conf.d/目录下:
1 2 3 4 5 6 7 8 9
| [program:awesome] command = /home/such/.env/bin/python3 /srv/awesome/www/app.py runserver directory = /srv/awesome/www user = such startsecs = 3 redirect_stderr = true stdout_logfile_maxbytes = 50MB stdout_logfile_backups = 10 stdout_logfile = /srv/awesome/log/app.log
|
配置文件通过[program:awesome]指定服务名为awesome,command指定启动app.py。
1 2 3 4 5
| 执行配置更新: $sudo supervisorctl reread $sudo supervisorctl update $sudo supervisorctl reload $sudo supervisorctl start awesome
|
nginx配置:
/etc/nginx/sites-available/下有个default文件,添加新配置awesome并不会生效。因此直接修改default文件进行配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| server { listen 80; root /srv/awesome/www; access_log /srv/awesome/log/access_log; error_log /srv/awesome/log/error_log;
location /favicon.ico { root /srv/awesome/www; }
location ~ ^\/static\/.*$ { root /srv/awesome/www; }
location / { proxy_pass http://127.0.0.1:9000; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
|
然后在/etc/nginx/sites-enabled/目录下创建软链接:
1 2 3 4 5
| $ pwd /etc/nginx/sites-enabled $ sudo ln -s /etc/nginx/sites-available/awesome 让Nginx重新加载配置文件: $ sudo /etc/init.d/nginx reload
|
获取ip:
未找到dos2unix报错:
1.安装tofrodos
sudo apt-get install tofrodos
实际上它安装了两个工具:todos(相当于unix2dos),和fromdos(相当于dos2unix)
2.做一些优化
由于习惯了unix2dos和dos2unix的命令,可以把上面安装的两个工具链接成unix2dos 和dos2unix,或者仅仅是起个别名,并放在启动脚本里。
步骤:
1 2
| ln -s /usr/bin/todos /usr/bin/unix2dos ln -s /usr/bin/fromdos /usr/bin/dos2unix
|
开发机:
Fabric(python2.7)自动化部署工具
若使用windows,则安装Fabric3(python3)
fabfile.py: 放在awesome-python-webapp,与www同级
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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| ''' Deployment toolkit in windows envirement. ''' import os, re, tarfile from datetime import datetime from fabric.api import * env.user = 'root' env.sudo_user = 'root'
env.host_string = '47.106.33.242' db_user = 'Blog' db_password = '1234567' _TAR_FILE = 'dist-awesome.tar.gz' _REMOTE_TMP_TAR = '/tmp/%s' % _TAR_FILE _REMOTE_BASE_DIR = '/srv/awesome' def _current_path(): return os.path.abspath('.') def _now(): return datetime.now().strftime('%y-%m-%d_%H.%M.%S') def build(): local('del dist\\%s' % _TAR_FILE) tar = tarfile.open("dist/%s" % _TAR_FILE,"w:gz") for root,_dir,files in os.walk("www/"): for f in files: if not (('.pyc' in f) or ('.pyo' in f)): fullpath = os.path.join(root,f) tar.add(fullpath) tar.close() def deploy(): newdir = 'www-%s' % _now() run('rm -rf %s' % _REMOTE_TMP_TAR) put('dist/%s' % _TAR_FILE, _REMOTE_TMP_TAR) with cd(_REMOTE_BASE_DIR): sudo('mkdir %s' % newdir) with cd('%s/%s' % (_REMOTE_BASE_DIR, newdir)): sudo('tar -xzvf %s' % _REMOTE_TMP_TAR) sudo('mv www/* .') sudo('rm -rf www') sudo('dos2unix app.py') sudo('chmod a+x app.py') with cd(_REMOTE_BASE_DIR): sudo('rm -rf www') sudo('ln -s %s www' % newdir) sudo('chown root:root www') sudo('chown -R root:root %s' % newdir) with settings(warn_only=True): sudo('supervisorctl stop awesome') sudo('supervisorctl start awesome') sudo('/etc/init.d/nginx reload') RE_FILES = re.compile('\r?\n') def rollback(): ''' rollback to previous version ''' with cd(_REMOTE_BASE_DIR): r = run('ls -p -1') files = [s[:-1] for s in RE_FILES.split(r) if s.startswith('www-') and s.endswith('/')] files.sort(reverse=True) r = run('ls -l www') ss = r.split(' -> ') if len(ss) != 2: print('ERROR: \'www\' is not a symbol link.') return current = ss[1] print('Found current symbol link points to: %s\n' % current) try: index = files.index(current) except ValueError as e: print('ERROR: symbol link is invalid.') return if len(files) == index + 1: print('ERROR: already the oldest version.') old = files[index + 1] print('==================================================') for f in files: if f == current: print(' Current ---> %s' % current) elif f == old: print(' Rollback to ---> %s' % old) else: print(' %s' % f) print('==================================================') print('') yn = input ('continue? y/N ') if yn != 'y' and yn != 'Y': print('Rollback cancelled.') return print('Start rollback...') sudo('rm -rf www') sudo('ln -s %s www' % old) sudo('chown www-data:www-data www') with settings(warn_only=True): sudo('supervisorctl stop awesome') sudo('supervisorctl start awesome') sudo('/etc/init.d/nginx reload') print('ROLLBACKED OK.') def backup(): ''' Dump entire database on server and backup to local. ''' dt = _now() f = 'backup-awesome-%s.sql' % dt with cd('/tmp'): run('mysqldump --user=%s --password=%s --skip-opt --add-drop-table --default-character-set=utf8 --quick awesome > %s' % (db_user, db_password, f)) run('tar -czvf %s.tar.gz %s' % (f, f)) get('%s.tar.gz' % f, '%s/backup/' % _current_path()) run('rm -rf %s' % f) run('rm -rf %s.tar.gz' % f) def restore2local(): ''' Restore db to local ''' backup_dir = os.path.join(_current_path(), 'backup') fs = os.listdir(backup_dir) files = [f for f in fs if f.startswith('backup-') and f.endswith('.sql.tar.gz')] files.sort(reverse = True) if len(files)==0: print('No backup files found.') return print('Found %s backup files:' % len(files)) print('==================================================') n = 0 for f in files: print('%s: %s' % (n, f)) n = n + 1 print('==================================================') print('') try: num = int(input ('Restore file: ')) except ValueError: print('Invalid file number.') return restore_file = files[num] yn = input('Restore file %s: %s? y/N ' % (num, restore_file)) if yn != 'y' and yn != 'Y': print('Restore cancelled.') return print('Start restore to local database...') p = input('Input mysql root password: ') sqls = [ 'drop database if exists awesome;', 'create database awesome;', 'alter database awesome default character set utf8 collate utf8_general_ci;' 'grant select, insert, update, delete on awesome.* to \'%s\'@\'localhost\' identified by \'%s\';' % (db_user, db_password) ] for sql in sqls: local(r'mysql -uroot -p%s -e "%s"' % (p, sql)) extract('backup\\%s' % restore_file, 'backup\\') with lcd('backup'): local(r'mysql -uroot -p%s --default-character-set=utf8 awesome < %s' % (p, restore_file[:-7])) local('del %s' % restore_file[:-7]) def extract(tar_path, target_path): ''' 解压tar.gz文件到目标目录 ''' try: tar = tarfile.open(tar_path, "r:gz") file_names = tar.getnames() for file_name in file_names: tar.extract(file_name, target_path) tar.close() except Exception as e: raise e if __name__ == '__main__': build() deploy() input()
|
直接运行fabfile.py即可连接linux服务器;
如果使用Linux:
提交修改:
实行应用: