其实在Glow的技术团队中是没有全职的Ops或是Sys admin,我想很多小的创业团队也是如此。但是运维是整个产品发布过程中必不可少的一环,所以想写一个针对开发工程师(特别是Python工程师)的运维入门教程。如果你是专业的运维工程师,请不要浪费你自己的时间。
先说一下,什么是“轻量化运维”?简而言之,就是用最快最省事的方法做好最基本的运维工作。这里的工作主要包括以下几个部分
今天先来聊聊服务器的日常管理。这里包括各种琐碎的任务,例如重启服务,安装或是更新软件包,备份日志文件或是数据库等等。通常对于这类任务,我们要解决两个问题
如果你碰巧对Python略知一二,那么恭喜你,从此以后你只要使用Fabric这个神器,就再不用为Shell脚本头痛了。
Fabric可以通过pip来安装
pip install fabric
它的功能是将一个任务通过ssh在多台服务器上执行,而每个任务可以是单条shell指令或是一段python脚本。一个最基本的例子
fab -H web0,web1 -- sudo apt-get update
在web0和web1两台机器上以root来运行apt-get update
指令。当然前提是,当前用户可以通过本机ssh到web0和web1两台机器。如果你嫌一台一台服务器按序执行太慢,你可以加上-P
参数,让所有服务器同时执行。
在之前的例子中,我们已经知道Fabric可以在多台服务器上执行任务。但当服务器数量较多时,手动指定一组服务器就比较麻烦了。Fabric提供了Role的概念,你可以将一组功能相同的服务器定义为一个Role,Role的定义需要写在名为fabfile.py
文件里,fabric
在执行时会默认读取当前目录下的fabfile.py
文件,例如:
from fabric.api import envenv.roledefs = { 'web': ['web%d.example.com' % i for i in xrange(10)], 'db': ['db%d.example.com' % i for i in xrange(4)]}
这里我们定义了web
和db
两个Role,其中web
包括了web0.example.com到web9.example.com共10台服务器,db
包括了4台服务器。例如,我们需要在所有的web服务器上安装nginx,在所有的db服务器上安装mysql,则只需下面两行命令
fab -P -R web -- sudo apt-get -y install nginx fab -P -R db -- sudo apt-get -y install mysql-server
这里用-P
也使得安装过程在这些服务器上并行执行。
单条指令能做的事情非常有限,Fabric中可以定义任务。通常一个任务对应于fabfile.py
中的一个函数方法,配合Fabric自身提供的API,可以对远程的服务器执行一组指令。既可以保留Shell指令简小精悍的优点,又不失Python语言出色的可读性。我们来看一个代码发布的例子。
在这个例子中,我们假设目标服务器上已经有代码的git repo,并且我们已经为将要部署的代码生成了tag并push到了remote。整个代码发布的流程如下,
import requests from fabric.api import task, sudo, prompt@taskdef deploy(tag): """ Deploy new code version and reload the webserver Version: 1.0 """ with cd('/repos/example'): sudo('git diff --stat HEAD..{}'.format(tag)) if not prompt('Does the code diff look good to you? [y/N]').lower() == 'y': print 'Abort' return sudo('git clean -xdf') sudo('git fetch --all') sudo('git checkout {}'.format(tag)) sudo('supervisorctl restart webserver') resp = requests.get('http://www.example.com/ping') print 'Web server health check: {}'.format('OK' if resp.status_code == 200 else 'FAILED')
用下面的命令来执行该任务
fab -H web0.example.com deploy:v0.1.0
以上的代码看上去还不错,但如果你需要在多台服务器上部署代码的话,则会碰到一些问题。比如code diff和http request都会被执行多次,而实际上它们只需要被执行一次。在下面的版本中我们用到了Fabric的execute
方法,它可以在一个任务中调用另一个任务,并指定在哪些服务器上执行这个子任务。以下是改进后的版本,
import requests import sys from fabric.api import task, sudo, prompt@taskdef deploy(tag): """ Deploy new code version and reload the webserver Version: 2.0 """ execute(check_code_diff, hosts=['web0.example.com']) execute(update_code, roles=['www']) execute(restart_webserver, roles=['www']) resp = requests.get('http://www.example.com/ping') print 'Web server health check: {}'.format('OK' if resp.status_code == 200 else 'FAILED')@taskdef check_code_diff(tag): with cd('/repos/example'): sudo('git diff --stat HEAD..{}'.format(tag)) if not prompt('Does the code diff look good to you? [y/N]').lower() == 'y': sys.exit(1)@task@paralleldef update_code(tag): sudo('git clean -xdf') sudo('git fetch --all') sudo('git checkout {}'.format(tag) @task@parallel(pool_size=4)def restart_webserver(): sudo('supervisorctl restart webserver')
执行该任务时不需要指定服务器,因为已经在任务代码中指定了。、
fab deploy:v0.1.0
这个版本解决了上面提到的两个问题。另外值得注意的是update_code
可以在所有服务器上并行执行,但我们不能对所有的服务器同时重启webserver,这样做会使得整个网站在短时间内无法响应任何请求。在这个例子中我们一共有10台服务器,将@parallel(pool_size=4)
保证同一时间最多只有4台服务器在重启webserver进程,确保了发布过程中web服务的可用性。
Fabric是将Python, Shell和SSH的功能很优雅地结合在了一起,同时自身又非常的轻量,适合大部分服务器群的日常管理工作。下次和大家分享一个更重量级的武器Ansible,它的强项在于多环境下服务器的自动化配置,用同一套代码管理development, sandbox和production环境。
联系客服