CentOS 部署 flask專案

adison發表於2019-03-03

原文地址

最近在學習 python,使用 flask 實現了個個人部落格程式,完了想部署到伺服器上。因為是新手,一路磕磕絆絆最終把它基本搞定。網上資料對新手感覺都不太友好,都是零零碎碎的,所以我整理了一下,一方面作為我自己的記錄,方便以後查閱,另一方面也希望能幫助到跟我一樣的新手。

前提

  1. 有一個伺服器(不然搞毛),購買可以參考優質國外vps推薦

  2. 有個人域名(當然,你可以直接使用 IP訪問,但有點奇怪不是?購買域名可以去GoDaddy

1.安裝git

可以選擇 github 或者Bitbucket,當然你也可以自己搭建 git伺服器,但我覺得沒啥必要,我選擇Bitbucket,主要是因為它私有庫免費

sudo yum install git
複製程式碼

後續就跟我們本地開發沒什麼區別了,配置 ssh key,clone程式碼,就不展開了,專案目錄建議放在 /home/www/

2. 安裝 Mysql

新增 MySQL YUM 源

$wget 'https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm'
$sudo rpm -Uvh mysql57-community-release-el7-11.noarch.rpm
$yum repolist all | grep mysql

mysql-connectors-community/x86_64 MySQL Connectors Community                  36
mysql-tools-community/x86_64      MySQL Tools Community                       47
mysql57-community/x86_64          MySQL 5.7 Community Server                 187

複製程式碼

安裝最新版本

$sudo yum install mysql-community-server
複製程式碼

啟動 MySQL 服務

$sudo service mysqld start 
$sudo systemctl start mysqld #CentOS 7
$sudo systemctl status mysqld
● mysqld.service - MySQL Community Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2017-05-27 12:56:26 CST; 15s ago
  Process: 2482 ExecStartPost=/usr/bin/mysql-systemd-start post (code=exited, status=0/SUCCESS)
  Process: 2421 ExecStartPre=/usr/bin/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
 Main PID: 2481 (mysqld_safe)
   CGroup: /system.slice/mysqld.service
           ├─2481 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
           └─2647 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/...
複製程式碼

說明已經正在執行中了

修改密碼

$ mysql -uroot -p 
複製程式碼

這裡有要求你輸入密碼,Mysql安裝時會生成一個預設密碼,使用 grep "temporary password" /var/log/mysqld.log命令,返回結果最後引號後面的字串就是root的預設密碼

mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword';
複製程式碼

修改編碼

在 /etc/my.cnf 中設定預設的編碼

[client]

default-character-set = utf8

[mysqld]

default-storage-engine = INNODB

character-set-server = utf8

collation-server = utf8_general_ci #不區分大小寫

collation-server = utf8_bin #區分大小寫

collation-server = utf8_unicode_ci #比 utf8_general_ci 更準確

複製程式碼

建立資料庫

mysql> CREATE DATABASE <datebasename> CHARACTER SET utf8;
複製程式碼

3. 安裝python3 pip3

CentOS 7 預設安裝了 Python 2,當需要使用 Python 3 的時候,可以手動下載 Python 原始碼後編譯安裝。

安裝 Python 3

sudo mkdir /usr/local/python3 # 建立安裝目錄
$ wget --no-check-certificate https://www.python.org/ftp/python/3.6.2/Python-3.6.2.tgz # 下載 Python 原始檔 
# 注意:wget獲取https的時候要加上:--no-check-certifica
$ tar -xzvf Python-3.6.2.tgz # 解壓縮包
$ cd Python-3.6.2 # 進入解壓目錄
sudo ./configure --prefix=/usr/local/python3 # 指定建立的目錄
sudo make
sudo make install # 編譯安裝
複製程式碼

執行./configure時可能會報錯,configure: error: no acceptable C compiler found in $PATH,這是因為未安裝合適的編譯器,安裝下就好了,

sudo yum install gcc-c++ (使用sudo yum install gcc-c++時會自動安裝/升級gcc及其他依賴的包。)

配置兩個版本共存

建立 python3 的軟連結:

$ sudo ln -s /usr/local/python3/bin/python3 /usr/bin/python3
複製程式碼

這樣就可以通過 python 命令使用 Python 2,python3 來使用 Python 3。

安裝 pip

$ sudo yum -y install epel-release # 首先安裝 epel 擴充套件源
$ sudo yum -y install python-pip # 安裝 python-pip
$ sudo yum clean all # 清除 cache
複製程式碼

通過這種方式貌似只能安裝 pip2,想要安裝 Python 3 的 pip,可以通過以下的原始碼安裝方式。

# 下載原始碼
$ wget --no-check-certificate https://github.com/pypa/pip/archive/9.0.1.tar.gz

$ tar -zvxf 9.0.1.tar.gz    # 解壓檔案

$ cd pip-9.0.1

$ python3 setup.py install # 使用 Python 3 安裝
複製程式碼

建立連結:

$ sudo ln -s /usr/local/python3/bin/pip /usr/bin/pip3
複製程式碼

升級 pip

$ pip install --upgrade pip
複製程式碼

4. 安裝 gunicorn

Gunicorn (獨角獸)是一個高效的Python WSGI Server,通常用它來執行 wsgi application(由我們自己編寫遵循WSGI application的編寫規範) 或者 wsgi framework(如Django,Paster),地位相當於Java中的Tomcat。 WSGI就是這樣的一個協議:它是一個Python程式和使用者請求之間的介面。WSGI伺服器的作用就是接受並分析使用者的請求,呼叫相應的python物件完成對請求的處理,然後返回相應的結果。 簡單來說gunicorn封裝了HTTP的底層實現,我們通過gunicorn啟動服務,使用者請求與服務相應都經過gunicorn傳輸

建立虛擬環境

cd /home/www/blog
mkdir venv
python3 -m venv venv
複製程式碼

啟用虛擬環境:

source venv/bin/activate
複製程式碼

然後根據requirements.txt檔案安裝依賴包:

pip3 install -r requirements.txt
複製程式碼

安裝gunicorn

pip3 install gunicorn
複製程式碼

在專案根目錄建立一個wsgi.py檔案

from app import create_app

application = create_app('production')

if __name__ == '__main__':
    application.run()
複製程式碼

不再通過manage.py啟動服務,那隻在開發的時候使用

啟動服務:

gunicorn -w 4 -b 127.0.0.1:8000 wsgi:application
複製程式碼

5. 安裝 Nginx

nginx 是一個高效能的web伺服器。通常用來在前端做反向代理伺服器。所謂正向與反向(reverse),只是英文說法翻譯。代理服務,簡而言之,一個請求經過代理伺服器從區域網發出,然後到達網際網路上伺服器,這個過程的代理為正向代理。如果一個請求,從網際網路過來,先進入代理伺服器,再由代理伺服器轉發給區域網的目標伺服器,這個時候,代理伺服器為反向代理(相對正向而言)。

正向代理:{ 客戶端 ---》 代理伺服器 } ---》 伺服器

反向代理:客戶端 ---》 { 代理伺服器 ---》 伺服器 }

{} 表示區域網

nginx既可以做正向,也可以做反向。

$ yum -y install nginx
複製程式碼

啟動 nginx 服務

$ service nginx start
複製程式碼

停止 nginx 服務

$ service nginx stop
複製程式碼

重啟 nginx 服務

$ service nginx restart
複製程式碼

平滑重啟

nginx配置改動了,可以重新載入而不用先關閉再開啟

$ nginx -s reload
複製程式碼

啟動後 ,在瀏覽器中 輸入伺服器的 ip 地址,就可以看到

1324702136-57fb16aa00d21_articlex.png

到這裡 yum 安裝 nginx 就完成了

新增配置

nginx的配置檔案為:/etc/nginx/nginx.conf

server {
        listen 80;
        server_name adisonhyh.com;

        location / {
                proxy_pass http://127.0.0.1:8000;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}
複製程式碼
  • 監聽http預設的埠號80
  • server_name:個人網站域名
  • 把請求代理到本機的8000埠(gunicorn啟動服務指定的埠) 剩下proxy_set_header照抄

gunicorn和nginx關係:

gunicorn 可以單獨提供服務,但生產環境一般不這樣做。首先靜態資源(jscssimg)會佔用不少的請求資源,而對於 gunicorn 來講它本身更應該關注實際業務的請求與處理而不應該把資源浪費在靜態資源請求上;此外,單獨執行 gunicorn 是沒有辦法起多個程式多個埠來負載均衡的。

nginx 的作用就是彌補以上問題,首先作為前端伺服器它可以處理一切靜態檔案請求,此時 gunicorn 作為後端伺服器,nginx 將會把動態請求轉發給後端伺服器,因此我們可以起多個 gunicorn 程式,然後讓 nginx 作均衡負載轉發請求給多個 gunicorn 程式從而提升伺服器處理效率與處理能力。最後,nginx 還可以配置很多安全相關、認證相關等很多處理,可以讓你的網站更專注業務的編寫,把一些轉發規則等其它業務無關的事情交給 nginx 做。

配置好後開啟本地瀏覽器,輸入域名,應該就能訪問了。

6.supervisor

如果你需要程式一直執行,若該程式因各種原因中斷,也會自動重啟的話,supervisor是一個很好的選擇。 supervisor管理程式,是通過fork/exec的方式將這些被管理的程式當作supervisor的子程式來啟動,所以我們只需要將要管理程式的可執行檔案的路徑新增到supervisor的配置檔案中就好了。此時被管理程式被視為supervisor的子程式,若該子程式異常終端,則父程式可以準確的獲取子程式異常終端的資訊,通過在配置檔案中設定autostart=true,可以實現對異常中斷的子程式的自動重啟。

安裝 supervisor

$ pip install supervisor
$ echo_supervisord_conf > supervisor.conf   # 生成 supervisor 預設配置檔案
$ vim supervisor.conf                       # 修改 supervisor 配置檔案,新增 gunicorn 程式管理
複製程式碼

在blog supervisor.conf 配置檔案底部新增 (注意我的工作路徑是www/home/blog/)

[program:blog]
command=/home/www/blog/venv/bin/gunicorn -w4 -b0.0.0.0:8000 wsgi:application    ;supervisor啟動命令
directory=/home/www/blog                                                 ; 專案的資料夾路徑
startsecs=0                                                               ; 啟動時間
stopwaitsecs=0                                                            ; 終止等待時間
autostart=false                                                           ; 是否自動啟動
autorestart=false                                                         ; 是否自動重啟
stdout_logfile=/home/www/blog/logs/gunicorn.log                            ; log 日誌
stderr_logfile=/home/www/blog/logs/gunicorn.err                            ; 錯誤日誌
複製程式碼

使用 supervsior 啟動 gunicorn

$ sudo supervisord -c supervisor.conf  
$ sudo supervisorctl start blog
複製程式碼

在瀏覽器位址列輸入配置的地址即可訪問網站。

7. fabric

最後一步,我們使用fabric實現遠端操作和部署。Fabric 是一個 Python 下類似於 Makefiles 的工具,但是能夠在遠端伺服器上執行命令。

安裝 fabric

pip install fabric
複製程式碼

在 blog 目錄下新建一個fabfile.py檔案

import os
from fabric.api import local, env, run, cd, sudo, prefix, settings, execute, task, put
from fabric.contrib.files import exists
from contextlib import contextmanager

env.hosts = ['204.152.201.69']
env.user = 'root'
env.password = '****'#密碼
env.group = "root"

DEPLOY_DIR = '/home/www/blog'
VENV_DIR = os.path.join(DEPLOY_DIR, 'venv')
VENV_PATH = os.path.join(VENV_DIR, 'bin/activate')


@contextmanager
def source_virtualenv():
    with prefix("source {}".format(VENV_PATH)):
        yield


def update():
    with cd('/home/www/blog/'):
        sudo('git pull')


def restart():
    with cd(DEPLOY_DIR):
        if not exists(VENV_DIR):
            run("virtualenv {}".format(VENV_DIR))
        with settings(warn_only=True):
            with source_virtualenv():
                run("pip install -r {}/requirements.txt".format(DEPLOY_DIR))
                with settings(warn_only=True):
                    stop_result = sudo("supervisorctl -c {}/supervisor.conf stop all".format(DEPLOY_DIR))
                    if not stop_result.failed:
                        kill_result = sudo("pkill supervisor")
                        if not kill_result:
                            sudo("supervisord -c {}/supervisor.conf".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf reload".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf status".format(DEPLOY_DIR))
                            sudo("supervisorctl -c {}/supervisor.conf start all".format(DEPLOY_DIR))


@task
def deploy():
    execute(update)
    execute(restart)

複製程式碼

現在程式碼如果更新了,可以直接在本地執行遠端部署了

fab deploy
複製程式碼

相關文章