fabric使用总结

fabric可谓部署神器,在小规模集群环境部署方面简直就是屠龙刀的存在

简介

  • fabric目前存在两个版本,分别对应python2和python3
  • 本文主要介绍fabric两个版本的常用方法

fabric(python2)

安装(python2环境)

1
pip install fabric

若要实现ssh跳转,需另外安装fexpect

1
pip install fexpect

fabric2的API对应部署的对象定义比较明了

  • env(定义部署主机的ip,密码,节点属性,全局变量等)
1
2
3
4
5
6
7
8
def dev():
env.roledefs = {
"manager": ["user@x.x.x.x:22"],
"worker": ["user@x.x.x.x:22"],
}
env.passwords = {"user@x.x.x.x:22": "123456", "user@x.x.x.x:22": "123456"}
global ENV_PARAM
ENV_PARAM = "dev"
  • roles
1
2
3
4
5
6
7
8
9
@roles("manager")
def start_swarm(tag, compose_file="docker-compose.yml"):
with cd(SRC_PATH):
with shell_env(ENV_PARAM = ENV_PARAM, TAG=tag):
run(
"docker stack deploy --with-registry-auth -c deploy/swarm_deploy/{} {}".format( # noqa
compose_file, PREFIX
)
)
  • run

执行shell指令

  • hide, settings

配合使用,隐藏输出内容等

1
with settings(hide("warnings", "running", "stdout", "stderr"), warn_only=True):
  • cd,sudo

同shell指令

  • execute

在本地任务中执行其他任务函数,提高代码复用率

  • shell_env

设置环境变量

1
2
3
4
5
6
with shell_env(ASSET_CONFIG=ASSET_CONFIG, TAG=tag):
run(
"docker stack deploy --with-registry-auth -c deploy/swarm_deploy/{} {}".format( # noqa
compose_file, PREFIX
)
)
  • 配合fexpect使用

贴了段之前用过的代码,可用于修饰任务函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
def env_init(f):
# 代码目录
global SRC_PATH
SRC_PATH = ""
# 私有镜像仓库
global REGISTRY_HOST
REGISTRY_HOST = ""
global REGISTRY_USER
REGISTRY_USER = ""
global REGISTRY_PWD
REGISTRY_PWD = ""
# 项目前缀
global PREFIX
PREFIX = "asset"
# 主节点ip
global MANAGER_IP, MANAGER_SSL, MANAGER_PWD

def _get_manager_ip():
return env.roledefs["manager"][0][6:-3]

def _get_manager_ssl():
return env.roledefs["manager"][0][:-3]

# EXPECT
global PROMPTS

@wraps(f)
def wrapper(*args, **kwargs):
global MANAGER_IP, MANAGER_SSL, MANAGER_PWD, PROMPTS
MANAGER_IP = _get_manager_ip()
MANAGER_SSL = _get_manager_ssl()
MANAGER_PWD = env.passwords[env.roledefs["manager"][0]]
PROMPTS = expect(
"Are you sure you want to continue connecting (yes/no)?", "yes"
)
return f(*args, **kwargs)

return wrapper

fabric(python3)

安装(python3环境)

1
pip install fabric

fabirc3的API相较而言显的抽象简单

  • Connection 作为连接通道抽象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 连接本地
local_conn = Connection('localhost')

# 远程连接
# 没了envAPI只能自己手动定义连接环境
envs = {
'remote': {
'host_name': 'xx',
'host': 'user@x.x.x.x:22',
'password': '123456',
},
}
conn = Connection(
env.get('host'),
connect_kwargs={'password': env.get('password')}
)
  • task 定义任务
1
2
3
4
5
@task
def deploy(ctx, debug=True):
mvn_package(ctx)
send_jar_2_remote(ctx)
start_server(ctx, debug=debug)

通过fab deploy执行该任务,值得注意的是ctx这个变量必须要写
指定传参fab start-server --jar-timestamp=20191203-1637 debug=True(让人琢磨尝试了半天)

  • 其他注意点

对task任务函数使用装饰器,需要注意ctx的传入

1
2
3
4
5
6
7
8
9
10
11
12
13
def timeit(start_msg=None, end_msg=None):
def decorator(func):
@wraps(func)
def wrapper(ctx, *args, **kwargs):
if start_msg:
print(start_msg)
start = time.time()
res = func(ctx, *args, **kwargs)
if end_msg:
print(f'{end_msg}{round((time.time() - start), 2)}s')
return res
return wrapper
return decorator

然而遗憾的是,在自定义装饰器的修饰下,再使用命令行传参将失效

1
2
3
4
5
6
7
# 此时debug的将无法被解析
@task
@timeit(end_msg='发布完成')
def deploy(ctx, debug=True):
mvn_package(ctx)
send_jar_2_remote(ctx)
start_server(ctx, debug=debug)

究其原因,是invoke中使用的python2的inspect.getargspec,而python3中删除了对应函数,并且six对此并未兼容,从而导致参数解析失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def argspec(self, body):
func = body if isinstance(body, types.FunctionType) else body.__call__
spec = inspect.getargspec(func)
arg_names = spec.args[:]
matched_args = [reversed(x) for x in [spec.args, spec.defaults or []]]
spec_dict = dict(zip_longest(*matched_args, fillvalue=NO_DEFAULT))
# Pop context argument
try:
context_arg = arg_names.pop(0)
except IndexError:
# TODO: see TODO under __call__, this should be same type
raise TypeError("Tasks must have an initial Context argument!")
del spec_dict[context_arg]
return arg_names, spec_dict

总结

  • 综上,可以看出fabric3较fabric2而言基本是完败,使用过fabric2再迁移到fabric3是格外的别扭,由此不难理解网上对fabric3对使用教程基本上寥寥无几,即便存在大部分也只是对官网用例的简单翻译,谈不上工业级的使用
  • fabric3是面向程序编程而非面向human编程
  • 无奈于python2终将被淘汰,还是对fabric3保留一些些期待吧
-------------The End-------------
坚持原创技术分享,您的支持将鼓励我继续创作!