Python 高手编程系列一千零五十三:十二要素应用

无痛部署的主要要求是确保构建应用的过程尽可能简单和流畅。这主要是清除障碍并鼓励成熟的做法。在有些组织中,只有特定的人负责开发(开发团队,Dev),而
不同的人负责部署和维护执行环境(运营团队,Ops),那么遵守这些常见做法就特别
重要。
与服务器维护、监控、部署、配置等相关的所有任务都统称为运营(operations)。即
使在某些组织中没有单独的运营团队,通常也只有一部分开发人员被授权执行部署任务并
维护远程服务器。这一职位的通用名称是 DevOps。此外,开发团队的每名成员都负责运营
也很常见,所以在这样的团队中每个人都被称为 DevOps。不管怎样,无论你的组织结构是
什么样的,无论每名开发人员的职责是什么,每个人都应该知道如何运营以及如何将代码
部署到远程服务器,这是因为最终看来,执行环境及其配置都是你正在构建的产品的隐藏
部分。
接下来介绍的这些常见做法和约定非常重要,其主要原因如下。
● 在每家公司都有人离职并有新人加入。利用最佳方法,新的团队成员更容易上手项
目。你永远不能保证新员工已经熟悉系统配置和可靠地运行应用的常见做法,但至
少可以让他们更快速地适应。
● 如果组织中只有一部分人负责部署,那么这些做法可以减少运营团队和开发团队之
间的摩擦。
鼓励构建易于部署的应用的这种做法有一个非常好的来源,就是叫作十二要素应用
(Twelve-Factor App)的宣言。它是构建“软件即服务”应用的一种通用的与语言无关的方
法论。其目的之一就是让应用部署更加简单,但它同时也强调其他主题,例如可维护性和
让应用更容易扩展。
从名字中可以看出,十二要素应用包含 12 条规则。
● 代码库(codebase):版本控制追踪一份代码库,多份部署。
● 依赖(dependencies):显式声明和隔离依赖关系。
● 配置(config):在环境中存储配置。
● 后端服务(backing services):将后端服务作为附加资源。
● 构建、发布、运行(build、release、run):严格分离构建和运行阶段。
● 进程(processes):以一个或多个无状态进程运行应用。
● 端口绑定(port binding):通过端口绑定提供服务。
● 并发(concurrency):通过进程模型进行扩展。
● 易处理(disposability):快速启动和优雅终止可最大化鲁棒性。
● 开发环境与生产环境等价(dev/prod parity):尽可能的保持开发、预发布和生产环
境相同。
● 日志(logs):把日志当作事件流。

● 管理进程(admin processes):将后台管理任务当作一次性进程运行。
在这里将每一条规则详细展开似乎没什么意义,因为十二要素应用方法论的官方页面
(https://12factor.net/)对每个应用要素都包含大量解释,还有不同框架和环境的工具示例。
本章尽量与上述宣言保持一致,必要时我们将会详细讨论其中某些要素。本章给出的
技术和示例有时可能与这 12 个要素略有不同,但请记住,这些规则并不是一成不变的
(carved in stone)。只要能够实现目的,那么它们就是好的。最后,重要的是工作应用(产
品)而不是与某种任意的方法论兼容。
用 Fabric 进行自动化部署
对于非常小的项目,“手动”部署代码是可行的,就是通过远程 shell 手动输入安装新
版代码所必需的一系列命令,并在远程 shell 中执行。不管怎样,即使是中等大小的项目,
这种方法也是容易出错的、乏味的,并且会浪费你最珍贵的资源——你自己的时间。
解决方案就是自动化。简单的经验法则就是,如果你需要手动执行相同的任务至少两
次,那么你应该将它自动化,这样你就不用再做第三次了。有各种工具可以让你将各种事
情自动化。
● 远程执行工具(例如 Fabric),用来按需求自动执行多台远程主机上的代码。
● 配置管理工具(例如 Chef、Puppet、CFEngine、Salt 和 Ansible),用来对远程主机
(执行环境)进行自动化配置。它们可用于设置后端服务(数据库、缓存等)、系统
权限、用户等等。大多数这种工具还可以当作像 Fabric 一样的远程执行工具,但
根据架构不同,其难易程度也不同。
配置管理解决方案是一个复杂的话题,值得单独用一本书介绍。事实上,最简单的远
程执行框架的门槛最低,它也是最常见的选择,至少对小型项目来说是这样。实际上,每
种提供了声明式指定机器配置方法的配置管理工具都在深层某处实现了远程执行层。
此外,由于一些工具的设计,它可能并不是最适合实际的自动化代码部署。一个这样
的例子是 Puppet,它阻止显式地运行任何 shell 命令。这就是许多人选择使用两种解决方案
来互相补充的原因:配置管理工具用于设置系统级的环境,按需的远程执行工具用于应用
部署。
迄今为止,Fabric(http://www.fabfile.org/)是 Python 开发者用于自动化远程执行的最
常用的解决方案。它是一个 Python 库,也是一个命令行工具,用来提高使用 SSH 进行应
用部署或系统管理的效率。我们将重点介绍它,因为它相对容易上手。注意,它对于你的
问题可能并不是最佳解决方案,这取决于你的需求。不管怎样,如果你还没有任何自动化
的实用程序,它是能够在运营中实现自动化的很好的实用程序例子。
你当然可以只用Bash 脚本将所有工作自动化,但这是非常乏味的,而且容易出错。Python
有更方便的字符串处理方法,并鼓励代码模块化。事实上,Fabric 只是利用 SSH 将命令执行连
在一起的工具,所以你仍然需要知道命令行界面及其实用程序在你的环境中的工作方式。
要开始使用 Fabric,你需要安装 fabric 包(使用 pip),并创建一个名为 fabfile.py
的脚本,它通常位于项目根目录中。注意,fabfile 可以被看作是项目配置的一部分。因
此,如果你想严格遵守十二要素应用的方法论,那么你不应该在所部署应用的源代码树中
维护其代码。事实上,复杂的项目通常是从作为独立代码库维护的各种组件中构建的,因
此这也是最好所有项目组件配置和 Fabric 脚本有一个单独的仓库的另一个原因。这使得不
同服务的部署更加一致,也鼓励重复使用优秀的代码。
一个定义了简单部署过程的 fabfile 示例如下所示:

-- coding: utf-8 --

import os
from fabric.api import * # noqa
from fabric.contrib.files import exists

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

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):
“”“通过原子级地(atomically)替换符号链接来切换版本。”“”
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 确保该操作的原子性(atomicity)

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
Available commands:
deploy Deploy application with packaging in mind
uptime Run uptime command on remote host - for testing connection.
现在你只有一个 shell 命令就可以将应用部署到给定的环境类型中:
$ fab –R production deploy
注意,前面的 fabfile 只是为了便于说明。在你自己的代码中,你可能要提供大量
的故障处理,并尽量无需重启 web worker 进程就可以重新加载应用。此外,这里介绍的某
些技术可能现在看起来显而易见,但本章后面将对其详细解释。这些技术包括:
● 使用私有包仓库来部署应用。
● 使用 Circus 在远程主机上进行进程管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值