17 Flask mega-tutorial 第17章 在Linux上部署(腾讯云 Ubuntu)【极其详细的部署过程】

如需转载请注明出处。
win10 64位、Python 3.6.3、Notepad++、Chrome 67.0.3396.99(正式版本)(64 位)
注:作者编写时间2018-03-28,linux、python 3.5.2

以下内容均是加入自己的理解与增删,以记录学习过程。不限于翻译,部分不完全照搬作者Miguel Grinberg的博客,版权属于作者,感谢他提供免费学习的资料。

传送门
00 开篇 01 Hello world 02 模板 03 Web表单
04 数据库 05 用户登录 06 个人资料和头像 07 错误处理
08 关注 09 分页 10 支持QQ邮箱 11 美化页面
12 时间和日期 13 I18n和L10n 翻译成中文 zh-CN 14 Ajax(百度翻译API 15 更好的App结构(蓝图)
16 全文搜索 17 部署到腾讯云Ubuntu 18 部署到Heroku 19 部署到Docker容器
20 JavaScript魔法 21 用户通知 22 后台工作(Redis) 23 应用程序编程接口(API)
预备: Linux,严格来讲,这个词本身 只表示Linux内核(内核是什么?它建立了计算机软件与硬件之间通讯的平台,内核提供系统服务,如文件管理、虚拟内存、设备I/O等),但实际上人们已习惯用Linux来形容 整个基于Linux内核,并且使用GNU工程各种工具和数据库的 操作系统

那么基于Linux内核的Linux发行版本有N多,如主流Linux发行版(常见的Ubuntu、CentOS、Debian、等等)、中国内地Linux发行版(雨林木风YLMF OS 哈哈、红旗Linux、等等)。

  • Ubuntu(优般图),有着漂亮的用户界面、完善的包管理系统、强大的软件源支持、丰富的技术社区,最佳的应用领域是桌面操作系统而非服务器操作系统。适合有钱人玩,占用的资源比CentOS、Debian都高,而VPS基本是卖内存、内存越高、价格越贵。
  • CentOS,很多应用程序部署在生产环境上的服务器都是使用的CentOS系统。它简约、稳定、命令行下的人性化做得非常好。新手的话,首选CentOS。占用资源少,在网上能方便地搜到安装配置的文档,且自身的帮助文档也非常强大。
  • Debian,也适合于服务器的操作系统,比Ubuntu稳定。适合Linux高手,在低配的VPS上稳定运行系统。
  • 等等。

本章将学习把 Microblog部署到Linux服务器。将在Microblog应用程序的生命周期中达到一个里程碑,接下来将讨论如何在生产服务器上部署应用程序,以便真实用户可以访问它

本章仅致力于探索 传统的托管,在此将使用 运行Ubuntu的专用Linux服务器,以及广受欢迎的Raspberry Pi小型计算机。

传统托管 Traditional hosting

说到“ 传统托管”,即意味着 应用程序是 手动安装的、或通过 在一个stock server machine上的脚本安装程序安装的。该过程涉及 安装应用程序,它的依赖项和生产规模Web服务器,并配置这个系统以确保其安全。

在部署项目时,需要解决的第一个问题是 在哪里找到服务器。在国内(中国)用的多可能就是阿里云、腾讯云、UCloud了;国际可选择 AWS。不过在不花钱的情况下练习部署,Vagrant、VirtualBox两个工具结合,也可以在自己的计算机上创建类似于付费虚拟服务器的 虚拟服务器。

操作系统选择而言,从技术角度看,我们这个应用程序可以部署在任何主要的操作系统上,包括各种开源Linux和BSD发行版的列表、以及商业OS X和Microsoft Windows。

由于OS X 和Windows是未经优化用作服务器的桌面操作系统,故将其作为候选者丢弃。Linux或BSD操作系统之间的选择很大程度上取决于偏好,因此选择最受欢迎的 Linux。而就Linux发行版而言,将按人气选择Ubuntu

创建Ubuntu服务器

我购买的是腾讯云 `1核CPU 2G内存 Ubuntu Server 16.04.01 LTS 64位`。10元/月。

免费方案是 自己的计算机上运行虚拟机(后续研究)。在计算机上安装 Vagrant和VirtualBox,然后创建名为 Vagrantfile的文件,用如下内容描述VM的规范:
Vagrantfile:Vagrant配置

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/xenial64"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024"
  end
end

此文件配置具有1GB RAM的Ubuntu 16.04服务器,可以从IP地址为192.168.33.10的主机访问该服务器。要创建服务器,请运行以下命令:

$ vagrant up

参阅Vagrant 命令行文档以了解管理虚拟服务器的其他选项。

使用SSH客户端

SSH(Secure Shel的缩写,译作 安全外壳协议。提供安全性的协议)。

在此,服务器并不像在自己计算机上那样拥有桌面。所以得通过SSH客户端来连接到服务器,并通过命令行处理它。由于我用的是win10,则可选择 Cygwin、Git、Windows Subsystem for Linux中的任一个,它们提供OpenSSH。在此,我使用Git。

如果使用的是来自第三方提供商的虚拟服务器,则在创建服务器时,会获得一个IP地址。可使用如下命令打开与全新服务器的终端会话:

Administrator@Cchen-PC MINGW64 /
$ ssh ubuntu@<腾讯云-公网IP>
ubuntu@<腾讯云-公网IP>'s password:输入密码
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-130-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

ubuntu@VM-0-10-ubuntu:~$

PS:腾讯云主机Ubuntu系统默认用户名为 ubuntu,登录服务器时每一次都是以默认账户ubuntu进行登录。

如果使用Vagrant VM,则可以使用如下命令打开终端会话:

$ vagrant ssh

如果使用的Windows并拥有Vagrant VM,注意 将需要从shell运行上述命令,它能调用OpenSSHd ssh命令。

无密码登录

PS:若使用Vagrant VM,可跳过此部分。因为VM已正确配置为 使用名为`ubuntu`的非root账户,而Vagrant不会自动使用密码。

如果使用的虚拟服务器,建议创建一个常规用户账户来进行部署工作,并配置此账户以便在不使用密码的情况下登录,不仅更方便而且更安全。

接下来将配置 ubuntu账户已使用公钥身份验证,以便无需键入密码即可登录。

首先,腾讯云控制平台 安全组 开放公网端口 至少要开放22端口。
17 Flask mega-tutorial 第17章 在Linux上部署(腾讯云 Ubuntu)【极其详细的部署过程】_第1张图片
将已打开的具有服务器的终端会话暂时保留(不关闭),然后在本地计算机上其中第二个终端(Git),用如下命令检查 ~/.ssh 目录的内容:

Administrator@Cchen-PC MINGW64 /
$ ls ~/.ssh
id_rsa  id_rsa.pub

如果目录列表显示如同上述名为 id_rsaid_rsa.pub的文件,那么意味着已有一个密钥。如果没有这两个文件根本没有~/.ssh 目录 ,那么需要通过运行以下命令来创建SSH密钥对,该命令也是OpenSSH工具集的一部分:

$ ssh-keygen -t rsa -b 1024

注意这个命令,观察 腾讯云平台生成的私钥长度比本地生成的要短,即本地生成公钥对时 需生成1024bits长度的密钥。故 加上 -b 参数。

将提示输入一些内容,建议在所有提示中按Enter键接受默认值。当然,如果知道在做什么,想要做什么,可不接受默认值。
运行上述命令后,将会具有上方所列出的两个文件(以我为例,这两个文件将存放在C:\Users\Administrator\.ssh )。id_rsa.pub文件 是你的公钥,它是一个文件,将提供给第三方作为识别你的方式。id_rsa文件是你的私钥,不应与任何人共享。

现在需要将公钥配置为 服务器中的授权主机,在自己的计算机上打开终端,将公钥打印到屏幕上:

Administrator@Cchen-PC MINGW64 /
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQD5HPx4k0SOz9/q/bnlYINvjPBy7O13hDiAy1PDArqSmHCO6/ZGDSQb+151NsVyzoqnMNyemNyYncCnE6iMmpQSVOi6VYbdHcaUfjbHsI8xHbtJokKfJbryNy+bPezgF8/A6fg3s5uSHPJJNDbMumKv8TdjW/Wcimi8xp4HZk4xXQ== Administrator@Cchen-PC

这是一个很长的字符序列,可能跨越多行。将此数据复制到剪贴板,然后切换回远程服务器上的终端(一开始的终端),用如下命令保存公钥

ubuntu@VM-0-10-ubuntu:~$ echo ssh-rsa  >> ~/.ssh/authorized_keys
ubuntu@VM-0-10-ubuntu:~$ chmod 600 ~/.ssh/authorized_keys

无密码登录现在应该正常工作。想法是你计算机上的ssh将通过执行需要密钥的加密操作来向服务器标识自己。然后,服务器使用你的公钥验证操作是否有效。

现在可退出ubuntu会话(如 exit命令 或直接关闭终端窗口后重新打开),然后尝试使用下方命令直接登录ubuntu账户:

$ ssh ubuntu@<腾讯云-公网IP>
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-130-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
New release '18.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Thu Sep  6 21:51:59 2018 from 183.14.134.229
ubuntu@VM-0-10-ubuntu:~$

这次不必输入密码!

保护你的服务器

为最大限度地降低服务器遭受入侵风险,这里可采取一些步骤,针对关闭攻击者可能获取访问权限的许多可能之处。

第一个改变:通过SSH禁用root登录。
现在可以无密码访问ubuntu账户,并可以通过此账户运行管理员命令 sudo,因此实际上不需要公开root账户。要禁用root登录,需编辑服务器上的/etc/ssh/sshd_config文件。在git上登录服务器后,输入如下命令,回车:

ubuntu@VM-0-10-ubuntu:~$ sudo vi /etc/ssh/sshd_config

更改此文件中的一行:
/etc/ssh/sshd_config:禁用root登录

PermitRootLogin no

第二个改变:禁用所有账户的密码登录。更改还是在同一个文件中。
我有 无密码登录设置,因此根本不需要允许密码。如果对完全禁用密码感到紧张,可跳过此更改,但对于生产服务器来说,这是个好主意,因为攻击者不断尝试在所有希望幸运的服务器上使用随机账户名和密码。
/etc/ssh/sshd_config:禁用root登录

PasswordAuthentication no

完成SSH配置编辑后在底部输入 :wq (Linux命令,意为 保存并退出vi),需要重新启动服务才能使更改生效:

ubuntu@VM-0-10-ubuntu:~$ sudo service ssh restart

第三个改变:安装防火墙。(暂未在腾讯云 webshell上操作)
这是一个阻止未明确启用的任何端口上对服务器的访问的软件:

ubuntu@VM-0-10-ubuntu:~$ sudo apt-get install -y ufw
Reading package lists... Done
Building dependency tree
Reading state information... Done
ufw is already the newest version (0.35-0ubuntu2).
0 upgraded, 0 newly installed, 0 to remove and 197 not upgraded.
ubuntu@VM-0-10-ubuntu:~$ sudo ufw allow ssh
Rules updated
Rules updated (v6)
ubuntu@VM-0-10-ubuntu:~$ sudo ufw allow http
Rules updated
Rules updated (v6)
ubuntu@VM-0-10-ubuntu:~$ sudo ufw allow 443/tcp
Rules updated
Rules updated (v6)
ubuntu@VM-0-10-ubuntu:~$ sudo ufw --force enable
Firewall is active and enabled on system startup
ubuntu@VM-0-10-ubuntu:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere
80                         ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
22 (v6)                    ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)

这些命令安装ufw(简单防火墙,版本0.35-0ubuntu2),并将其配置为仅允许端口22(ssh),80(http)和443(https)上的外部流量。不允许任何其他端口。

安装基本依赖项

如果遵循上述建议使用 腾讯云 Ubuntu 16.04版本 配置我们的服务器,那么系统将支持 Python 3.5.1-3(时间:20180907的腾讯云),而我使用的3.6.3,作者使用3.5.2。

基本的Python解释器可能已预先安装在腾讯云服务器上,但是有一些额外的软件包可能没有,而且还有一些其他Python外的软件包(用于创建健壮的生产就绪部署)。对于数据库服务器,我将从SQLite切换到MySQL。postfix包是一个邮件传输代理,我将它发送电子邮件。supervisor工具将监视Flask服务器进程,并在崩溃时自动重启它,或如果服务器重新启动也会自动重启。nginx服务器将接受来自外部世界的所有请求,并将它们转发给应用程序。最后,我将使用git作为直接从git仓库下载应用程序的工具。
在git上登录服务器后(或腾讯云 WebShell中)输入如下命令:

$ sudo apt-get -y update
$ sudo apt-get -y install python3 python3-venv python3-dev
$ sudo apt-get -y install mysql-server postfix supervisor nginx git

其中,各自版本如下:

名称 版本号
MySQL 5.7.23
postfix 3.1.0
supervisor 3.2.0
nginx 1.10.3
git 1:2.7.4

上述安装软件包 是“无人值守”的,在运行第三个安装语句的某个时刻时,系统会提示选择输入MySQL服务器的root密码(输入你想设置的密码),并且还会询问有关安装 postfix软件包的几个问题,可接受它们默认答案。

注意,上述部署,不安装Elasticsearch。这个服务需要大量RAM,因此得拥有大于2GB RAM的大型服务器才能实现。。为了避免服务器内存不足的问题,将保留搜索功能。如果你是土豪,服务器足够大,可以从Elasticsearch网站下载官方.deb软件包,并按照其安装说明将其添加到我们的服务器。不过注意,在Ubuntu 16.04软件包仓库中提供的Elasticsearch软件包太老而无法使用,需要安装6.x或更高版本。

还应该注意,postfix的默认安装可能不足以在生产环境中发送电子邮件。为了避免垃圾邮件和恶意电子邮件,许多服务器要求发件人服务器通过安全扩展来识别自己,这意味着至少必须拥有与我们服务器关联的域名。如果想了解如何完全配置电子邮件服务器以使其通过标准安全测试,可参阅下方Digital Ocean 指南:

  • Postfix Configuration
  • Adding an SPF Record
  • DKIM Installation and Configuration

安装应用程序

我一直未上传microblog应用程序代码 至github仓库中。首先我得在microblog目录下建一个`.gitignore`文件。由于在win下无法直接创建 .开头的且没有文件名的文件,所以在需要创建`.gitignore`文件的microblog文件夹,右键选择 `Git Bash Here`进入命令行,从而进入项目所在目录。

接着,输入touch .gitignore命令,此时microblog文件夹下就生成一个 .gitignore文件。

最后 git bash中输入 vi .gitignore命令编辑.gitignore文件。输入我要忽略的文件夹、文件。见我的github查看具体的编辑内容。
具体可参考大牛博客1
博客2

上传代码至github的步骤:

  1. 在github上新建仓库,名为 microblog;
  2. 右键单击microblog文件夹,选择 Git Bash Here进入命令行,从而进入项目所在目录;
  3. 依次输入命令:

git init
git add .
git commit -m "部署到腾讯云 Ubuntu上的microblog应用程序代码(截止到教程第17章 )"
git remote add origin https://github.com/czy0905/microblog.git
git push -u origin master
在上述输入最后一个命令时,会提示输入github用户名和密码。

git bash登录腾讯云

$ ssh [email protected]
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-130-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
New release '18.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.


Last login: Fri Sep  7 19:54:43 2018 from 183.14.134.229
ubuntu@VM-0-10-ubuntu:~$ ls -l
total 8
drwxrwxr-x 5 ubuntu ubuntu 4096 Sep  7 19:55 microblog
drwxrwxr-x 6 ubuntu ubuntu 4096 Sep  7 20:01 venv
ubuntu@VM-0-10-ubuntu:~$ ~ #代表[目前用户身份]所在的家目录
-bash: /home/ubuntu: Is a directory
ubuntu@VM-0-10-ubuntu:~$ cd microblog #进入microblog目录
ubuntu@VM-0-10-ubuntu:~/microblog$ ls -l #以长格式显示目录下的内容列表
total 28
drwxrwxr-x 8 ubuntu ubuntu 4096 Sep  7 19:55 app
-rw-rw-r-- 1 ubuntu ubuntu  101 Sep  7 19:55 babel.cfg
-rw-rw-r-- 1 ubuntu ubuntu  898 Sep  7 19:55 config.py
-rw-rw-r-- 1 ubuntu ubuntu  209 Sep  7 19:55 microblog.py
drwxrwxr-x 3 ubuntu ubuntu 4096 Sep  7 19:55 migrations
-rw-rw-r-- 1 ubuntu ubuntu  600 Sep  7 19:55 requirements.txt
-rw-rw-r-- 1 ubuntu ubuntu 2940 Sep  7 19:55 tests.py
ubuntu@VM-0-10-ubuntu:~/microblog$

现在将使用 git 从我的GitHub仓库下载 Microblog源代码。要将应用程序下载到服务器,请确保目前位于ubuntu用户的主目录中,然后运行如下命令:

ubuntu@VM-0-10-ubuntu:~$ git clone https://github.com/czy0905/microblog.git
Cloning into 'microblog'...
remote: Counting objects: 62, done.
remote: Compressing objects: 100% (52/52), done.
remote: Total 62 (delta 5), reused 62 (delta 5), pack-reused 0
Unpacking objects: 100% (62/62), done.
Checking connectivity... done.

ubuntu@VM-0-10-ubuntu:~$ cd microblog
ubuntu@VM-0-10-ubuntu:~$ git checkout v0.17

上述将在我的服务器上安装代码,并将其与本章同步。如果将本教程的代码版本保存在自己的git仓库中,则可以将存储仓库URL更改为自个的URL,在这种情况下可跳过 git checkout命令。

现在需要创建一个虚拟环境,并使用所有包依赖项填充它,在第15章已方便地保存到requirements.txt文件中了:

ubuntu@VM-0-10-ubuntu:~$ ls -l #列出当前主目录下的文件夹/文件
total 4
drwxrwxr-x 5 ubuntu ubuntu 4096 Sep  7 19:55 microblog
ubuntu@VM-0-10-ubuntu:~$ cd microblog #进入microblog目录
ubuntu@VM-0-10-ubuntu:~/microblog$ python3 -m venv venv #在microblog目录下建立虚拟环境
ubuntu@VM-0-10-ubuntu:~/microblog$ ls -l #列出此目录所有文件夹/文件
total 32
drwxrwxr-x 8 ubuntu ubuntu 4096 Sep  7 19:55 app
-rw-rw-r-- 1 ubuntu ubuntu  101 Sep  7 19:55 babel.cfg
-rw-rw-r-- 1 ubuntu ubuntu  898 Sep  7 19:55 config.py
-rw-rw-r-- 1 ubuntu ubuntu  209 Sep  7 19:55 microblog.py
drwxrwxr-x 3 ubuntu ubuntu 4096 Sep  7 19:55 migrations
-rw-rw-r-- 1 ubuntu ubuntu  600 Sep  7 19:55 requirements.txt
-rw-rw-r-- 1 ubuntu ubuntu 2940 Sep  7 19:55 tests.py
drwxrwxr-x 6 ubuntu ubuntu 4096 Sep  7 20:36 venv
ubuntu@VM-0-10-ubuntu:~/microblog$ cd venv
ubuntu@VM-0-10-ubuntu:~/microblog/venv$ ls -l
total 20
drwxrwxr-x 2 ubuntu ubuntu 4096 Sep  7 20:36 bin
drwxrwxr-x 2 ubuntu ubuntu 4096 Sep  7 20:36 include
drwxrwxr-x 3 ubuntu ubuntu 4096 Sep  7 20:36 lib
lrwxrwxrwx 1 ubuntu ubuntu    3 Sep  7 20:36 lib64 -> lib
-rw-rw-r-- 1 ubuntu ubuntu   69 Sep  7 20:36 pyvenv.cfg
drwxrwxr-x 3 ubuntu ubuntu 4096 Sep  7 20:36 share
ubuntu@VM-0-10-ubuntu:~/microblog/venv$ cd .. #回到上一级目录(microblog目录)
ubuntu@VM-0-10-ubuntu:~/microblog$ source venv/bin/activate #激活虚拟环境(进入虚拟环境)
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ pip install -r requirements.txt #安装依赖文件
Collecting alembic==1.0.0 (from -r requirements.txt (line 1))
  Downloading http://mirrors.tencentyun.com/pypi/packages/96/c7/a4129db460c3e0ea8fea0c9eb5de6680d38ea6b6dcffcb88898ae42e170a/alembic-1.0.0-py2.py3-none-any.whl (158kB)
    100% |████████████████████████████████| 163kB 3.0MB/s
...
...
Failed to build blinker dominate Flask-Bootstrap Flask-Login Flask-Mail guess-language-spirit itsdangerous Mako MarkupSafe python-editor SQLAlchemy visitor
Installing collected packages: six, python-dateutil, python-editor, SQLAlchemy, MarkupSafe, Mako, alembic, pytz, Babel, blinker, certifi, chardet, click, dominate, urllib3, elasticsearch, Werkzeug, itsdangerous, Jinja2, Flask, Flask-Babel, visitor, Flask-Bootstrap, Flask-Login, Flask-Mail, Flask-SQLAlchemy, Flask-Migrate, Flask-Moment, WTForms, Flask-WTF, guess-language-spirit, idna, PyJWT, python-dotenv, requests
  Running setup.py install for python-editor ... done
  Running setup.py install for SQLAlchemy ... done
  Running setup.py install for MarkupSafe ... done
  Running setup.py install for Mako ... done
  Running setup.py install for blinker ... done
  Running setup.py install for dominate ... done
  Running setup.py install for itsdangerous ... done
  Running setup.py install for visitor ... done
  Running setup.py install for Flask-Bootstrap ... done
  Running setup.py install for Flask-Login ... done
  Running setup.py install for Flask-Mail ... done
  Running setup.py install for guess-language-spirit ... done
Successfully installed Babel-2.6.0 Flask-1.0.2 Flask-Babel-0.11.2 Flask-Bootstrap-3.3.7.1 Flask-Login-0.4.1 Flask-Mail-0.9.1 Flask-Migrate-2.2.1 Flask-Moment-0.6.0 Flask-SQLAlchemy-2.3.2 Flask-WTF-0.14.2 Jinja2-2.10 Mako-1.0.7 MarkupSafe-1.0 PyJWT-1.6.4 SQLAlchemy-1.2.10 WTForms-2.2.1 Werkzeug-0.14.1 alembic-1.0.0 blinker-1.4 certifi-2018.8.24 chardet-3.0.4 click-6.7 dominate-2.3.1 elasticsearch-6.3.1 guess-language-spirit-0.5.3 idna-2.7 itsdangerous-0.24 python-dateutil-2.7.3 python-dotenv-0.9.1 python-editor-1.0.3 pytz-2018.5 requests-2.19.1 six-1.11.0 urllib3-1.23 visitor-0.1.3
You are using pip version 8.1.1, however version 18.0 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.


PS:退出虚拟环境 deactivate;删除虚拟环境 rm -r venv

除了在requirements.txt中常见的依赖,我还将使用两个包 特定于我们的生产部署,因此它们不包含在requirements.txt文件中。一个是gunicorn包,它是Python应用程序的生产Web服务器。另一个是pymysql软件包,它包含MySQL驱动程序,使SQLAlchemy能使用MySQL数据库:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ pip install gunicorn pymysql
Looking in indexes: http://mirrors.tencentyun.com/pypi/simple
Requirement already satisfied: gunicorn in ./venv/lib/python3.5/site-packages (19.9.0)
Collecting pymysql
Downloading http://mirrors.tencentyun.com/pypi/packages/a7/7d/682c4a7da195a678047c8f1c51bb7682aaedee1dca7547883c3993ca9282/PyMySQL-0.9.2-py2.py3-none-any.whl (47kB)
 100% |████████████████████████████████| 51kB 2.0MB/s
Collecting cryptography (from pymysql)
Downloading http://mirrors.tencentyun.com/pypi/packages/59/32/92cade62c645756a83598edf56289e9b19aae5370642a7ce690cd06bc72f/cryptography-2.3.1-cp34-abi3-manylinux1_x86_64.whl (2.1MB)
 100% |████████████████████████████████| 2.1MB 4.5MB/s
Requirement already satisfied: idna>=2.1 in ./venv/lib/python3.5/site-packages (from cryptography->pymysql) (2.7)
Requirement already satisfied: cffi!=1.11.3,>=1.7 in ./venv/lib/python3.5/site-packages (from cryptography->pymysql) (1.11.5)
Requirement already satisfied: six>=1.4.1 in ./venv/lib/python3.5/site-packages (from cryptography->pymysql) (1.11.0)
Requirement already satisfied: asn1crypto>=0.21.0 in ./venv/lib/python3.5/site-packages (from cryptography->pymysql) (0.24.0)
Requirement already satisfied: pycparser in ./venv/lib/python3.5/site-packages (from cffi!=1.11.3,>=1.7->cryptography->pymysql) (2.18)
Installing collected packages: cryptography, pymysql
Successfully installed cryptography-2.3.1 pymysql-0.9.2

还需要创建一个.env文件,其中包含所有必需的环境变量:
/home/ubuntu/microblog/.env:环境配置。

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ touch .env #新建文件
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ vi .env 编辑文件

接着编辑(输入如下内容。#符号内容请输入自己真实的)

SECRET=0b0299d9bc0c4e5db6196c20d6948a82
MAIL_SERVER=smtp.qq.com
MAIL_PORT=465
MAIL_USE_SSL=True
MAIL_USERNAME=##@qq.com
MAIL_PASSWORD=##
DATABASE_URL=mysql+pymysql://microblog:<密码>@localhost:3306/microblog
APPID=##
BD_TRANSLATOR_KEY=##

上述.env文件大致类似于在第15章中展示的示例,但这SECRET_KEY使用了随机字符串。为了生成此随机字符串,使用如下命令:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ python3 -c "import uuid; print(uuid.uuid4().hex)"
0b0299d9bc0c4e5db6196c20d6948a82

对于DATABASE_URL变量,定义了一个MySQL URL。将在下一小节中展示如何配置数据库。

还需要将FLASK_APP环境变量设置为应用程序的入口点 以使flask命令起作用,但在解析.env文件之前需要此变量,因此需要手动设置。为了避免每次都设置它,将其添加到账户的~/.profile文件的底部ubuntu,以便每次登陆时自动设置它:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ echo "export FLASK_APP=microblog.py" >> ~/.profile
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ flask --help
[2018-09-07 21:58:12,845] INFO in __init__: Microblog startup
Usage: flask [OPTIONS] COMMAND [ARGS]...

  A general utility script for Flask applications.

  Provides commands from Flask, extensions, and the application. Loads the
  application defined in the FLASK_APP environment variable, or from a
  wsgi.py file. Setting the FLASK_ENV environment variable to 'development'
  will enable debug mode.

    $ export FLASK_APP=hello.py
    $ export FLASK_ENV=development
    $ flask run

Options:
  --version  Show the flask version
  --help     Show this message and exit.

Commands:
  db      Perform database migrations.
  routes  Show the routes for the app.
  run     Runs a development server.
  shell   Runs a shell in the app context.

如果我退出,并重新登陆,现在FLASK_APP将为我设置。可以通过运行flask --help确认它已设置。如果帮助显示应用程序添加的translate命令,则表示已找到应用程序。

PS:上述并没有translate选项。未成功。待解决!!
解决:在腾讯云 Ubuntu,应该 set 不是export

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ echo "set FLASK_APP=microblog.py" >> ~/.profile
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ flask --help
[2018-09-07 22:26:41,190] INFO in __init__: Microblog startup
Usage: flask [OPTIONS] COMMAND [ARGS]...

  A general utility script for Flask applications.

  Provides commands from Flask, extensions, and the application. Loads the
  application defined in the FLASK_APP environment variable, or from a
  wsgi.py file. Setting the FLASK_ENV environment variable to 'development'
  will enable debug mode.

    $ export FLASK_APP=hello.py
    $ export FLASK_ENV=development
    $ flask run

Options:
  --version  Show the flask version
  --help     Show this message and exit.

Commands:
  db         Perform database migrations.
  routes     Show the routes for the app.
  run        Runs a development server.
  shell      Runs a shell in the app context.
  translate

可看到 translate命令。

现在flask 命令功能正常,我们可以编译语言翻译:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ flask translate compile
[2018-09-07 22:29:30,065] INFO in __init__: Microblog startup
compiling catalog app/translations/zh/LC_MESSAGES/messages.po to app/translations/zh/LC_MESSAGES/messages.mo

设置MySQL

在开发过程中使用的sqlite数据库非常适合简单的应用程序,但当部署一个可能需要一次处理多个请求的完整Web服务器时,最好使用更强大的数据库。处于此原因,我将建立一个MySQL数据库,我将调用`microblog`。

要管理数据库服务器,我将使用mysql命令,该命令已经安装在我的服务器上:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ mysql -u root -p
Enter password:#输入密码
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.7.23-0ubuntu0.16.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

请注意,需键入在安装MySQL时选择的MySQL root密码才能访问MySQL命令提示符。

下方命令用于 创建一个新的名为microblog的数据库,以及具有完全访问权限的同名用户:

mysql> create database microblog character set utf8 collate utf8_bin;
Query OK, 1 row affected (0.00 sec)

mysql> create user 'microblog'@'localhost' identified by '';
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on microblog.* to 'microblog'@'localhost';
Query OK, 0 rows affected (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)

mysql> quit;
Bye
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$

你将需要用一个你自己选择的密码去替换。这将是microblog数据库用户的密码,因此,最好不要跟root用户选择相同的密码(我个人为了方便记忆,是使用相同的。哈哈!)。当然,对于microblog用户的密码,需要匹配之前在.env文件中包含的DATABASE_URL变量。

如果数据库配置正确,现在可运行 创建所有表的数据库迁移:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ flask db upgrade
[2018-09-07 22:40:24,100] INFO in __init__: Microblog startup
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 1f1d69541c8c, users table
INFO  [alembic.runtime.migration] Running upgrade 1f1d69541c8c -> c0139b2ef594, posts table
INFO  [alembic.runtime.migration] Running upgrade c0139b2ef594 -> 00cd8a8ea68a, new fields in user model
INFO  [alembic.runtime.migration] Running upgrade 00cd8a8ea68a -> 65b4b5c357fa, followers
INFO  [alembic.runtime.migration] Running upgrade 65b4b5c357fa -> 2c59449fbf9a, add language to posts
(venv) ubuntu@VM-0-10-ubuntu:~/microblog$

在继续之前,请确保上述命令完成,而不会产生任何错误。

设置Gunicorn和Supervisor

当用`flask run`运行服务器时,是正在使用 Flask附带的Web服务器。这个服务器在开发期间非常有用,但它不适合用于生产服务器,因为它没有考虑到性能和稳健性。替换Flask开发服务器,对于部署来讲,在此决定使用[gunicorn](https://gunicorn.org/),它也是一个纯Python Web服务器,但与Flask不同,它是一个强大的生产服务器,很多人使用它,同时很容易上手使用。

要在gunicorn下启动Microblog,可使用下方命令:

(venv) ubuntu@VM-0-10-ubuntu:~/microblog$ gunicorn -b localhost:8000 -w 4 microblog:app
[2018-09-07 22:55:23 +0800] [23967] [INFO] Starting gunicorn 19.9.0
[2018-09-07 22:55:23 +0800] [23967] [INFO] Listening at: http://127.0.0.1:8000 (23967)
[2018-09-07 22:55:23 +0800] [23967] [INFO] Using worker: sync
[2018-09-07 22:55:23 +0800] [23970] [INFO] Booting worker with pid: 23970
[2018-09-07 22:55:23 +0800] [23971] [INFO] Booting worker with pid: 23971
[2018-09-07 22:55:23 +0800] [23972] [INFO] Booting worker with pid: 23972
[2018-09-07 22:55:23 +0800] [23973] [INFO] Booting worker with pid: 23973
[2018-09-07 22:55:25,030] INFO in __init__: Microblog startup
[2018-09-07 22:55:25,091] INFO in __init__: Microblog startup
[2018-09-07 22:55:25,097] INFO in __init__: Microblog startup
[2018-09-07 22:55:25,111] INFO in __init__: Microblog startup

上述命令中 -b选项 告知gunicorn在哪里监听请求,命令中设置为端口8000的内部网络接口。在没有外部访问的情况下运行Python Web应用程序,这通常是一个好主意;然后有一个非常快速的Web服务器,该服务器经过优化以便提供服务器静态文件 接受来自客户端的所有请求。此快速Web服务器将直接提供静态文件,并将针对应用程序的任何请求转发到内部服务器。下一小节将展示如何将nginx设置为面向公众的服务器。

-w 选项 配置gunicorn将运行的worker数量。拥有4个worker将允许应用程序同时处理多达4个客户端,对于Web应用程序而言通常足以处理大量客户端,因为并非所有客户端都在不断地请求内容。根据服务器的RAM大小,可能需要调整worker数量,以免内存不足。

microblog:app参数告诉gunicorn如何加载应用程序实例。冒号前的名称是 包含应用程序的模块;冒号后的名称是这个应用程序的名称。

虽然gunicorn设置非常简单,但从命令行运行服务器 实际上并不是生产服务器的好解决方案。我想要的是 让服务器在后台运行,并让它在持续监控下,因为如果由于任何原因服务器崩溃并退出,我想确保自动启动新服务器以取代它。而且我还想确保 如果重新启动计算机,服务器会在启动时自动运行,而无需我自己登录和启动。要做到以上几点,就可以使用上方安装的supervisor包来完成这些操作。

supervisor效用 使用配置文件来告诉它要监视哪些程序、以及在必要时如何重启启动它们。配置文件必须存储在/etc/supervisor/conf.d中。这是Microblog的配置文件,将其称为 microblog.conf
/etc/supervisor/conf.d/microblog.conf:supervisor配置

ubuntu@VM-0-10-ubuntu:~$ cd /etc/supervisor/conf.d
ubuntu@VM-0-10-ubuntu:/etc/supervisor/conf.d$ sudo touch microblog.conf #要加上sudo。新建这个.conf文件
ubuntu@VM-0-10-ubuntu:/etc/supervisor/conf.d$ ls -l
total 0
-rw-r--r-- 1 root root 0 Sep  8 16:23 microblog.conf
ubuntu@VM-0-10-ubuntu:/etc/supervisor/conf.d$ sudo vi microblog.conf #要加上sudo。编辑文件

sudo vi microblog.conf编辑内容如下:

[program:microblog]
command=/home/ubuntu/microblog/venv/bin/gunicorn -b localhost:8000 -w 4 microblog:app
directory=/home/ubuntu/microblog
user=ubuntu
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true

commanddirectoryuser 设置告诉supervisor如何运行应用程序。当计算机开机或崩溃时,autostartautorestart设定了自动重启。stopasgroupkillasgroup用来确保当supervisor需要去停止应用程序去重新启动它,它也达到了gunicorn进程的子进程。

在编写完这个配置文件后,必须重新加载supervisor服务 用于导入它:

ubuntu@VM-0-10-ubuntu:/etc/supervisor/conf.d$ sudo supervisorctl reload
Restarted supervisord
ubuntu@VM-0-10-ubuntu:/etc/supervisor/conf.d$

就这样,gunicorn Web服务器应该会启动 并运行和监控了。

设置Nginx

由gunicorn提供支持的Microblog应用程序服务器现在私有地运行端口`8000`。将应用程序暴露给外部世界 现在需要做的是 在端口`80`和`443`上启用面向公众的Web服务器,这是我在防火墙打开的两个端口来处理应用程序的Web流量。

我希望这是一个安全的部署,因此我将配置端口80以将所有流量转到将要加密的端口443。所以我首先将创建一个SSL证书。现在要创建一个自签名SSL证书,可以测试所有单不适合实际部署,因为Web浏览器会警告用户证书不是由受信任的证书颁发机构颁发的。给Microblog创建SSL证书的命令是:

ubuntu@VM-0-10-ubuntu:~/microblog$ openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -keyout certs/key.pem -out certs/cert.pem
Generating a 4096 bit RSA private key
..................................................................++
...............++
writing new private key to 'certs/key.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CH
State or Province Name (full name) [Some-State]:GuangDong
Locality Name (eg, city) []:ShenZhen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:CYG
Organizational Unit Name (eg, section) []:Test
Common Name (e.g. server FQDN or YOUR name) []:Yankeen
Email Address []:<填写你自己的>@qq.com
ubuntu@VM-0-10-ubuntu:~/microblog$ cd certs
ubuntu@VM-0-10-ubuntu:~/microblog/certs$ ls -l
total 8
-rw-rw-r-- 1 ubuntu ubuntu 2098 Sep  8 17:00 cert.pem
-rw-rw-r-- 1 ubuntu ubuntu 3272 Sep  8 17:00 key.pem
ubuntu@VM-0-10-ubuntu:~/microblog/certs$

这个命令将询问有关你的应用程序和自己的一些信息(国家、省份、城市、公司名称、姓名等)。这些将是包含在SSL证书中的信息,如果用户请求查看,则会向用户显示这些信息。上述命令的结果是 生成两个名为 cert.pemkey.pem的文件,它放在Microblog根目录certs子目录中。

要使网站由nginx提供服务,需要为其编写配置文件。在大多数nginx安装中,此文件需要位于/etc/nginx/sites-enabled目录中。Nginx在这个位置安装了一个我不需要的测试站点,所以我将首先删除它:

ubuntu@VM-0-10-ubuntu:~/microblog/certs$ cd /etc/nginx/sites-enabled
ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ sudo rm /etc/nginx/sites-enabled/default
ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ ls -l
total 0

下方将看到Microblog的nginx配置文件,它位于/etc/nginx/sites-enabled/microblog中:
/etc/nginx/sites-enabled/microblog:Nginx配置

ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ sudo touch microblog #新建文件
ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ ls -l
total 4
-rw-r--r-- 1 root root    0 Sep  8 17:16 microblog
ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ sudo vi microblog #编辑文件
ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$

文件内容如下:

server {
    # listen on port 80 (http)
    listen 80;
    server_name _;
    location / {
        # redirect any requests to the same URL but on https
        return 301 https://$host$request_uri;
    }
}
server {
    # listen on port 443 (https)
    listen 443 ssl;
    server_name _;

    # location of the self-signed SSL certificate
    ssl_certificate /home/ubuntu/microblog/certs/cert.pem;
    ssl_certificate_key /home/ubuntu/microblog/certs/key.pem;

    # write access and error logs to /var/log
    access_log /var/log/microblog_access.log;
    error_log /var/log/microblog_error.log;

    location / {
        # forward application requests to the gunicorn server
        proxy_pass http://localhost: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;
    }

    location /static {
        # handle static files directly, without forwarding to the application
        alias /home/ubuntu/microblog/app/static;
        expires 30d;
    }
}

nginx配置 远远不是微不足道,上述添加了一些注释,以便知道每个部分的作用。如果想获得有关特定指令的信息,可参阅nginx官方文档。

添加这个文件后,需要告诉nginx重新加载配置以激活它:

ubuntu@VM-0-10-ubuntu:/etc/nginx/sites-enabled$ sudo service nginx reload

现在应用程序应该已成功部署。在Web浏览器中,键入服务器IP地址(公网IP。如果使用的是Vagrant VM,则输入192.168.33.10)并将连接到应用程序。由于使用的是自签名证书,因此将从Web浏览器收到警告,你可以忽略它。

在完成部署后,请按照自己项目的上述说明进行操作,强烈建议将自签名证书替换为 真实证书以便浏览器不会警告你的用户的站点。为此,首先需要购买域名,并将其配置为指向服务器的IP地址。拥有域名后,可申请免费的Let’s Encrypt SSL证书。在作者博客有一篇关于如果通过HTTPS运行Flask应用程序的详细文章。
效果:
17 Flask mega-tutorial 第17章 在Linux上部署(腾讯云 Ubuntu)【极其详细的部署过程】_第2张图片

部署应用程序更新

关于 基于Linux的部署 的最后一个主题是 如何处理应用程序升级。应用程序源代码通过`git`安装在服务器中,因此,只要我想将应用程序升级到最新版本,只需运行`git pull`命令去下载 自上次部署以来所做的新提交。

但是,当然,仅是下载新版本的代码并不会促使升级。当前正在运行的服务器进程将继续使用旧代码运行,旧代码已经读取并保存在内存中。要触发升级,必须停止当前服务器,并启动一个新服务器,以强制在此读取所有代码。

运行升级通常比重新启动服务器更复杂。可能需要运用数据库迁移或编译新的语言翻译,因此实际上,执行升级的过程涉及一系列命令:

(venv) $ git pull                              # download the new version
(venv) $ sudo supervisorctl stop microblog     # stop the current server
(venv) $ flask db upgrade                      # upgrade the database
(venv) $ flask translate compile               # upgrade the translations
(venv) $ sudo supervisorctl start microblog    # start a new server

Raspberry Pi Hosting 树莓派主机

树莓派 是一个具有非常低的功耗低成本的革命性的小太Linux计算机,因此它是主机,可以每天24小时在线而不会占用我们的桌面电脑或笔记本电脑的基于Web服务器的理想设备。有几个Linux发行版在树莓派上运行。作者的选择是 [Raspbian](http://www.raspbian.org/),它是Raspberry Pi Foundation的官方发行版。

为了准备 树莓派,安装一个新的 Raspbian版本。使用2017年9月版的Raspbian Stretch Lite,现在可能有更新的版本,可查看官方下载页面获取最新版本。

Raspbian映像需要安装在SD卡上,然后将其插入Raspberry Pi,以便它可以随机启动。Raspberry Pi网站上提供了将Raspbian映像从Windows,Mac OS X和Linux复制到SD卡的说明。

第一次启动Raspberry Pi时,请在连接到键盘和显示器时执行此操作,以便可以进行设置。至少应启用SSH,以便可以从计算机登录以更舒适地执行部署任务。

像Ubuntu一样,Raspbian是Debian的衍生产品,因此上面针对Ubuntu Linux的说明大部分都适用于Raspberry Pi。但是,如果计划在家庭网络上运行小型应用程序而无需外部访问,则可以决定跳过某些步骤。例如,可能不需要防火墙或无密码登录。可能想在这么小的计算机上使用SQLite而不是MySQL。可以选择不使用nginx,只需让gunicorn服务器直接监听来自客户端的请求即可。可能只想要一个gunicorn worker。supervisor服务 在确保应用程序始终处于运行状态时非常有用,因此建议也在Raspberry Pi上使用它。

参考:
作者博客
源代码

如需转载请注明出处。

你可能感兴趣的:(Python,3.X,flask,Flask,mega-tutorial,腾讯云,Ubuntu,linux,部署,python)