git hook 和fabric的使用,实现自动化部署.
Git hook实现项目部署自动化
接下来设置git hook,实现我们本地push到repo后git自动部署到VPS.
其实就是自己搭建一个私人的github服务~
安装git,建立bare仓库,bare意思是文件夹里没有源代码,只是用于版本控制:
$ sudo apt-get install -y git
$ sudo mkdir /home/git && cd /home/git
$ sudo mkdir flask_project.git && cd flask_project.git
$ sudo git init --bare
小贴士:在shell prompt显示你当前位于哪个分支:
加入如下到/etc/profile(所有用户) ~/.bashrc(当前用户) :
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "
在/home/git/flask_project.git下:
$ sudo vim hooks/post-receive
写入:
#!/bin/sh
GIT_WORK_TREE=/home/www/flask_project git checkout -f
sudo supervisorctl restart flask_project
如果想要推送后自动更新supervisor就把supervisor的控制命令也加入钩子,但是需要用root身份ssh登录到git,这个在本地项目根目录下.git/config设置。
现在每次push都会自动执行一次上面的脚本.推送到vps
$ sudo chmod +x hooks/post-receive
现在在本地开发机的flask应用根目录,vps相当于github,设置这个ssh路径是容易出错的地方:
$ git init
$ git remote add production root@<your_ip_or_domain>:/home/git/flask_project.git
或者对于修改过vps ssh端口号的情况:
如在第一篇中设置过ssh别名为vps($vi ~/.ssh/config, 登录vps的用户名为user)
$ git remote add bandwagon user@vps:home/leroy/git/flask_project.git
如果想修改这个地址直接如下,改里面的url:
$ vim .git/config
修改,删除再添加,如果只是改名就rename:
$ git remote -v
$ git remote rm production
这时候,config 里面关键的一行是这样的:
url = ssh://root@bw:/home/leroy/git/flask_project.git
这就设置完了。
这里可以同时加入github的ssh连接,一次push到两个地方。
以后对代码库进行修改后,
$ git add -A
$ git commit -am "initial"
$ git push production master
或者
$ git push bandwagon master
就部署完毕了,这时候重启一下应用就上线
$ sudo supervisorctl restart flask_project
补充: 1.如果没有在virtualenv里安装需要的包,推送后部署会错误,需要自己手动去安装一下。
2.这样的设置无法pull只能push。
Fabric自动化部署脚本
把这三篇文章的命令放在一个脚本里面,以后就只用改改脚本即可自动化部署.
使用方法:
视频演示
把包含所有这三篇文章修改过的文件的整个文件夹,放到全新装完系统的vps上,一键部署:
$ fab creatve
如果想通过git推送更改:
$ fab deploy
如果有问题需要回滚:
$ fab rollback
下面是fab文件:
###############
### imports ###
###############
from fabric.api import cd, env, lcd, put, prompt, local, sudo
from fabric.contrib.files import exists
##############
### config ###
##############
local_app_dir = './flask_project'
local_config_dir = './config'
remote_app_dir = '/home/www'
remote_git_dir = '/home/git'
remote_flask_dir = remote_app_dir + '/flask_project'
remote_nginx_dir = '/etc/nginx/sites-enabled'
remote_supervisor_dir = '/etc/supervisor/conf.d'
env.hosts = ['add_ip_or_domain'] # replace with IP address or hostname
env.user = 'newuser'
# env.password = 'blah!'
#############
### tasks ###
#############
def install_requirements():
""" Install required packages. """
sudo('apt-get update')
sudo('apt-get install -y python')
sudo('apt-get install -y python-pip')
sudo('apt-get install -y python-virtualenv')
sudo('apt-get install -y nginx')
sudo('apt-get install -y gunicorn')
sudo('apt-get install -y supervisor')
sudo('apt-get install -y git')
def install_flask():
"""
1. Create project directories
2. Create and activate a virtualenv
3. Copy Flask files to remote host
"""
if exists(remote_app_dir) is False:
sudo('mkdir ' + remote_app_dir)
if exists(remote_flask_dir) is False:
sudo('mkdir ' + remote_flask_dir)
with lcd(local_app_dir):
with cd(remote_app_dir):
sudo('virtualenv env')
sudo('source env/bin/activate')
sudo('pip install Flask==0.10.1')
with cd(remote_flask_dir):
put('*', './', use_sudo=True)
def configure_nginx():
"""
1. Remove default nginx config file
2. Create new config file
3. Setup new symbolic link
4. Copy local config to remote config
5. Restart nginx
"""
sudo('/etc/init.d/nginx start')
if exists('/etc/nginx/sites-enabled/default'):
sudo('rm /etc/nginx/sites-enabled/default')
if exists('/etc/nginx/sites-enabled/flask_project') is False:
sudo('touch /etc/nginx/sites-available/flask_project')
sudo('ln -s /etc/nginx/sites-available/flask_project' +
' /etc/nginx/sites-enabled/flask_project')
with lcd(local_config_dir):
with cd(remote_nginx_dir):
put('./flask_project', './', use_sudo=True)
sudo('/etc/init.d/nginx restart')
def configure_supervisor():
"""
1. Create new supervisor config file
2. Copy local config to remote config
3. Register new command
"""
if exists('/etc/supervisor/conf.d/flask_project.conf') is False:
with lcd(local_config_dir):
with cd(remote_supervisor_dir):
put('./flask_project.conf', './', use_sudo=True)
sudo('supervisorctl reread')
sudo('supervisorctl update')
def configure_git():
"""
1. Setup bare Git repo
2. Create post-receive hook
"""
if exists(remote_git_dir) is False:
sudo('mkdir ' + remote_git_dir)
with cd(remote_git_dir):
sudo('mkdir flask_project.git')
with cd('flask_project.git'):
sudo('git init --bare')
with lcd(local_config_dir):
with cd('hooks'):
put('./post-receive', './', use_sudo=True)
sudo('chmod +x post-receive')
def run_app():
""" Run the app! """
with cd(remote_flask_dir):
sudo('supervisorctl start flask_project')
def deploy():
"""
1. Copy new Flask files
2. Restart gunicorn via supervisor
"""
with lcd(local_app_dir):
local('git add -A')
commit_message = prompt("Commit message?")
local('git commit -am "{0}"'.format(commit_message))
local('git push production master')
sudo('supervisorctl restart flask_project')
def rollback():
"""
1. Quick rollback in case of error
2. Restart gunicorn via supervisor
"""
with lcd(local_app_dir):
local('git revert master --no-edit')
local('git push production master')
sudo('supervisorctl restart flask_project')
def status():
""" Is our app live? """
sudo('supervisorctl status')
def create():
install_requirements()
install_flask()
configure_nginx()
configure_supervisor()
configure_git()
What’s next?
- 一个staging server作为上线前的测试平台.
- 自动单元测试.
日新又新.