本文記錄如何利用Python、Flask、Nginx、Supervisor、Gunicorn、Git搭建Website
架構
我們使用Nginx作爲前端反向代理服務器,一些靜態資源可以直接通過Nginx
訪問。對於動態資源,Nginx
將請求轉發到後端的Gunicorn服務器,Gunicorn
負責調用後端的Python
代碼,進行動態處理。
租VPS
可以選擇以下服務器提供商
买域名
(域名解析到國內主機需要備案)
搭建環境
選擇Ubuntu
作爲VPS的操作系統,下面開始安裝必要的軟件
安装nginx
, git
, mysql
, python-pip
, virtualenv
, python-dev
,libmysqlclient-dev
git
版本控制,同時也是程序源碼來源python-pip
安裝Python modulevirtualenv
Python虛擬執行環境,可以避免依賴衝突mysql
數據庫nginx
前端代理服務器
$ sudo apt-get install git
$ sudo apt-get install python-pip
$ sudo apt-get install mysql-server
$ sudo apt-get install nginx
$ sudo apt-get install python-dev
$ sudo apt-get install libmysqlclient-dev
配置好mysql
的密碼後,可以嘗試登陸
$ mysql -u root -p
安裝好nginx
後,輸入以下命令,可以查看其運行狀態
$ sudo service nginx status
裝好後nginx
服務已經啓動,此時,可以在瀏覽器中鍵入服務器ip或者域名,會顯示歡迎界面(圖爲在Raspberry Pi上面搭建的結果)
我們需要更改nginx
的配置文件,使其能將請求解析到我們編寫的網頁。
Nginx配置
我們將項目部署到/usr/www/
目錄下,首先創建以下目錄:
/usr/www/demo/app
Python代碼/usr/www/demo/app/static
css樣式、js等靜態資源/usr/www/demo/venv
python virtualenv/usr/www/demo/log
日誌文件/usr/www/demo/files
圖片等附件/usr/git/demo
git服務器
接着,爲項目添加nginx
配置文件。在/etc/nginx/sites-available/
目錄下創建文件demo
,文件內容爲
server {
listen 80;
root /usr/www/demo/app;
access_log /usr/www/demo/log/access_log;
error_log /usr/www/demo/log/error_log;
server_name $demo.hejunjie.net;
location ~ ^\/static\/.*$ {
root /usr/www/demo/app;
}
location ~ ^\/files\/.*$ {
root /usr/www/demo/files;
}
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;
}
}
nginx
會直接處理/static/*
以及/files/*
目錄下的請求,將其他請求轉發到本地的9000
端口。9000
端口由Gunicorn
監聽,稍後會講解其配置。
接下來,我們在/etc/nginx/sites-enabled/
下創建符號連接
$ sudo ln -s /etc/nginx/sites-available/demo /etc/nginx/sites-enabled/demo
sites-available
目錄下的配置文件表示所有可能使用的配置,sites-enabled
中的文件是sites-available
中文件的符號鏈接,表示實際上正在使用的項目。通過更改符號鏈接,我們可以隨時更改正在使用的項目。
Gunicorn配置
上面,我們說道,nginx
將動態請求轉發到本地的9000
端口,Gunicorn
正是監聽此端口。Nginx
可以直接作爲服務進程啓動,但是Gunicorn
還不行,因此我們使用Supervisor。Supervisor
是一个管理进程的工具,可以随系统启动而启动服务,它还时刻监控服务进程,如果服务进程意外退出,Supervisor可以自动重启服务。同時,我們安裝gevent,它是一個把Python同步代码变成异步协程的库;
首先,我們在/usr/www/demo/
下創建Python
虛擬環境,然後安裝Gunicorn
,gevent
$ virtualenv venv
$ source venv/bin/active
(venv)$ pip install gunicorn
(venv)$ pip install gevent
$ deactive
然後,我們創建Supervisor
配置文件。在/etc/supervisor/conf.d/
目錄下,創建demo.conf
文件。內容如下
[program:demo]
command = /usr/www/demo/venv/bin/gunicorn --bind 127.0.0.1:9000 --workers 1 --worker-class gevent index:app
directory = /usr/www/demo/app
user = www-data
startsecs = 3
redirect_stderr = true
stdout_logfile_maxbytes = 50MB
stdout_logfile_backups = 10
stdout_logfile = /usr/www/demo/log/supervisor.log
配置文件通过[program:demo]
指定服务名为demo
,command指定启动gunicorn
的命令行,设定gunicorn
的启动端口为9000
,WSGI
处理函数入口为index:app
。即/usr/www/demo/app/
目錄下的index.py
文件,該文件中有app
對象。
我們只需要將項目源碼放入/usr/www/demo/app/
目錄下即可
Git配置
爲了方便項目部署,我們使用git
作爲版本控制系統。並可以利用git
的hook
機制,當我們將源碼提交到版本庫時,同時將最新版的源碼拷貝到/usr/www/demo/app/
目錄下,實現更新。
首先,按照git官方教程創建git server
。然後在/usr/git/
下建立一個裸倉庫
$ sudo git init --bare demo
接着,在hooks
目錄下創建post-receive
,當我們提交新源碼時,會更新項目代碼以及安裝新增的依賴項。內容如下
#!/bin/bash
GIT_WORK_TREE=/usr/www/demo/app git checkout -f
source /usr/www/demo/venv/bin/activate
pip install -r /usr/www/demo/app/requirements.txt
deactivate
supervisorctl reload demo
然後,我們需要將裸倉庫中的內容拷貝到/usr/www/demo/app
git clone git@your_ip:/usr/git/$project.git /usr/www/demo/app
之後,需要將git
添加到www-data
用戶組,並將Supervisor
配置文件中的user=www-data
改爲user=git
還要更改Supervisor
的權限配置,不然無法在提交後更新項目
[unix_http_server]
file=/var/run/supervisor.sock ; (the path to the socket file)
chmod=0770 ; sockef file mode (default 0700)
chown=root:www-data ;
gpasswd -a git www-data
就可以利用git提交代碼啦
啓動
$ sudo supervisorctl reload
$ sudo service nginx restart
集成
以上命令可以集成爲一個shell腳本,參數爲 項目名 端口號
#!/bin/bash
project=$1
port=$2
directory=/usr/www/$1
sudo mkdir -p $directory/app
sudo mkdir -p $directory/log
sudo mkdir -p $directory/files
# nginx
nginx_file="/etc/nginx/sites-available/$project"
nginx_conf="server {
listen 80;
root $directory/app;
access_log $directory/log/access_log;
error_log $directory/log/error_log;
server_name $project.hejunjie.net;
location ~ ^\/static\/.*$ {
root $directory/app;
}
location ~ ^\/files\/.*$ {
root $directory/files;
}
location / {
proxy_pass http://127.0.0.1:$port;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header Host \$host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
}
}"
echo $nginx_conf | sudo tee $nginx_file
sudo chmod 644 $nginx_file
sudo ln -s $nginx_file /etc/nginx/sites-enabled/$project
# supervisor
supervisor_file="/etc/supervisor/conf.d/$project.conf"
supervisor_conf="[program:$project]\r\ncommand = $directory/venv/bin/gunicorn --bind 127.0.0.1:$port --workers 1 --worker-class gevent index:app\r\ndirectory = $directory/app\r\nuser = git\r\nstartsecs = 3\r\nredirect_stderr = true\r\nstdout_logfile_maxbytes = 50MB\r\nstdout_logfile_backups = 10\r\nstdout_logfile = $directory/log/supervisor.log"
echo -e $supervisor_conf | sudo tee $supervisor_file
sudo virtualenv $directory/venv
sudo chmod -R 777 $directory/venv
source $directory/venv/bin/activate
pip install gunicorn gevent
deactivate
sudo chmod -R 755 $directory/venv
sudo chown -R www-data:www-data $directory
sudo chown -R git:git $directory/app
sudo chown -R git:git $directory/venv
# git
git_dir="/usr/git/$project.git"
hook_file="$git_dir/hooks/post-receive"
hook_shell="#!/bin/bash\n
GIT_WORK_TREE=$directory/app git checkout -f\n
source $directory/venv/bin/activate\n
pip install -r $directory/app/requirements.txt\n
deactivate\n
supervisorctl reload $project"
sudo mkdir -p /usr/git
sudo git init --bare $git_dir
echo -e $hook_shell | sudo tee $hook_file
sudo chmod 755 $hook_file
sudo chown -R git:git $git_dir
sudo chown -R ubuntu:ubuntu $directory/app
git clone git@your_ip:/usr/git/$project.git $directory/app
sudo chown -R git:git $directory/app
sudo service nginx restart
sudo supervisorctl reload