赞
踩
对于非常小的项目,“手动”部署代码是可行的,就是通过远程shell 手动输入安装新
版代码所必需的一系列命令,并在远程shell 中执行。不管怎样,即使是中等大小的项目,
这种方法也是容易出错的、乏味的,并且会浪费你最珍贵的资源——你自己的时间。
解决方案就是自动化。简单的经验法则就是,如果你需要手动执行相同的任务至少两
次,那么你应该将它自动化,这样你就不用再做第三次了。有各种工具可以让你将各种事
情自动化。
● 远程执行工具(例如Fabric),用来按需求自动执行多台远程主机上的代码。
● 配置管理工具(例如Chef、Puppet、CFEngine、Salt 和Ansible),用来对远程主机
(执行环境)进行自动化配置。它们可用于设置后端服务(数据库、缓存等)、系统
权限、用户等等。大多数这种工具还可以当作像Fabric 一样的远程执行工具,但
根据架构不同,其难易程度也不同。
配置管理解决方案是一个复杂的话题,值得单独用一本书介绍。事实上,最简单的远
程执行框架的门槛最低,它也是最常见的选择,至少对小型项目来说是这样。实际上,每
种提供了声明式指定机器配置方法的配置管理工具都在深层某处实现了远程执行层。
此外,由于一些工具的设计,它可能并不是最适合实际的自动化代码部署。一个这样
的例子是Puppet,它阻止显式地运行任何shell 命令。这就是许多人选择使用两种解决方案
来互相补充的原因:配置管理工具用于设置系统级的环境,按需的远程执行工具用于应用
部署。
迄今为止,Fabric(http://www.fabfile.org/)是Python 开发者用于自动化远程执行的最
常用的解决方案。它是一个Python 库,也是一个命令行工具,用来提高使用SSH 进行应
用部署或系统管理的效率。我们将重点介绍它,因为它相对容易上手。注意,它对于你的
问题可能并不是最佳解决方案,这取决于你的需求。不管怎样,如果你还没有任何自动化
的实用程序,它是能够在运营中实现自动化的很好的实用程序例子。
Fabric 与Python 3
本书鼓励你只用Python 3 进行开发(如果可能的话),同时
给出有关旧版语法特性和兼容性注意事项的说明,只是为
了使最终的版本切换更加容易。不幸的是,在写作本书时,
Fabric 仍然没有正式移植到Python 3。这个工具的粉丝至少
在几年前就被告知,Fabric 2 正在持续开发以引入兼容性更
新。据说是添加许多新功能的完全重写,但Fabric 2 没有官
方的开放仓库,几乎没有人见过其代码。在Fabric 项目的
当前开发分支中,其核心开发人员不接受任何与Python 3
兼容有关的合并请求(pull request),并关闭所有相关的功
能请求。对流行开源项目的这种开发方法是最令人不安的。
基于这个问题的历史,我们不太可能很快看到Fabric 2 的官
方发布。新的Fabric 版本的这种秘密开发引发了许多问题。
不考虑其他人的观点,这一事实并没有降低Fabric 当
前状态的有用性。因此,如果你已经决定坚持使用
Python 3,那么有两个选择:使用完全兼容和独立的派
生(https://github.com/mathiasertl/fabric/),或者用Python
3 编写应用并且用Python 2 维护Fabric 脚本。最好的方
法是在单独的代码库中这么做。
你当然可以只用Bash 脚本将所有工作自动化,但这是非常乏味的,而且容易出错。Python
有更方便的字符串处理方法,并鼓励代码模块化。事实上,Fabric 只是利用SSH 将命令执行连
在一起的工具,所以你仍然需要知道命令行界面及其实用程序在你的环境中的工作方式。
要开始使用Fabric,你需要安装fabric 包(使用pip),并创建一个名为fabfile.py
的脚本,它通常位于项目根目录中。注意,fabfile 可以被看作是项目配置的一部分。因
此,如果你想严格遵守十二要素应用的方法论,那么你不应该在所部署应用的源代码树中
维护其代码。事实上,复杂的项目通常是从作为独立代码库维护的各种组件中构建的,因
此这也是最好所有项目组件配置和Fabric 脚本有一个单独的仓库的另一个原因。这使得不
同服务的部署更加一致,也鼓励重复使用优秀的代码。
一个定义了简单部署过程的fabfile 示例如下所示:
import os
from fabric.api import * # noqa
from fabric.contrib.files import exists
PYPI_URL = ‘http://devpi.webxample.example.com’
#.
REMOTE_PROJECT_LOCATION = “/var/projects/webxample”
env.project_location = REMOTE_PROJECT_LOCATION
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’)
run(
“ln -fsT {target} {symlink}”
“”.format(target=new_version_path, symlink=temporary)
)
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):
run(‘python3 -m venv {}’.format(version
run(“{} install webxample=={} --index-url {}”.format(
pip_path, version, PYPI_URL
))
switch_versions(version)
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 在远程主机上进行进程管理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。