2

我有一个执行任务的任务 -

@roles('group_django')
@task
@serial
def deploy_web():
    execute(pre_deploy)
    execute(fix_srv_perms)
    execute(force_checkout_branch_to_production)
    execute(update_sources)
    execute(pip_install_requirements)
    #execute(bounce_workers)
    execute(bounce_uwsgi)
    execute(clear_cache)

考虑到提供的主机顺序执行但共同执行,是否可以在 deploy_web 中执行。

假设角色“group_django”有 4 个服务器,它将从该角色中的第一个主机开始并执行每个执行然后重复。还是我需要在前面做更多的跑腿工作,然后在call 的每个循环中获取当前env.hosts和循环deploy_webexecutehosts=[current_host]

我的目标是,如果部署不好,它只会淘汰服务器池中的一个,以便负载均衡器将其踢出,但平台会保持一些完整性。

已经阅读(有没有办法在结构文件中进行滚动部署?)它不适用于我的deploy_web任务的工作方式。

4

1 回答 1

1

Very basic answer to my question is with this little helper function.

def execute_serial(func, *args, **kwargs):
    a2set = lambda x : set(getattr(func, x)) if hasattr(func, x) else None

    func_hosts = a2set('hosts')
    func_roles = a2set('roles')
    should_exec = False

    if 'host' not in kwargs:
        kwargs['host'] = my_host = env.host_string

    if func_hosts and my_host in func_hosts:
        should_exec = True


    if func_roles:
        for func_role in func_roles:
            if func_role in env.roledefs and my_host in env.roledefs[func_role]:
                should_exec = True

    if should_exec:
        return execute(func, *args, **kwargs)

And usage would be like

@roles('group_django')
@task
def deploy_web():
    execute(pre_deploy)
    execute_serial(fix_srv_perms)
    execute_serial(force_checkout_branch_to_production)
    execute_serial(update_sources)
    execute_serial(pip_install_requirements)

    #these won't work correctly anymore
    execute(bounce_workers)
    execute(bounce_uwsgi)
    execute(clear_cache)

I've gone through fabric.main.main() and there's no easy opportunities for hooks ( prior to start, all tasks done, on error, etc etc ) so an additional solution might be instead

@roles('local') # defined in roledefs as {'local':'127.0.0.1'}
@task    
def deploy_web():
    execute(pre_deploy) #This is already role('local') with @runonce

    for host in env.roledefs['group_django'].values():
        execute_serial(fix_srv_perms, host = host)
        execute_serial(force_checkout_branch_to_production, host = host)
        execute_serial(update_sources, host = host)
        execute_serial(pip_install_requirements, host = host)

    #These will pickup the @role decorators
    execute(redeploy_web_crontab)
    execute(redeploy_work_crontab)
    execute(bounce_workers) 
    execute(bounce_uwsgi)
    execute(clear_cache)

Additional info, I've written something like this a few times but I have a boto iterator that uses to ~/.boto to decide on region and produce a env.roledefs as illustrated in pseudo-code

{ "{name in instance.tags }_{instance.tags[name]}": [ list of instance.public_dns_name that matches] }

additionally for my current webstack, all instances have tags like "group", "type", and optionally "lead" for specifying where to install crontabs, or execute final deployment scripts.

Using the local task loop you would need to make some slight modification to execute_serial specifically env.host_string would equal "{env.user}@127.0.0.1" which is not ideal.

def execute_serial(func, *args, **kwargs):
a2set = lambda x : set(getattr(func, x)) if hasattr(func, x) else None

no_user = lambda x: x.split("@")[-1]
func_hosts = a2set('hosts')
func_roles = a2set('roles')
should_exec = False
my_host = env.host_string

my_host = env.host_string = kwargs['host']


if func_hosts and no_user(my_host) in func_hosts:
    should_exec = True


if func_roles:
    for func_role in func_roles:
        if func_role in env.roledefs and no_user(env.host_string) in env.roledefs[func_role]:
            should_exec = True
            break

if should_exec:
    return execute(func, *args, **kwargs)
于 2013-05-26T01:03:20.790 回答