當咱們開發了一個簡單的 Flask 程序,想把項目部署上線,咱們能夠選擇傳統的部署方式或者雲部署方式把項目部署上線。在本文中,筆者將使用阿里雲輕量應用服務器
安裝CentOS 7
系統部署一個簡單的 Flask 項目。
要部署一個網站,首先要作的就是購買域名和服務器,市面上主要有阿里雲、騰訊雲、亞馬遜雲等雲服務器供應商,你能夠自由選擇。除了域名和服務器外,還須要申請 SSL 證書,爲開啓 HTTPS 訪問作準備。html
對於還從未購買過域名的用戶,推薦使用阿里雲和騰訊雲購買域名,能夠享受一元首購優惠。前端
阿里雲和騰訊雲針對有專門針對學生的學生機,價格很是實惠。其中阿里雲是隻要你的年齡 24 歲如下自動認定爲大學生,能夠嘗試一下。python
SSL證書是數字證書的一種,相似於駕駛證、護照和營業執照的電子副本。由於配置在服務器上,也稱爲SSL服務器證書。SSL 證書就是遵照 SSL 協議,由受信任的數字證書頒發機構 CA ,在驗證服務器身份後頒發,具備服務器身份驗證和數據傳輸加密功能。mysql
阿里雲和騰訊雲控制檯都提供了 SSL 證書購買的功能,對於須要付費的 SSL 證書,你能夠直接挑選一個價格合適的而後付錢便可。若是想申請免費的 SSL 證書,能夠直接參考下方連接:linux
備案是指向主管機關報告事由存案以備查考。行政法角度看備案,實踐中主要是《立法法》和《法規規章備案條例》的規定。根據中華人民共和國信息產業部第十二次部務會議審議經過的《非經營性互聯網信息服務備案管理辦法》精神,在中華人民共和國境內提供非經營性互聯網信息服務,應當辦理備案。未經備案,不得在中華人民共和國境內從事非經營性互聯網信息服務。而對於沒有備案的網站將予以罰款和關閉。nginx
簡單來講,購買了服務器以後,若是但願經過域名能正常訪問到您的網站,就須要進行網站備案。web
這裏僅以阿里雲服務器控制檯爲例,其它雲服務器請參考官方說明文檔。sql
首先,選擇服務器控制檯中的 站點設置 > 域名
菜單;而後點擊 添加域名
按鈕,爲你的域名同時添加 'www' 及 '@' 記錄。假設你購買的域名爲 demo.com ,則同時添加的兩條記錄爲:shell
這兩個域名都能訪問到你的網站首頁。數據庫
經過 SSH 遠程鏈接服務器實例,能夠方便的對服務器進行管理。你能夠手動輸入命令生成 SSH 密鑰鏈接服務器;也能夠經過雲服務器控制檯自動生成密鑰,而後導出密鑰到本地,再使用導出的密鑰鏈接服務器。這裏推薦經過雲服務器控制檯生成密鑰的方式。
相較於傳統的用戶名和密碼認證方式,使用 SSH 密鑰有如下優點:
在客戶端的 Shell 中執行下面命令生成 SSH 密鑰對:
$ ssh-keygen -t rsa -b 4096 -C "your_email@domain.com"
在客戶端的 Shell 中執行下面命令授予 .ssh
文件夾 600 權限:
$ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/authorizes_keys
在客戶端的 Shell 中執行下面命令將客戶端私鑰拷貝到服務器:
# 執行下面的命令會被要求輸入服務器對應用戶的密碼,密碼輸入正確才能成功完成拷貝 # 記得將下面命令中的 root@47.107.132.88 替換成你本身的服務器的 SSH 地址 $ ssh-copy-id -i ~/.ssh/id_rsa.pub root@47.107.132.88
在客戶端的 Shell 中執行下面命令,進行 SSH 免密碼登錄測試:
$ ssh root@47.107.132.88
在客戶端的 ~/.bashrc
文件中爲遠程鏈接的命令取個別名,之後就能夠方便的進行登錄了:
$ vim ~/.bashrc
在文件中找到下面這一行:
# some more ls aliases
在該行代碼下面再添加一行並保存,內容以下:
alias ecs='ssh root@47.107.132.88'
在客戶端的 Shell 中執行下面命令,使剛剛修改文件生效:
$ source ~/.bashrc
在客戶端的 Shell 中執行下面命令,查看你已經設置的別名:
$ alias
MySQL是一個關係型數據庫管理系統,由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。MySQL 是最流行的關係型數據庫管理系統之一,在 WEB 應用方面,MySQL是最好的 RDBMS (Relational Database Management System,關係數據庫管理系統) 應用軟件。MySQL 軟件採用了雙受權政策,分爲社區版和商業版,因爲其體積小、速度快、整體擁有成本低,尤爲是開放源碼這一特色,通常中小型網站的開發都選擇 MySQL 做爲網站數據庫。
在 Download MySQL Yum Repository 頁面獲取 MySQL 8 Community Yum 倉庫文件的連接,例如:
https://repo.mysql.com//mysql80-community-release-el7-2.noarch.rpm
經過 SSH 遠程鏈接服務器實例,執行下面命令切換到其它擁有 root 權限的用戶,阿里雲服務器實例默認有一個擁有 root 權限的 admin 用戶,這裏以切換到 admin 用戶爲例子:
$ su admin
執行下面命令,下載 MySQL 8 Community Yum 倉庫文件:
$ wget https://repo.mysql.com//mysql80-community-release-el7-2.noarch.rpm
執行下面命令,安裝 MySQL 8 Community Yum 倉庫文件:
$ sudo yum localinstall mysql80-community-release-el7-2.noarch.rpm
執行下面命令,檢查 MySQL 8 Community Yum 倉庫文件是否正確安裝 :
$ yum repolist enabled | grep "mysql.*-community.*"
執行下面命令,安裝 MySQL 8 Community :
$ sudo yum install mysql-community-server
使用 service
命令管理 MySQL 服務:
$ sudo service mysqld start # 啓動 MySQL 服務 $ sudo service mysqld stop # 中止 MySQL 服務 $ sudo service mysqld restart # 重啓 MySQL 服務 $ sudo service mysqld status # 查看 MySQL 服務狀態
使用 systemctl
命令管理 MySQL 服務:
$ sudo systemctl start mysqld # 啓動 MySQL 服務 $ sudo systemctl stop mysqld # 中止 MySQL 服務 $ sudo systemctl restart mysqld # 重啓 MySQL 服務 $ sudo systemctl status mysqld # 查看 MySQL 服務狀態 $ sudo systemctl enable mysqld # 設置 MySQL 服務開機自啓動 $ sudo systemctl disable mysqld # 關閉 MySQL 服務開機自啓動
首次啓動 MySQL 服務,會自動初始化數據目錄、生成 SSL 證書和密鑰文件、建立超級用戶 ' root'@'localhost'
,超級用戶的密碼被設置並存儲在錯誤日誌文件中。可使用如下命令查詢臨時密碼:
$ sudo grep 'temporary password' /var/log/mysqld.log
輸入如下命令,根據提示輸入上一步得到的臨時密碼,鏈接數據庫服務器:
$ mysql -u root -p Enter password: (在這裏輸入上一步查詢到的臨時密碼)
鏈接 MySQL 服務器後,在 MySQL 命令行中爲 ' root'@'localhost'
設置新密碼,使臨時密碼失效:
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';
新版 MySQL 的安全策略要求輸入的密碼要包含大寫字母、小寫字母、數字、特殊符號,推薦使用密碼管理工具生成隨機密碼來做爲你的新密碼。
爲了更加方便的遠程鏈接 MySQL 服務器,接下來須要容許 MySQL 的 root 帳戶在其它地址登錄:
mysql> USE mysql; mysql> UPDATE user SET host = '%' WHERE host = 'root'; # 這裏的 host = '%' 中的 % 表示容許在任意地址登錄,你也能夠設置爲指定的局域網 IP、公網 IP、域名等
Cent OS 預裝了一個 Python 2,而且系統不少組件都依賴於 Python 2 ,筆者在安裝和使用 Python 3 時就由於這些依賴狀況遇到了不少問題,最後總結下來,正確的安裝和使用 Python 3 的過程以下:
使用 Yum 安裝編譯安裝 Python 3 時依賴的包:
$ yum -y groupinstall "Development tools" $ yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel
下載 Python 3.6.7 版本的安裝包,其它版本的請自行去 Download Python | Python.org 獲取連接:
$ wget https://www.python.org/ftp/python/3.6.7/Python-3.6.7.tgz
在當前用戶目錄解壓下載的 Python 安裝包:
$ tar -zxvf Python-3.6.7.tgz
進入已解壓的 Python 安裝文件根目錄:
$ cd Python-3.6.7
經過編譯配置指定 Python 的安裝位置:
$ ./configure --prefix=/usr/local/python3
使用 make
命令開始編譯安裝 Python:
$ make && make install
爲了和系統自帶的 python
和 pip
命令區分開來,給剛剛安裝的 Python 創建軟連接,併爲其設置命令別名。分別取名爲 python3
、pip3
:
$ ln -s /usr/local/python3/bin/python3.6 /usr/bin/python3 $ ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
測試 Python 3 是否正確安裝,輸入 python3
命令:
$ python3 Python 3.6.7 (default, Feb 4 2019, 19:05:27) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux Type "help", "copyright", "credits" or "license" for more information. >>>
測試 Pip 3 是否正確安裝,輸入 pip3
命令:
$ pip3 -V pip 10.0.0 from /usr/local/python3/lib/python3.6/site-packages/pip (python 3.6)
更新 Pip :
$ pip3 install --upgrade pip
Pipenv 是 Pipfile 主要倡導者、requests 做者 Kenneth Reitz 寫的一個命令行工具,主要包含了 Pipfile、pip、click、requests 和 virtualenv ,使用 Pipenv 能夠方便的管理 Python 虛擬環境、管理依賴文件。Pipfile 和 Pipenv原本都是Kenneth Reitz 的我的項目,後來貢獻給了 pypa 組織。Pipfile 是社區擬定的依賴管理文件,用於替代過於簡陋的 requirements.txt 文件。
執行下面命令,安裝 Pipenv :
$ pip3 install pipenv
執行下面命令,爲 Pipenv 可執行文件設置軟連接,以後能夠經過 pipenv
命令來使用 Pipenv :
$ ln -s /usr/local/python3/bin/pipenv /usr/bin/pipenv
切換到一個擁有 root 權限的用戶,這裏以 admin 用戶爲例:
$ su admin
在用戶目錄下爲你的項目建立一個目錄,並進入項目目錄,項目名稱以 FlaskApp 爲例:
$ cd ~ $ mkdir FlaskApp $ cd FlaskApp
執行下面命令,爲項目建立 Python 虛擬環境,默認將虛擬環境保存在 ~/.local/share/virtualenvs
:
$ pipenv install
若是想把虛擬環境保存至項目根目錄,須要設置環境變量 PIPENV_VENV_IN_PROJECT=1
,再執行建立命令:
$ export PIPENV_VENV_IN_PROJECT=1 $ pipenv install
虛擬環境建立完成後,執行下面命令爲虛擬環境安裝 Flask 包:
$ pipenv install flask
在項目根目錄編寫一個簡單的 Flask Demo 進行測試:
# 新建並打開一個名爲 app.py 的文件 $ vim app.py
輸入下面的代碼並保存:
from flask import Flask app = Flask(__name__) @app.route('/') def hello_flask(): return 'Hello Flask!'
使用 pipenv run
調用虛擬環境中的 Python 執行 flask run
命令能夠運行編寫的代碼:
$ pipenv run flask run
也可使用 pipenv shell
命令進入虛擬環境,而後再在虛擬環境執行 flask run
命令運行程序:
$ pipenv shell (venv)$ flask run
Flask 默認運行的地址和端口爲 http://127.0.0.1:5000 ,雲服務器實例不包含桌面環境的話,你很難去瀏覽這個頁面。你能夠設置 flask 運行的地址和端口,而後嘗試從外網訪問該頁面。先執行下面命令,讓 flask 容許外網訪問,而且監聽 80 端口:
$ pipenv run flask run --host 0.0.0.0 --port 80
而後你能夠經過你的服務器公網 IP 或 域名 直接訪問到該頁面。
flask run
命令啓動的開發服務器是由 Werkzeug 提供的。細分的話, Werkzeug 提供的這個開發服務器應該被稱爲 WSGI 服務器,而不是單純意義上的 Web 服務器。在生產環境中,咱們須要一個更強健、性能更高的 WSGI 服務器。這些 WSGI 服務器也被稱爲獨立 WSGI 容器,由於它們能夠承載咱們編寫的 WSGI 程序,而後處理 HTTP 請求和響應。這一般有不少選擇,好比 Gunicorn 。 Gunicorn 是 Green Unicorn 的簡寫,意爲綠色獨角獸,是一款專爲 UNIX 設計的 Python WSGI HTTP 服務器。是一個Pre-fork 工人模型。Gunicorn 服務器普遍兼容各類 web 框架,實現簡單,節省服務器資源,速度至關快。
安裝 Gunicorn :
$ pipenv install gunicorn
使用 Gunicorn 運行一個 WSGI 程序:
$ pipenv run gunicorn --workers=4 --bind=0.0.0.0:8000 app:app # --workers = 4 表示使用 4 worker 進程運行程序,建議 worker 數量爲 ( CPU 核心數 × 2 ) + 1 # Gunicorn 默認只容許從本地 8000 端口訪問,--bind=0.0.0.0:8000 表示容許使用 8000 端口從外部訪問 # app:app 冒號前面的 app 表示 app.py 文件,冒號後面的 app 表示 flask 程序的名稱
也能夠把 --workers
簡寫爲 -w
、--bind
簡寫爲 -b
,以下:
# 沒有 -b 或者 --bind 參數,默認監聽 127.0.0.1:8000 $ pipenv run gunicorn -w 4 app:app # 指定 -b 0.0.0.0:8000 監聽 8000 端口的外部請求 $ pipenv run gunicorn -w 4 -b 0.0.0.0:8000 app:app
像 Gunicorn 這類 WSGI 服務器內置的 Web 服務器還不夠強健,雖然程序能夠正常運行,可是更流行的部署方式是使用一個常規的 Web 服務器運行在前端,爲 WSGI 提供反向代理。比較流行的開源 Web 服務器有 Nginx 、Apache 等,這裏選擇使用和 Gunicorn 集成良好的 Nginx 。
訪問 nginx packages 獲取對應版本 Nginx 的 Yum 倉庫的連接,例如:
http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
下載 Nginx Yum 倉庫文件:
$ wget http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
安裝 Nginx Yum 倉庫文件:
$ sudo yum localinstall nginx-release-centos-7-0.el7.ngx.noarch.rpm
安裝 Nginx :
$ sudo yum install nginx
進入 Nginx 配置文件目錄:
$ cd /etc/nginx/
建立 cert 目錄,並上傳你的 SSL 證書到該目錄:
$ mkdir cert
上傳 SSL 證書到 cert 目錄你可使用 scp
命令,或者使用 FileZilla 等 SFTP 軟件,我上傳的文件以下:
$ cd cert $ ls ssl.key ssl.pem
進入 /etc/nginx/conf.d/
目錄編輯默認的配置文件 default.conf
:
$ cd /etc/nginx/conf.d/ $ vim default.conf
刪除文件中原有的所有內容,新增下面內容並保存:
# 監聽 http 請求,強制跳轉到 https server { listen 80; # 這裏的 your.domain.com 換成你購買的域名 server_name your.domain.com; # 這裏的 your.domain.com 換成你購買的域名 return 301 https://your.domain.com$request_uri; } # 監聽 https 請求 server { listen 443; # 這裏的 your.domain.com 換成你購買的域名 server_name your.domain.com; access_log /var/log/nginx/host.access.log; error_log /var/log/nginx/host.error.log; ssl on; # 這部分的 ssl.pem ssl.key 換成你上傳的與其對應的文件 ssl_certificate cert/ssl.pem; ssl_certificate_key cert/ssl.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; location / { # 轉發請求給 Gunicorn proxy_pass http://127.0.0.1:8000; proxy_redirect off; # 爲了能正常運行,重寫請求頭 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # 處理靜態文件夾中的靜態文件 location /static { alias /home/admin/FlaskApp/static/; # 設置靜態文件緩存過時時間爲 30 天 expires 30d; } }
測試配置正確性:
$ sudo nginx -t
若是出現的提示中沒有報錯,則能夠啓動 nginx 了。
啓動 nginx :
$ sudo nginx
如今,你可使用 Gunicorn 不指定 --bind
參數運行 Flask 程序,而後嘗試從外網經過 HTTPS 訪問,判斷 nginx 反向代理是否設置成功。
使用 nginx
命令管理 Nginx :
$ sudo nginx # 啓動 Nginx 服務 $ sudo nginx -s stop # 關閉 Nginx 服務 $ sudo nginx -s reload # 重載 Nginx 服務 $ sudo nginx -s reopen # 重啓 Nginx 服務 $ sudo nginx -s quit # 退出 Nginx 服務
使用 service
命令管理 Nginx 服務:
$ sudo service nginx start # 啓動 Nginx 服務 $ sudo service nginx stop # 中止 Nginx 服務 $ sudo service nginx restart # 重啓 Nginx 服務 $ sudo service nginx status # 查看 Nginx 服務狀態
使用 systemctl
命令管理 Nginx 服務:
$ sudo systemctl start nginx # 啓動 Nginx 服務 $ sudo systemctl stop nginx # 中止 Nginx 服務 $ sudo systemctl restart nginx # 重啓 Nginx 服務 $ sudo systemctl status nginx # 查看 Nginx 服務狀態 $ sudo systemctl enable nginx # 設置 Nginx 服務開機自啓動 $ sudo systemctl disable nginx # 關閉 Nginx 服務開機自啓動
若是 Nginx 已經啓動卻又被啓動了一次,可能會報錯。好比:找不到 nginx.pid
文件、提示 XX 端口已經被使用等等...,解決辦法以下:
# 殺掉佔用 80 端口的進程 $ sudo fuser -k 80/tcp # 殺掉佔用 443 端口的進程 $ sudo fuser -k 443/tcp # 使用默認配置文件從新啓動 Nginx $ sudo nginx -c /etc/nginx/nginx.conf
Supervisor 是用 Python 開發的一套通用的進程管理程序,能將一個普通的命令行進程變爲後臺 daemon ,並監控進程狀態,異常退出時能自動重啓。它是經過 fork/exec 的方式把這些被管理的進程看成 Supervisor 的子進程來啓動,這樣只要在 Supervisor 的配置文件中把要管理的進程的可執行文件的路徑寫進去便可。也實現當子進程掛掉的時候,父進程能夠準確獲取子進程掛掉的信息的,能夠選擇是否本身啓動和報警。Supervisor 還提供了一個功能,能夠爲 supervisord 或者每一個子進程設置一個非 root 的用戶,這個用戶就能夠管理它對應的進程。
安裝 Supervisor :
$ sudo yum install supervisor
檢查 Supervisor 配置文件:
$ vim /etc/supervisord.conf
找到最後一行,檢查是不是以下內容:
[include] files = supervisord.d/*.ini
若是不是,則修改文件使其跟上面內容一致。
進入 /etc/supervisord.d/
目錄, 爲項目建立一個 Supervisor 配置文件:
$ cd /etc/supervisord.d/ $ vi FlaskApp.ini
配置文件內容爲:
[program:app] ; 下面命令中的 app:app 請修改成你實際部署時的項目名稱 command=pipenv run gunicorn -w 4 app:app ; 下面的路徑請修改成你建立的項目的根目錄 directory=/home/admin/FlaskApp autostart=true autorestart=true stopsignal=QUIT stopasgroup=true killasgroup=true ; 下面的用戶請修改成建立該項目的用戶 user=admin redirect_stderr=true ; log 文件的路徑你能夠從新自定義 stdout_logfile=/home/admin/FlaskApp/log/supervisor.log ; 解決編碼問題 [supervisord] environment=LC_ALL='en_US.UTF-8',LANG='en_US.UTF-8'
啓動 Supervisor :
$ supervisord -c /etc/supervisord.conf
使用 service
命令管理 Supervisor 服務:
$ sudo service supervisord start # 啓動 Supervisor 服務 $ sudo service supervisord stop # 中止 Supervisor 服務 $ sudo service supervisord restart # 重啓 Supervisor 服務 $ sudo service supervisord status # 查看 Supervisor 服務狀態
使用 systemctl
命令管理 Supervisor 服務:
$ sudo systemctl start supervisord # 啓動 Supervisor 服務 $ sudo systemctl stop supervisord # 中止 Supervisor 服務 $ sudo systemctl restart supervisord # 重啓 Supervisor 服務 $ sudo systemctl status supervisord # 查看 Supervisor 服務狀態 $ sudo systemctl enable supervisord # 設置 Supervisor 服務開機自啓動 $ sudo systemctl disable supervisord # 關閉 Supervisor 服務開機自啓動
進入 Supervisor 控制檯,管理後臺進程:
$ sudo supervisorctl app RUNNING pid 2696, uptime 23:46:00 supervisor > help # 輸入 help 命令,查看 supervisor 支持的命令 default commands (type help <topic>): ===================================== add clear fg open quit remove restart start stop update avail exit maintail pid reload reread shutdown status tail version
使用 status
命令,查看正在運行的後臺進程:
supervisor> status app RUNNING pid 2696, uptime 23:49:37
使用 stop
命令,結束指定的進程:
supervisor> stop app app: stopped
使用 start
命令,啓動指定的進程:
supervisor> start app app: started