如何在 Fabric 文件中设置目标主机
我想使用 Fabric 将我的 Web 应用程序代码部署到开发、登台和生产服务器。我的 fabfile:
def deploy_2_dev():
deploy('dev')
def deploy_2_staging():
deploy('staging')
def deploy_2_prod():
deploy('prod')
def deploy(server):
print 'env.hosts:', env.hosts
env.hosts = [server]
print 'env.hosts:', env.hosts
示例输出:
host:folder user$ fab deploy_2_dev
env.hosts: []
env.hosts: ['dev']
No hosts found. Please specify (single) host string for connection:
当我创建一个 set_hosts()
任务时,如 Fabric 文档,env.hosts 设置正确。然而,这不是一个可行的选择,装饰器也不是。在命令行上传递主机最终会生成某种调用 fabfile 的 shell 脚本,我更希望使用一个工具来正确完成这项工作。
Fabric 文档中说“env.hosts 只是一个 Python 列表对象”。根据我的观察,这根本不是事实。
谁能解释一下这是怎么回事?如何设置要部署到的主机?
I want to use Fabric to deploy my web app code to development, staging and production servers. My fabfile:
def deploy_2_dev():
deploy('dev')
def deploy_2_staging():
deploy('staging')
def deploy_2_prod():
deploy('prod')
def deploy(server):
print 'env.hosts:', env.hosts
env.hosts = [server]
print 'env.hosts:', env.hosts
Sample output:
host:folder user$ fab deploy_2_dev
env.hosts: []
env.hosts: ['dev']
No hosts found. Please specify (single) host string for connection:
When I create a set_hosts()
task as shown in the Fabric docs, env.hosts is set properly. However, this is not a viable option, neither is a decorator. Passing hosts on the command line would ultimately result in some kind of shell script that calls the fabfile, I would prefer having one single tool do the job properly.
It says in the Fabric docs that 'env.hosts is simply a Python list object'. From my observations, this is simply not true.
Can anyone explain what is going on here ? How can I set the host to deploy to ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
您需要设置
host_string
示例如下:You need to set
host_string
an example would be:解释为什么这甚至是一个问题。命令fab正在利用fabric库来运行主机列表上的任务。如果您尝试更改任务内的主机列表,那么您实际上是在迭代列表时尝试更改列表。或者,在没有定义主机的情况下,循环遍历一个空列表,其中将列表设置为循环的代码永远不会执行。
使用 env.host_string 可以解决此行为,只是因为它直接向函数指定要连接的主机。这会导致一些问题,因为如果您想要在多个主机上执行,您将重新创建执行循环。
人们能够在运行时设置主机的最简单方法是将环境填充为一个不同的任务,该任务设置所有主机字符串、用户等。然后他们运行部署任务。它看起来像这样:
或
其中登台和生产就像您给出的任务,但它们本身不会调用下一个任务。它必须像这样工作的原因是任务必须完成,并跳出循环(主机的循环,在 env 情况下为 None,但此时它是一个循环),然后让循环结束重新指定主机(现在由前面的任务定义)。
To explain why it's even an issue. The command fab is leveraging fabric the library to run the tasks on the host lists. If you try and change the host list inside a task, you're esentially attempting to change a list while iterating over it. Or in the case where you have no hosts defined, loop over an empty list where the code where you set the list to loop over is never executed.
The use of env.host_string is a work around for this behavior only in that it's specifying directly to the functions what hosts to connect with. This causes some issues in that you'll be remaking the execution loop if you want to have a number of hosts to execute on.
The simplest way the people make the ability to set hosts at run time, is to keep the env populatiing as a distinct task, that sets up all the host strings, users, etc. Then they run the deploy task. It looks like this:
or
Where staging and production are like the tasks you have given, but they do not call the next task themselves. The reason it has to work like this, is that the task has to finish, and break out of the loop (of hosts, in the env case None, but it's a loop of one at that point), and then have the loop over the hosts (now defined by the preceding task) anew.
您需要在模块级别修改 env.hosts,而不是在任务函数内。我也犯了同样的错误。
You need to modify env.hosts at the module level, not within a task function. I made the same mistake.
这很简单。只需初始化 env.host_string 变量,以下所有命令都将在此主机上执行。
It's very simple. Just initialize the env.host_string variable and all of the following commands will be executed on this host.
我对 Fabric 完全陌生,但要让 Fabric 在多个主机上运行相同的命令(例如,在一个命令中部署到多个服务器),您可以运行:
where staging-server 和 生产服务器是您要对其运行部署操作的 2 台服务器。这是一个简单的 fabfile.py,它将显示操作系统名称。请注意,fabfile.py 应与运行 fab 命令的目录位于同一目录中。
这至少适用于 Fabric 1.8.1。
I'm totally new to fabric, but to get fabric to run the same commands on multiple hosts (e.g. to deploy to multiple servers, in one command) you can run:
where staging-server and production-server are 2 servers you want to run the deploy action against. Here's a simple fabfile.py that will display the OS name. Note that the fabfile.py should be in the same directory as where you run the fab command.
This works with fabric 1.8.1 at least.
因此,为了设置主机并在所有主机上运行命令,您必须首先:
定义这些主机后,然后在命令行上运行命令:
什么将在所有服务器上运行部署任务在 PROD 函数中列出,因为它在运行任务之前设置 env.hosts。
So, in order to set the hosts, and have the commands run across all the hosts, you have to start with:
Once those are defined, then run the command on the command line:
What will run the deploy task across all of the servers listed in the PROD function, as it sets the env.hosts before running the task.
您可以在执行子任务之前分配
env.hoststring
。如果要迭代多个主机,请在循环中分配给此全局变量。不幸的是,对于你我来说,fabric 并不是为这种用例而设计的。查看 http://github.com/bitprophet/fabric/main.py" 的
main
函数/github.com/bitprophet/fabric/blob/master/fabric/main.py 看看它是如何工作的。You can assign to
env.hoststring
before executing a subtask. Assign to this global variable in a loop if you want to iterate over multiple hosts.Unfortunately for you and me, fabric is not designed for this use case. Check out the
main
function at http://github.com/bitprophet/fabric/blob/master/fabric/main.py to see how it works.这是另一种“翻跟斗”模式,可启用 fab my_env_1 my_command 用法:
使用此模式,我们只需使用字典定义一次环境。
env_factory
根据ENVS
的键名创建函数。我将ENVS
放在其自己的目录中,并文件secrets.config.py
将配置与结构代码分开。缺点是,如所写,添加
@task
装饰器将 打破它。注意:我们在工厂中使用
def func(k=k):
而不是def func():
因为 后期绑定。我们使用 此解决方案 并对其进行修补以定义该函数。Secrets.config.py
fabfile.py
Here's another "summersault" pattern that enables the
fab my_env_1 my_command
usage:With this pattern, we only have to define environments one time using a dictionary.
env_factory
creates functions based on the keynames ofENVS
. I putENVS
in its own directory and filesecrets.config.py
to separate config from the fabric code.The drawback is that, as written, adding the
@task
decorator will break it.Notes: We use
def func(k=k):
instead ofdef func():
in the factory because of late binding. We get the running module with this solution and patch it to define the function.secrets.config.py
fabfile.py
使用角色目前被认为是执行此操作的“适当”和“正确”方法,并且是您“应该”执行的操作。
也就是说,如果您像大多数人一样,您“想要”或“渴望”的是执行“扭曲系统”或动态切换目标系统的能力。
因此,仅出于娱乐目的(!)以下示例说明了许多人可能认为有风险但又完全令人满意的操作,如下所示:
然后运行:
Using roles is currently considered to be the "proper" and "correct" way of doing this and is what you "should" do it.
That said, if you are like most of what you "would like" or "desire" is the ability to perform a "twisted syster" or switching target systems on the fly.
So for entertainment purposes only (!) the following example illustrates what many might consider to a risky, and yet somehow thoroughly satisfying, manoeuvre that goes something like this:
Then running:
我通过为每个环境声明一个实际函数来做到这一点。例如:
使用上述函数,我将键入以下内容来部署到我的测试环境:
...以及以下内容来部署到生产环境:
这样做的好处是
test
和 prod 函数可以在任何 fab 函数之前使用,而不仅仅是部署。它非常有用。I do this by declaring an actual function for each environment. For example:
Using the above functions, I would type the following to deploy to my test environment:
...and the following to deploy to production:
The nice thing about doing it this way is that the
test
andprod
functions can be used before any fab function, not just deploy. It is incredibly useful.使用 roledefs
用 -R 选择角色:
Use roledefs
Choose role with -R:
这是 serverhorror 的答案的简单版本:
Here's a simpler version of serverhorror's answer:
我自己也被困在这个问题上,但最后想通了。您根本无法在任务内设置 env.hosts 配置。每个任务都会执行 N 次,每个指定的主机执行一次,因此该设置基本上超出了任务范围。
看看上面的代码,您可以简单地执行以下操作:
这似乎可以实现您的预期。
或者,您可以在全局范围内编写一些自定义代码,手动解析参数,并在定义任务函数之前设置 env.hosts。由于一些原因,这实际上就是我的设置方式。
Was stuck on this myself, but finally figured it out. You simply can't set the env.hosts configuration from within a task. Each task is executed N times, once for each Host specified, so the setting is fundamentally outside of task scope.
Looking at your code above, you could simply do this:
Which seems like it would do what you're intending.
Or you can write some custom code in the global scope that parses the arguments manually, and sets env.hosts before your task function is defined. For a few reasons, that's actually how I've set mine up.
从 fab 1.5 开始,这是动态设置主机的记录方法。
http://docs.fabfile.org/en/1.7/usage /execution.html#dynamic-hosts
引用下面的文档。
Since fab 1.5 this is a documented way to dynamically set hosts.
http://docs.fabfile.org/en/1.7/usage/execution.html#dynamic-hosts
Quote from the doc below.
与其他一些答案相反,可以修改任务中的
env
环境变量。但是,此env
将仅用于使用fabric.tasks.execute
函数执行的后续任务。如果不将子任务包装在
execute(...)
中,您的模块级env
设置或从fab
CLI 传递的任何内容都将是用过的。Contrary to some other answers, it is possible to modify the
env
environment variables within a task. However, thisenv
will only be used for subsequent tasks executed using thefabric.tasks.execute
function.Without wrapping sub-tasks in
execute(...)
, your module-levelenv
settings or whatever is passed from thefab
CLI will be used.