本文記錄如何利用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 modulevirtualenvPython虛擬執行環境,可以避免依賴衝突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/appPython代碼/usr/www/demo/app/staticcss樣式、js等靜態資源/usr/www/demo/venvpython virtualenv/usr/www/demo/log日誌文件/usr/www/demo/files圖片等附件/usr/git/demogit服務器
接着,爲項目添加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