<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fabric on Dapeng Zhang</title><link>https://zhangdapeng.dev/tags/fabric/</link><description>Recent content in Fabric on Dapeng Zhang</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 30 Jul 2025 11:44:26 +0800</lastBuildDate><atom:link href="https://zhangdapeng.dev/tags/fabric/index.xml" rel="self" type="application/rss+xml"/><item><title>fabric 2.5.0添加类似env配置文件，减少执行命令重复操作</title><link>https://zhangdapeng.dev/p/fabric-2-5-0-tian-jia-lei-si-env-pei-zhi-wen-jian-jian-shao-zhi-xing-ming-ling-chong-fu-cao-zuo/</link><pubDate>Wed, 30 Jul 2025 11:44:26 +0800</pubDate><guid>https://zhangdapeng.dev/p/fabric-2-5-0-tian-jia-lei-si-env-pei-zhi-wen-jian-jian-shao-zhi-xing-ming-ling-chong-fu-cao-zuo/</guid><description>&lt;img src="https://res.cloudinary.com/dy5dvcuc1/image/upload/v1575509665/gowhich/fabric1.jpg" alt="Featured image of post fabric 2.5.0添加类似env配置文件，减少执行命令重复操作" /&gt;&lt;p&gt;fabric 2.5.0可以通过添加类似env配置文件，从而达到减少执行命令的重复操作，比如减少每次执行任务的用户名和密码的输入&lt;/p&gt;
&lt;p&gt;如果将用户名和密码写入fabric.py这种项目文件中，并提交到git仓库的话也是非常不安全的&lt;/p&gt;
&lt;p&gt;但是根据用户来创建一个可自己访问和执行的文件就比较方便，尤其是在linux系统下，多个用户多一个操作系统都有权限的话，每个用户下面只要有个&lt;code&gt;~/.fabric.yaml&lt;/code&gt;文件&lt;/p&gt;
&lt;p&gt;便可以执行fabric的任务操作，从而避免了将重要密码暴漏给所有人，或者将自己的密码共享给所有人&lt;/p&gt;
&lt;p&gt;创建配置文件&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;touch ~/.fabric.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在配置文件中添加类似如下的配置信息&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;user: dpzhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pwd: 123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后在&lt;code&gt;fabric.py&lt;/code&gt;中添加任务&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Author: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Date: 2019-12-04 16:52:35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified by: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified time: 2019-12-20 18:50:44&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;pwd)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;命令行下执行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;得到输出的结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dpzhang
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果将test方法修改如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Author: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Date: 2019-12-04 16:52:35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified by: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified time: 2019-12-20 18:50:44&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;user)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;pwd)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;hosts&lt;span style="color:#f92672"&gt;.&lt;/span&gt;host)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同时修改&lt;code&gt;~/.fabric.yaml&lt;/code&gt;，内容修改后如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;user: dpzhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pwd: 123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;hosts:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;host: 127.0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再次运行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab test
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;得到的输出结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dpzhang
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;123456&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Python小技巧 - Fabric并发执行远程主机操作</title><link>https://zhangdapeng.dev/p/python-xiao-ji-qiao-fabric-bing-fa-zhi-xing-yuan-cheng-zhu-ji-cao-zuo/</link><pubDate>Wed, 30 Jul 2025 10:40:36 +0800</pubDate><guid>https://zhangdapeng.dev/p/python-xiao-ji-qiao-fabric-bing-fa-zhi-xing-yuan-cheng-zhu-ji-cao-zuo/</guid><description>&lt;img src="https://res.cloudinary.com/dy5dvcuc1/image/upload/v1565854753/walkerfree/python.jpg" alt="Featured image of post Python小技巧 - Fabric并发执行远程主机操作" /&gt;&lt;p&gt;fabric中如何实现并发执行远程主机任务&lt;/p&gt;
&lt;p&gt;比如我有多台远程主机，想要通过并行的方式在没太主机上执行同样的命令&lt;/p&gt;
&lt;p&gt;如果按照fabric提供的&lt;code&gt;ThreadingGroup&lt;/code&gt;的话，可能会遇到一个问题就是，每个主机在执行命令的时候，遇到问题，比如链接失败的话可能会导致所有的链接都失败，再比如我要判断每台机器的部署项目的目录是否存在，这个时候的话，每个远程主机执行的时候需要执行不同的逻辑，我采用另外一个方式，就是&lt;code&gt;multiprocessing&lt;/code&gt;的方式&lt;/p&gt;
&lt;p&gt;首先看下&lt;code&gt;multiprocessing的并发如何实现&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;第一种是&lt;code&gt;Process&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;实现方式如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; multiprocessing &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Pool, Process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host_run&lt;/span&gt;(host):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;执行 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; host)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;结束 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; host)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;4&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;5&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;7&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;8&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;9&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Process方式创建进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;创建Process&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; h &lt;span style="color:#f92672"&gt;in&lt;/span&gt; hosts:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Process(target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;host_run, args&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(h &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39; - process&amp;#39;&lt;/span&gt;, ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;Process执行结束&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;创建Process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process执行结束
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; - process
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第二种是&lt;code&gt;Pool&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;实现方式如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; multiprocessing &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Pool, Process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; time
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host_run&lt;/span&gt;(host):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;执行 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; host)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; time&lt;span style="color:#f92672"&gt;.&lt;/span&gt;sleep(&lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;结束 &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; host)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;4&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;5&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;7&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;8&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;9&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Pool方式创建大量子进程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;创建Pool&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pool &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Pool(len(hosts))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; h &lt;span style="color:#f92672"&gt;in&lt;/span&gt; hosts:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pool&lt;span style="color:#f92672"&gt;.&lt;/span&gt;apply_async(host_run, args&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(h &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;pool&amp;#39;&lt;/span&gt;, ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;print(&lt;span style="color:#e6db74"&gt;&amp;#39;等待Pool执行&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pool&lt;span style="color:#f92672"&gt;.&lt;/span&gt;close()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pool&lt;span style="color:#f92672"&gt;.&lt;/span&gt;join()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;创建Pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;等待Pool执行
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;执行 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;结束 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; - pool
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到这里，两种方式我们都实现了并发的方式执行代码逻辑&lt;/p&gt;
&lt;p&gt;下面回到主体，整合到fabric中，要如何实现&lt;/p&gt;
&lt;p&gt;实现代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; socket&lt;span style="color:#f92672"&gt;,&lt;/span&gt; paramiko.ssh_exception
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SerialGroup, exceptions, runners, Connection
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.exceptions &lt;span style="color:#f92672"&gt;import&lt;/span&gt; GroupException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; multiprocessing &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Process
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host_run&lt;/span&gt;(host):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Connection(host)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;ls -ahl&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(res)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;asyncrun&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; h &lt;span style="color:#f92672"&gt;in&lt;/span&gt; hosts:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Process(target&lt;span style="color:#f92672"&gt;=&lt;/span&gt;host_run, args&lt;span style="color:#f92672"&gt;=&lt;/span&gt;(h, ))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; p&lt;span style="color:#f92672"&gt;.&lt;/span&gt;start()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行结果如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ fab asyncrun
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process Process-1:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#f92672"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 267, in _bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.run&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 114, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self._target&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*self._args, **self._kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/practise/fabfile.py&amp;#34;&lt;/span&gt;, line 34, in host_run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c.run&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ls -ahl&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;decorator-gen-3&amp;gt;&amp;#34;&lt;/span&gt;, line 2, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 29, in opens
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.open&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 634, in open
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.client.connect&lt;span style="color:#f92672"&gt;(&lt;/span&gt;**kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/paramiko/client.py&amp;#34;&lt;/span&gt;, line 368, in connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process Process-3:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process Process-4:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Process Process-2:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#f92672"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#f92672"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback &lt;span style="color:#f92672"&gt;(&lt;/span&gt;most recent call last&lt;span style="color:#f92672"&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 267, in _bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 267, in _bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 267, in _bootstrap
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.run&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 114, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.run&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 114, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self._target&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*self._args, **self._kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/practise/fabfile.py&amp;#34;&lt;/span&gt;, line 34, in host_run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self._target&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*self._args, **self._kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/practise/fabfile.py&amp;#34;&lt;/span&gt;, line 34, in host_run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c.run&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ls -ahl&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;decorator-gen-3&amp;gt;&amp;#34;&lt;/span&gt;, line 2, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.run&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 29, in opens
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/usr/local/Cellar/python@2/2.7.16/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py&amp;#34;&lt;/span&gt;, line 114, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self._target&lt;span style="color:#f92672"&gt;(&lt;/span&gt;*self._args, **self._kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/practise/fabfile.py&amp;#34;&lt;/span&gt;, line 34, in host_run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c.run&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ls -ahl&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c.run&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;ls -ahl&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;decorator-gen-3&amp;gt;&amp;#34;&lt;/span&gt;, line 2, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;lt;decorator-gen-3&amp;gt;&amp;#34;&lt;/span&gt;, line 2, in run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 29, in opens
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 29, in opens
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raise NoValidConnectionsError&lt;span style="color:#f92672"&gt;(&lt;/span&gt;errors&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NoValidConnectionsError: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Errno None&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Unable to connect to port &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; on 127.0.0.1 or ::1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.open&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 634, in open
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.client.connect&lt;span style="color:#f92672"&gt;(&lt;/span&gt;**kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/paramiko/client.py&amp;#34;&lt;/span&gt;, line 368, in connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.open&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 634, in open
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.client.connect&lt;span style="color:#f92672"&gt;(&lt;/span&gt;**kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/paramiko/client.py&amp;#34;&lt;/span&gt;, line 368, in connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.open&lt;span style="color:#f92672"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/fabric/connection.py&amp;#34;&lt;/span&gt;, line 634, in open
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.client.connect&lt;span style="color:#f92672"&gt;(&lt;/span&gt;**kwargs&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; File &lt;span style="color:#e6db74"&gt;&amp;#34;/Users/durban/python/.env_2.7.16/lib/python2.7/site-packages/paramiko/client.py&amp;#34;&lt;/span&gt;, line 368, in connect
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raise NoValidConnectionsError&lt;span style="color:#f92672"&gt;(&lt;/span&gt;errors&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raise NoValidConnectionsError&lt;span style="color:#f92672"&gt;(&lt;/span&gt;errors&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NoValidConnectionsError: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Errno None&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Unable to connect to port &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; on 127.0.0.1 or ::1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NoValidConnectionsError: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Errno None&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Unable to connect to port &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; on 127.0.0.1 or ::1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; raise NoValidConnectionsError&lt;span style="color:#f92672"&gt;(&lt;/span&gt;errors&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NoValidConnectionsError: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;Errno None&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Unable to connect to port &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; on 127.0.0.1 or ::1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我这里是报了错误，但是从错误信息可以看出，每个host都并发的执行了，不然错误应该不会交叉输出的&lt;/p&gt;
&lt;p&gt;后面会记录一个完整版的fabric，能过链接正式生产环境的脚本实践实例。&lt;/p&gt;</description></item><item><title>Fabric 并发方式执行项目部署命令</title><link>https://zhangdapeng.dev/p/fabric-bing-fa-fang-shi-zhi-xing-xiang-mu-bu-shu-ming-ling/</link><pubDate>Wed, 30 Jul 2025 10:40:13 +0800</pubDate><guid>https://zhangdapeng.dev/p/fabric-bing-fa-fang-shi-zhi-xing-xiang-mu-bu-shu-ming-ling/</guid><description>&lt;img src="https://res.cloudinary.com/dy5dvcuc1/image/upload/v1565854753/walkerfree/python.jpg" alt="Featured image of post Fabric 并发方式执行项目部署命令" /&gt;&lt;p&gt;最近做运维工作，遇到项目部署的问题，不过通过python库fabric也是可以解决问题的&lt;/p&gt;
&lt;p&gt;而且还是很方便，大概的方式如下&lt;/p&gt;
&lt;p&gt;强调下，这里使用的是fabric 2这个版本&lt;/p&gt;
&lt;p&gt;原理也是简单就是，fabric提供了&lt;code&gt;ThreadingGroup&lt;/code&gt;这个类，网上很少有人用吧，google很久才找到&lt;/p&gt;
&lt;p&gt;先看下以前的并行的方式，是如何执行项目部署命令的&lt;/p&gt;
&lt;p&gt;代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; invoke &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Responder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# service online machine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.2&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.3&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input username:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input password:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Responder(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\[sudo\] password&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auth_pass &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy_series&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; host &lt;span style="color:#f92672"&gt;in&lt;/span&gt; hosts:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Connection(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (user, host),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;: auth_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ls -al /&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(command, pty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, watchers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[sudo_pass])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(res)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;示例代码简单的执行了&lt;code&gt;ls -al /&lt;/code&gt;命令&lt;/p&gt;
&lt;p&gt;上面的方式就是一台跟着一台机器的进行命令的执行，总的时间是没台机器执行完的时间总和，着实有点慢，影响代码上线的效率&lt;/p&gt;
&lt;p&gt;下面看下并行的方式，并发的方式是如何运行的&lt;/p&gt;
&lt;p&gt;代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; invoke &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Responder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SerialGroup, ThreadingGroup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.exceptions &lt;span style="color:#f92672"&gt;import&lt;/span&gt; GroupException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# service online machine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.2&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;127.0.0.3&amp;#39;&lt;/span&gt;, &lt;span style="color:#75715e"&gt;# web3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input username:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input password:&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Responder(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\[sudo\] password&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auth_pass &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy_parallel&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ThreadingGroup(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;hosts,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;: auth_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ls -al /&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; g&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(command, pty&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, watchers&lt;span style="color:#f92672"&gt;=&lt;/span&gt;[sudo_pass])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(res)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; GroupException &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; c, r &lt;span style="color:#f92672"&gt;in&lt;/span&gt; e&lt;span style="color:#f92672"&gt;.&lt;/span&gt;result&lt;span style="color:#f92672"&gt;.&lt;/span&gt;items():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(r)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同样的也只是执行命令而已&lt;/p&gt;
&lt;p&gt;但是执行的顺序是并发的方式，总的执行时间是执行时间最长的那台机器的时间，很大程度提高了上线代码的执行效率。&lt;/p&gt;</description></item><item><title>如何使用fabric 2.x使用并行方式和串行方式远程自动化运维部署</title><link>https://zhangdapeng.dev/p/ru-he-shi-yong-fabric-2-x-shi-yong-bing-xing-fang-shi-he-chuan-xing-fang-shi-yuan-cheng-zi-dong-hua-yun-wei-bu-shu/</link><pubDate>Wed, 30 Jul 2025 09:57:20 +0800</pubDate><guid>https://zhangdapeng.dev/p/ru-he-shi-yong-fabric-2-x-shi-yong-bing-xing-fang-shi-he-chuan-xing-fang-shi-yuan-cheng-zi-dong-hua-yun-wei-bu-shu/</guid><description>&lt;img src="https://res.cloudinary.com/dy5dvcuc1/image/upload/v1575509665/gowhich/fabric1.jpg" alt="Featured image of post 如何使用fabric 2.x使用并行方式和串行方式远程自动化运维部署" /&gt;&lt;p&gt;之前一篇文章介绍如何使用fabric进行远程自动化部署&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.walkerfree.com/article/183" target="_blank" rel="noopener"
 &gt;fabric2.x使用指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;脚本如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; invoke &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Responder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.2&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.3&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.4&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input username: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;project &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input project dirname: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input auth pass: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 需要sudo权限的时候需要&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Responder(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\[sudo\] password&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auth_pass &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; h &lt;span style="color:#f92672"&gt;in&lt;/span&gt; hosts:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Connection(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (user, h), connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;: auth_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ls -al&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# sudo 权限可用下面的命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# conn.run(command, pty=True, watchers=[sudo_pass])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 非sudo权限可用下面的命令 - 这里使用非sudo权限&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(command)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;串行方式如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task, SerialGroup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; invoke &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Responder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.2&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.3&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.4&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input username: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;project &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input project dirname: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input auth pass: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 需要sudo权限的时候需要&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Responder(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\[sudo\] password&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auth_pass &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SerialGroup(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;hosts, user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user, connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;: auth_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ls -al&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# sudo 权限可用下面的命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# conn.run(command, pty=True, watchers=[sudo_pass])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 非sudo权限可用下面的命令 - 这里使用非sudo权限&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(command)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;并行方式如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task, SerialGroup
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; invoke &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Responder
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.2&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.3&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;10.0.0.4&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input username: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;project &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input project dirname: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;auth_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input auth pass: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 需要sudo权限的时候需要&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Responder(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; pattern&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;r&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;\[sudo\] password&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; response&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auth_pass &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\n&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; ThreadingGroup(&lt;span style="color:#f92672"&gt;*&lt;/span&gt;hosts, user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;user, connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#39;password&amp;#39;&lt;/span&gt;: auth_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;ls -al&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# sudo 权限可用下面的命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# conn.run(command, pty=True, watchers=[sudo_pass])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 非sudo权限可用下面的命令 - 这里使用非sudo权限&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; conn&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(command)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;节省掉了for循环的操作 但是增加了排查问题的难度&lt;/p&gt;
&lt;p&gt;这里举例如何处理异常&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; socket&lt;span style="color:#f92672"&gt;,&lt;/span&gt; paramiko.ssh_exception
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; SerialGroup, exceptions, runners
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.exceptions &lt;span style="color:#f92672"&gt;import&lt;/span&gt; GroupException
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; g &lt;span style="color:#f92672"&gt;=&lt;/span&gt; SerialGroup(&lt;span style="color:#e6db74"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; res &lt;span style="color:#f92672"&gt;=&lt;/span&gt; g&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;hostname&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# print(res)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;except&lt;/span&gt; GroupException &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; e:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; c, r &lt;span style="color:#f92672"&gt;in&lt;/span&gt; e&lt;span style="color:#f92672"&gt;.&lt;/span&gt;result&lt;span style="color:#f92672"&gt;.&lt;/span&gt;items():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;.&lt;/span&gt;format(c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;host))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(c)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(r)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; isinstance(r, runners&lt;span style="color:#f92672"&gt;.&lt;/span&gt;Result):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34; SUCCESS, &amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; r&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stdout&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; isinstance(r, socket&lt;span style="color:#f92672"&gt;.&lt;/span&gt;gaierror):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;NetWork Error&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;elif&lt;/span&gt; isinstance(r, paramiko&lt;span style="color:#f92672"&gt;.&lt;/span&gt;ssh_exception&lt;span style="color:#f92672"&gt;.&lt;/span&gt;AuthenticationException):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Auth failed&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#39;Other Error&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基础知识汇总&lt;/p&gt;
&lt;p&gt;Fabric 提供了一个 fabric.group.Group 基类，并由其派生出两个子类，区别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SerialGroup(*hosts, **kwargs)：按串行方式执行操作&lt;/li&gt;
&lt;li&gt;ThreadingGroup(*hosts, **kwargs)：按并发方式执行操作&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://cloud.tencent.com/developer/article/1590930" target="_blank" rel="noopener"
 &gt;https://cloud.tencent.com/developer/article/1590930&lt;/a&gt;&lt;/p&gt;</description></item><item><title>fabric2.x使用指南</title><link>https://zhangdapeng.dev/p/fabric2-x-shi-yong-zhi-nan/</link><pubDate>Wed, 30 Jul 2025 09:56:44 +0800</pubDate><guid>https://zhangdapeng.dev/p/fabric2-x-shi-yong-zhi-nan/</guid><description>&lt;img src="https://res.cloudinary.com/dy5dvcuc1/image/upload/v1575509665/gowhich/fabric1.jpg" alt="Featured image of post fabric2.x使用指南" /&gt;&lt;p&gt;之前在看flask1.0的文档，里面学到了一个自动部署的工具fabric，但是里面介绍的是1.0系列的使用指南，但是我安装的时候版本已经更新了，已经是fabric2.x了，so，没办法，直接使用fabric2.x的版本吧，但是文档是fabric1.0的版本确实挺难受，毕竟很多功能要靠自己去摸索，然后再一点一点的实现，刚开始也是一头雾水，没有思路，今天回过头一看其实很简单的，主要是远程连接这块，不在区分本地和远程连接了，fabric1.x版本的时候会有个&lt;code&gt;local&lt;/code&gt;的方法，使用起来一目了然，就知道具体这个是本地的还是远程。然后有小伙伴说了，就使用这个版本不行吗，我说不行，具体可以去fabric官网看下升级的必要性说明，其他不多说了，下面看下我说如何使用fabric2.x实现具体细节的&lt;/p&gt;
&lt;p&gt;代码如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-py" data-lang="py"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Author: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Date: 2019-12-04 16:52:35&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified by: durban.zhang&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# @Last Modified time: 2019-12-04 18:41:59&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; getpass
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric &lt;span style="color:#f92672"&gt;import&lt;/span&gt; Connection, task
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;pack&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 这里的c参数我理解为是Connection连接的本地 然后根据setup.py进行项目打包&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;python setup.py release sdist --format=gztar&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@task&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;deploy&lt;/span&gt;(c):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 输入服务器的登录用户名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input login user name: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 输入服务器的登录地址&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; host &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input login host: &amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 输入服务器的项目目录地址&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root &lt;span style="color:#f92672"&gt;=&lt;/span&gt; raw_input(&lt;span style="color:#e6db74"&gt;&amp;#39;Input project root path：&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 输入服务器的登录密码&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_pass &lt;span style="color:#f92672"&gt;=&lt;/span&gt; getpass&lt;span style="color:#f92672"&gt;.&lt;/span&gt;getpass(&lt;span style="color:#e6db74"&gt;&amp;#39;Input login user pass：&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 获取包的全名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;python setup.py --fullname&amp;#39;&lt;/span&gt;, hide&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dist &lt;span style="color:#f92672"&gt;=&lt;/span&gt; result&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stdout&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;.tar.gz&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; dist
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 获取包的名称 - 这个名称可以根据自己的需求来自定义，这里主要是为了下面supervisor启动时使用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; c&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;python setup.py --name&amp;#39;&lt;/span&gt;, hide&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; result&lt;span style="color:#f92672"&gt;.&lt;/span&gt;stdout&lt;span style="color:#f92672"&gt;.&lt;/span&gt;strip()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 远端服务器连接创建&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; remote &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Connection(&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (user, host),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; connect_kwargs&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#e6db74"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;: user_pass})
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 上传文件到远端服务器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; remote&lt;span style="color:#f92672"&gt;.&lt;/span&gt;put(&lt;span style="color:#e6db74"&gt;&amp;#39;./dist/&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; filename, remote&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; root)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# 在远端服务器上执行下面命令 - 这个会默认输出你在远端服务器展示的信息&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; result &lt;span style="color:#f92672"&gt;=&lt;/span&gt; remote&lt;span style="color:#f92672"&gt;.&lt;/span&gt;run(&lt;span style="color:#e6db74"&gt;&amp;#39;cd &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; source .env/bin/activate &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; ls -al &amp;amp;&amp;amp; type python &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; pip install &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; supervisorctl restart walkerfree&amp;#39;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; (root, filename))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用方式如下&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab pack deploy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个命令其实也可以分布执行&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab pack
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab deploy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我上面的代码也可以将两个函数合并到一起在执行，分开的话主要是看起来思路比较清晰&lt;/p&gt;</description></item><item><title>使用Fabric自动化你的任务</title><link>https://zhangdapeng.dev/p/shi-yong-fabric-zi-dong-hua-ni-de-ren-wu/</link><pubDate>Tue, 24 Jun 2025 11:24:20 +0000</pubDate><guid>https://zhangdapeng.dev/p/shi-yong-fabric-zi-dong-hua-ni-de-ren-wu/</guid><description>&lt;h2 id="fabric是什么"&gt;&lt;a class="link" href="#1" &gt;fabric是什么？&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="http://docs.fabfile.org/zh/1.8/" target="_blank" rel="noopener"
 &gt;Fabric&lt;/a&gt;是一个Python库，可以通过SSH在多个host上批量执行任务。你可以编写任务脚本，然后通过Fabric在本地就可以使用SSH在大量远程服务器上自动运行。这些功能非常适合应用的自动化部署，或者执行系统管理任务。&lt;/p&gt;
&lt;p&gt;让我们首先看一个例子。我们知道在 &lt;code&gt;*NIX&lt;/code&gt; 下面，uname命令是查看系统的发行版。可以写这样一个Fabric脚本：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.api &lt;span style="color:#f92672"&gt;import&lt;/span&gt; run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host_type&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run(&lt;span style="color:#e6db74"&gt;&amp;#39;uname -s&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将上面的脚本保存为fabfile.py，就可以通过fab命令在多个主机上执行host_type脚本了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; fab &lt;span style="color:#f92672"&gt;-&lt;/span&gt;H localhost,linuxbox host_type
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[localhost] run: uname &lt;span style="color:#f92672"&gt;-&lt;/span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[localhost] out: Darwin
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[linuxbox] run: uname &lt;span style="color:#f92672"&gt;-&lt;/span&gt;s
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[linuxbox] out: Linux
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行过程中可能需要你输入系统密码。&lt;/p&gt;
&lt;h2 id="安装"&gt;&lt;a class="link" href="#2" &gt;安装&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;如果你看到这里了，说明你开始对Fabric感兴趣了。但是上述操作在你那里无法执行，因为你还没有安装Fabric。安装Fabric很简单，可以用pip或者easy_install，也可以下载原代码安装。&lt;/p&gt;
&lt;h2 id="任务函数"&gt;&lt;a class="link" href="#3" &gt;任务函数&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;很好，安装Fabric并没有难住你。可能你已经成功的执行了前面的任务，现在让我们更深入一些。&lt;/p&gt;
&lt;p&gt;Fabric中的任务就是一个python函数，姑且让我们称之为“任务函数”。既然是python函数，那么对函数的一些用法也适用于任务函数。比如传递参数、互相调用、返回值等等。首先看一个传递参数的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;!&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在执行任务的时候，可以通过fab的命令行参数为任务函数传递参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;$&lt;/span&gt; fab hello:name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;Holbrook
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hello Holbrook&lt;span style="color:#960050;background-color:#1e0010"&gt;!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;组合任务的例子如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.api &lt;span style="color:#f92672"&gt;import&lt;/span&gt; run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;host_type&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run(&lt;span style="color:#e6db74"&gt;&amp;#39;uname -s&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hello&lt;/span&gt;(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello &lt;/span&gt;&lt;span style="color:#e6db74"&gt;%s&lt;/span&gt;&lt;span style="color:#e6db74"&gt;!&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;%&lt;/span&gt; name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;composite&lt;/span&gt;(name&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;world&amp;#34;&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hello(name)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; host_type()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="fabric提供的命令"&gt;&lt;a class="link" href="#4" &gt;Fabric提供的命令&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;前面我们见过了fabric.api模块中的run函数，其功能是在远端主机上执行命令。fabric.api中还提供了local函数，用于执行本地（Fabric所在的主机）命令。如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.api &lt;span style="color:#f92672"&gt;import&lt;/span&gt; local
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lslocal&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; local(&lt;span style="color:#e6db74"&gt;&amp;#39;ls&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;类似远端命令和本地命令，Fabric也区分远端目录和本地目录。Fabric提供的对远端和本地目录的操作分别是cd和lcd。如果你用过命令行的ftp，这很容易理解。让我们看一个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;filepath&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; remote_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;/opt/xxx&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;with&lt;/span&gt; cd(remote_dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run(&lt;span style="color:#e6db74"&gt;&amp;#34;touch README&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面代码的功能是进入远端的&lt;code&gt;/opt/xxx&lt;/code&gt;目录，并创建一个README文件。&lt;/p&gt;
&lt;p&gt;Fabric还提供了很多的命令，比如文件操作等，可以参考Fabric的operations模块。&lt;/p&gt;
&lt;h2 id="管理服务器连接"&gt;&lt;a class="link" href="#5" &gt;管理服务器连接&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;前面的例子中，都需要在fab命令行参数中指定server。当要管理大量服务器时很麻烦。Fabric提供了环境变量的字典env，其中就包含了hosts字典项，可以定义需要连接的server。如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.api &lt;span style="color:#f92672"&gt;import&lt;/span&gt; env, run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;env&lt;span style="color:#f92672"&gt;.&lt;/span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;host1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;host2&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mytask&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run(&lt;span style="color:#e6db74"&gt;&amp;#39;ls /var/www&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以为每个任务单独指定要执行该任务的host列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fabric.api &lt;span style="color:#f92672"&gt;import&lt;/span&gt; env, run
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;set_hosts&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; env&lt;span style="color:#f92672"&gt;.&lt;/span&gt;hosts &lt;span style="color:#f92672"&gt;=&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;host1&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;host2&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;mytask&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; run(&lt;span style="color:#e6db74"&gt;&amp;#39;ls /var/www&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样执行 &lt;code&gt;fab set_hosts mytask&lt;/code&gt;时，就可以为&lt;code&gt;set_hosts&lt;/code&gt;中指定的两个host执行mytask任务了。如果你懒得写函数，在fab命令行中指定也是一样的：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;fab mytask:hosts&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;host1;host2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为了更方便的执行批量任务，Fabric中还定义了Role，有兴趣可以阅读其官方文档。&lt;/p&gt;
&lt;p&gt;管理SSH密码、用户、端口&lt;/p&gt;
&lt;p&gt;尽管更推荐使用SSH公钥认证，但是Fabric还是提供了管理密码的机制。Fabric提供了两层密码。&lt;/p&gt;
&lt;p&gt;如果你的server有相同的密码，可以在env.password中设置默认的密码；如果server密码不同，还可以在env.passwords中设置(host,password）对，为每个server设置单独的ssh密码。&lt;/p&gt;
&lt;p&gt;上面的host字符串采用这种格式：username@hostname:port。所以，在指定ssh密码的同时，也就指定了ssh用户。同密码一样，你也可以在env.user中指定一个默认的用户。如果都没有指定，执行fab命令时会提示你输入密码。&lt;/p&gt;
&lt;h2 id="小结"&gt;&lt;a class="link" href="#6" &gt;小结&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;使用Fabric，你可以管理一系列host的SSH连接（包括主机名，用户，密码），定义一系列的任务函数，然后灵活的指定在哪些host上执行哪些任务。这非常使用于需要管理大量host的场景，比如运维，私有云管理，应用自动化部署等。&lt;/p&gt;
&lt;p&gt;本文只是一篇入门文档，远没有体现出Fabric的强大。实际上，Fabric还包括大量的功能，比如Role的定义，远程交互及异常处理，并发执行，文件操作等，并且不仅仅局限于命令行方式，可以在你的应用中调用Fabric。&lt;/p&gt;
&lt;p&gt;希望本文能够引起你对Fabric的兴趣，并在你的实际应用中解决问题。&lt;/p&gt;</description></item></channel></rss>