python高级编程代码_Python高级编程-(Part 6 部署代码)

此系列是《Python高级编程》的笔记,根据个人知识水平整理。

本节主要关注将代码部署到远程主机方面的内容。

6.1 十二要素应用

鼓励构建易于部署的应用的这种做法有一个非常好的来源,叫做十二要素应用。是构建“软件即服务”应用的一种通用的方法论。十二要素应用包含12条规则:代码库:版本控制追踪一份代码库,多份部署

依赖:显示声明和隔离依赖关系

配置:在环境中存储配置

后端服务:将后端服务作为附加资源

构建、发布、运行:严格分离构建和运行阶段

进程:以一个或多个无状态进程运行应用

端口绑定:通过绑定端口提供服务

并发:通过进程模型进行扩展

易处理:快速启动和优雅中止可最大化鲁棒性

开发环境与生产环境等价:尽可能保持开发、预发布和生产环境相同

日志:把日志当作事件流

管理进程:将后台管理任务当作一次性进程运行

6.2 Fabric自动化部署

判断是否要自动化部署的简单规则是:如果需要手动执行相同任务至少2次,那么它应该自动化,避免手动做第三次。以下工具可以让你将各种事情自动化:远程执行工具(如Fabric),用来按需自动执行多台远程主机上的代码

配置管理工具(Chef、Puppet、CFEngine)用来对远程主机进行自动化配置。设置后端服务、系统权限等

Fabric是python开发者用于自动化执行的最常用解决方案,用来提供使用ssh进行应用部署或系统管理的效率。要开始使用Fabric,需要安装fabric包,并创建一个fabfile.py的脚本,其通常位于项目根目录中。一个简单部署过程的fabfile示例如下所示:

# -*- coding: utf-8 -*-

import os

from fabric.api import * # noqa

from fabric.contrib.files import exists

# 假设我们用‘devpi’创建了一个私有包仓库

# using 'devpi' project

PYPI_URL = 'http://devpi.webxample.example.com'

# 这是用于保存已安装版本的任意位置

# 每个版本都是独立的虚拟环境目录,以版本命名

# 还有一个指向最近部署版本的符号链接‘current’

# 这个符号链接是用于配置进程管理工具的实际路径。例如:

# .

# ├── 0.0.1

# ├── 0.0.2

# ├── 0.0.3

# ├── 0.1.0

# └── current -> 0.1.0/

REMOTE_PROJECT_LOCATION = "/var/projects/webxample"

env.project_location = REMOTE_PROJECT_LOCATION

# roledefs 映射环境类型(预发布环境/生产环境)

env.roledefs = {

'staging': [

'staging.webxample.example.com',

],

'production': [

'prod1.webxample.example.com',

'prod2.webxample.example.com',

],

}

def prepare_release():

""" 通过创建源代码发行版并将其上传至私有包仓库来准备新版本"""

local('python setup.py build sdist upload -r {}'.format(

PYPI_URL

))

def get_version():

""" 从setuptools获取当前项目版本 """

return local(

'python setup.py --version', capture=True

).stdout.strip()

def switch_versions(version):

""" 通过替换符号链接来切换版本 """

new_version_path = os.path.join(REMOTE_PROJECT_LOCATION, version)

temporary = os.path.join(REMOTE_PROJECT_LOCATION, 'next')

desired = os.path.join(REMOTE_PROJECT_LOCATION, 'current')

# 强制使用符号链接(-f) 因为可能已经有一个了

run(

"ln -fsT {target} {symlink}"

"".format(target=new_version_path, symlink=temporary)

)

# mv -T 确保该操作地原子性

run("mv -Tf {source} {destination}"

"".format(source=temporary, destination=desired))

@task

def uptime():

"""在远程主机上运行uptime命令--用于测试连接"""

run("uptime")

@task

def deploy():

""" 用来打包部署应用 """

version = get_version()

pip_path = os.path.join(

REMOTE_PROJECT_LOCATION, version, 'bin', 'pip'

)

prepare_release()

if not exists(REMOTE_PROJECT_LOCATION):

# 在新主机上的初次部署,它可能不存在

run("mkdir -p {}".format(REMOTE_PROJECT_LOCATION))

with cd(REMOTE_PROJECT_LOCATION):

# 使用venv创建新的虚拟环境

run('python3 -m venv {}'.format(version))

run("{} install webxample=={} --index-url {}".format(

pip_path, version, PYPI_URL

))

switch_versions(version)

# 假设circus是我们选择的进程管理工具

run('circusctl restart webxample')

每个用@task装饰的函数都被看作与fabric包一起提供的fab实用程序的可用子命令。可以使用-l或-list开关列出所有可用的子命令:

$ fab --list

最后只需要一个shell命令就可以将应用部署到给定的环境类型中:

$ fab -R production deploy

6.3 你自己的包索引或索引镜像

官方python包索引没有可用性包证。如果PyPI出现故障,或者网络连接不稳定都会中止部署。

6.3.1 PyPI镜像

官方的python包索引是自带镜像的,但却无法避免在某些时候下载依旧会出现问题。最好的解决方案是使用自己的pypi镜像,里面包含所有需要的包。另外当服务停机时,你不需要依赖他人重启服务。书中推荐使用devpi工具,它可以提供:上传非公开包的私有索引

索引镜像

devpi可以维护客户端已经请求的包组成的镜像,而不是对整个仓库进行备份。当安装工具请求一个包时,如果这个包不在本地镜像,则从pypi中下载并提供。一旦包下载完后,devpi将定期检查其更新,以保持镜像的最新状态。

6.3.2 使用包部署

现代web应用包含大量的依赖,通常需要很多步骤才能在远程主机上安装。典型的引导过程包括:创建新的虚拟环境

将代码移到指定位置

安装项目依赖

同步或迁移数据库模式

从项目源代码或外部包收集静态文件并放在所需位置

为不同语言的应用编译本地文件

......

在安装过程中还需要保证网络连接的稳定。如果需要部署到多台服务器,则需要耗费大量精力,这显然适合使用自动化,但应该在正确的地方和时间进行。类似静态收集和代码预处理的大多数事情都可以在本地或专用环境中完成,素养部署到远程服务器的实际代码只需要少量的现场处理。在构建一个发行版或安装一个包的过程中,最值得注意的部署步骤如下:安装python依赖,并将静态资产移动到所需位置。这两步可以作为setup.py脚本install命令的一部分来处理

预处理代码与诸如将文本(多语言等)编译本地化之类的操作都可以作为setup.py脚本sdist/bdist命令的一部分。

利用正确的http://MANIFEST.in文件,可以轻松处理python之外的预处理代码。

6.4 常见约定与实践

6.4.1文件系统层次结构

文件系统层次结构标准(FHS)定义了Unix和类似Unix系统中目录结构和目录内容,但很难找到一个真正的OS发行版与FHS完全兼容。唯一的建议如下:明智选择,避免出现意外

在项目所有可用的基础设施中保持一致

尽量在组织内部保持一致

真正有用的是将项目约定文档化,让参与项目的所有人都知道这份文档的存在。

6.4.2 隔离

在项目中,应当始终隔离每个应用版本的项目依赖。在实践中,无论何时部署应用的新版本,都应该为这个版本创建一个新的隔离环境。旧环境应该保留一段时间,保证在出问题时可以轻松回滚到应用的某个历史版本。

6.4.3 使用进程管理工具

在远程主机上可以使用nohup,screen,tmux等半守护进程。但更好的方式是使用某种进程管理工具。此类工具需要具有以下功能:如果服务退出则重启服务

可靠地跟踪其状态

捕获输入输出流用于日志

运行具有特定用户权限的进程

配置系统环境变量

python社区中,管理应用进程的两个常用工具是supervisor和circus。具体方法读者可以自行了解

6.4.4 在用户空间运行应用代码

应当始终在用户空间运行代码而不是超级用户权限下运行。按照12要素应用的方法设计应用,那么可以在几乎没有任何权限的用户下运行应用。在Linux中,同一用户组的进程可以互相交互,所有在用户层面将不同应用分离式很重要的。

6.4.5 使用HTTP反向代理

许多符合WSGI的python web服务器自身可以处理HTTP流量。但将他们隐藏在反向代理(如nginx)的后面也是很常见的。原因包括:顶层web服务器(如nginx和apache)通常可以很好处理TLS/SSL终止。python应用可以只使用简单http协议,从而将安全通信信道的复杂性和配置都留给反向代理

非特权用户不能绑定较小的端口,但http协议应该在80端口为用户服务,https协议应该在443端口服务。

nginx可以比python代码更高效的提高静态资源

如果单一主机需要服务于来自不同域的多个应用,那么apache或nginx是不可或缺的。

反向代理可以通过添加额外的缓存层来提高性能

6.4.6 优雅地重新加载进程

快速地启动时间和优雅地中止将鲁棒性最大化,对于web应用,如果以不优雅地方式中止服器进程,那么他会立刻推出,没有时间来处理请求和已经连接地客户端地响应回复。所以还需要执行一个额外地步骤:在旧地工作进程优雅退出时启动能够接受新连接地新工作进程。目前最流行地工具是Gunicorn和uWSGI。在接受到sighup信号后,gunicorn的主进程将启动新的工作进程并尝试让旧的工作进程优雅的退出

uWSGI至少有3种独立的方案来进行优雅地重新加载。

6.5 代码检测与监控

为了确保产品按预期工作,我们需要正确处理应用日志并监控必要地应用指标。通常包括:监控web应用访问日志的各种HTTP状态码

进程日志集合,其中可能包含有关运行错误的各种警告信息

在运行应用的远程主机上监控系统资源。

监控作为业务绩效指标的应用级性能和指标

目前有许多工具可用于检测代码并监控性能。其中大多数都很容易继承。

最后欢迎大家关注我的个人订阅号:deeptrial_lab 。获取《python高级编程(第二版)》高清PDF版以及代码,请在订阅号中回复 "python高级编程"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值