当咱们开发了一个简单的 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