Fabric学习
[toc]
总结
fabric3 移除了很多实用的功能和装饰器,变得更精简了,另外fab这个cli入口提供的参数能力也变弱了,目前个人实用的方式是typer+fabric3+makefile:
- typer 作为参数解析入口
- makefile 固定一些操作逻辑,可以使用它的并发操作,而不是ThreadingGroup
Link
What is Fabric
python的一个high level的库,通过ssh执行shell命令。
基于以下两个包构建的:
- Invoke,subprocess command execution and command-line features
- Paramiko,SSH protocol implementation
私钥配置
- 配置ssh的authorized_keys,将本机的id_rsa.pub信息复制到远程的authorized_keys文件中
简要用法
- pty(prompt by hand),如果sudo有密码,那么用pty来手动输入
>>> from fabric import Connection
>>> c = Connection('192.168.9.139')
>>> c.run('sudo useradd mydbuser', pty=True)
[sudo] password:
<Result cmd='sudo useradd mydbuser' exited=0>
>>> c.run('id -u mydbuser')
- 利用Invoke的自动回应来输入sudo密码,
注意pattern的正确匹配,以及repsonese的结尾符号
>>> from invoke import Responder
>>> from fabric import Connection
>>> c = Connection('host')
>>> sudopass = Responder(
... pattern=r'\[sudo\] password:',
... response='mypassword\n',
... )
>>> c.run('sudo whoami', pty=True, watchers=[sudopass])
[sudo] password:
root
<Result cmd='sudo whoami' exited=0>
- watchers虽然提供了自动填充密码的功能,但是代码中多次引用这种配置比较麻烦,所以考虑将sudopass的内容放入配置里面,让Connection.sudo来处理剩下的工作。
>>> import getpass
>>> from fabric import Connection, Config
>>> sudo_pass = getpass.getpass("What's your sudo password?")
What's your sudo password?
>>> config = Config(overrides={'sudo': {'password': sudo_pass}})
>>> c = Connection('db1', config=config)
>>> c.sudo('whoami', hide='stderr')
root
<Result cmd="...whoami" exited=0>
>>> c.sudo('useradd mydbuser')
<Result cmd="...useradd mydbuser" exited=0>
>>> c.run('id -u mydbuser')
1001
<Result cmd='id -u mydbuser' exited=0>
- 文件传输,transfer files,利用Connection.put和Connection.get。在使用时发现如果像下面这样定义remote的话,会报错OSError,要带上远程的文件重命名就不会报错。
>>> from fabric import Connection
>>> result = Connection('web1').put('myfiles.tgz', remote='/opt/mydata/')
>>> print("Uploaded {0.local} to {0.remote}".format(result))
Uploaded /local/myfiles.tgz to /opt/mydata/
- 之前都是单行的操作,实际多半不是这样,多个同时执行,如上传、解压,路径、文件名可以作为参数传入,以便复用函数
from fabric import Connection
c = Connection('web1')
c.put('myfiles.tgz', '/opt/mydata')
c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
def upload_and_unpack(c):
c.put('myfiles.tgz', '/opt/mydata')
c.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
多服务器的情况,这个单列出来
- 最直观的方法是遍历一个connection列表
>>> from fabric import Connection
>>> for host in ('web1', 'web2', 'mac1'):
>>> result = Connection(host).run('uname -s')
... print("{}: {}".format(host, result.stdout.strip()))
...
...
web1: Linux
web2: Linux
mac1: Darwin
- fabric提供了一个更好的解决办法,把所有的对象放到一个
Group
里面。- Group和SerialGroup(Subclass of Group which executes in simple, serial fashion. New in version 2.0.)
- 返回的结果看,Connection返回单个的Result对象,Group返回GroupResult对象,dict-like
In [18]: results = Group('peter@192.168.9.218', 'peter@192.168.9.208').run('uname -s')
Linux
Linux
In [19]: for conn, result in results.items():
...: print("{0.host}: {1.stdout}".format(conn, result))
...:
192.168.9.218: Linux
192.168.9.208: Linux
- Group对象来执行的操作会对所有服务器生效,但是这里官方教程的
pool.put
会得到一个AttributeError: 'SerialGroup' object has no attribute 'put'
错误,已在github提交issue
from fabric import SerialGroup as Group
pool = Group('web1', 'web2', 'web3')
pool.put('myfiles.tgz', '/opt/mydata')
pool.run('tar -C /opt/mydata -xzvf /opt/mydata/myfiles.tgz')
fab cli tool
封装了Invoke的CLI功能,能够很快的在多个机器上运行tasks。
- 将之前的任务编程一个fab task来运行,要定义一个fabfile.py
实际部署
这里参考的一篇博客,使用的是python2版本的fabric,仅供学习思路。
流程
- 远程连接服务器。
- 进入项目根目录,从远程仓库拉取最新的代码。
- 如果项目引入了新的依赖,需要执行 pip install -r requirement.txt 安装最新依赖。
- 如果修改或新增了项目静态文件,需要执行 python manage.py collectstatic 收集静态文件。
- 如果数据库发生了变化,需要执行 python manage.py migrate 迁移数据库。
- 重启 Nginx 和 Gunicorn 使改动生效。
fabfile.py
位于项目(真正的代码项目,而非包含各种配置的部署项目)的根目录,
python2 fabric mac路径问题
I got same problem. If I run brew link --overwrite python2
. There was still zsh: /usr/local/bin//fab: bad interpreter: /usr/local/opt/python/bin/python2.7: no such file or directory
.
方案1
- 如果python本来指向了Celler的python3.6,那么先移除这个链接
- 然后在用过ln -s python2 python软连接
- 如果没有python2可以用
brew reinstall python2
,之后就能查看到
方案2
cd /usr/local/opt/
mv python2 python
Solved it! Now we can use python2 version fabric.