<div class="blogpost-body cnblogs-markdown"><blockquote>
<p>因为我的个人网站 <a href="http://restran.net">restran.net</a> 已经启用,博客园的内容已经不再更新。请访问我的个人网站获取这篇文章的最新内容,<a href="http://www.restran.net/2015/10/04/supervisord-tutorial/">Python 进程管理工具 Supervisor 使用教程</a></p>
</blockquote>
<p><a href="http://supervisord.org/">Supervisor</a> 是基于 Python 的进程管理工具,只能运行在 Unix-Like 的系统上,也就是无法运行在 Windows 上。Supervisor 官方版目前只能运行在 Python 2.4 以上版本,但是还无法运行在 Python 3 上,不过已经有一个 Python 3 的移植版 <a href="https://github.com/palmkevin/supervisor-py3k">supervisor-py3k</a>。</p>
<p>什么情况下我们需要进程管理呢?就是执行一些需要以守护进程方式执行的程序,比如一个后台任务,我最常用的是用来启动和管理基于 Tornado 写的 Web 程序。</p>
<p>除此之外,Supervisor 还能很友好的管理程序在命令行上输出的日志,可以将日志重定向到自定义的日志文件中,还能按文件大小对日志进行分割。</p>
<p>Supervisor 有两个主要的组成部分:</p>
<ol>
<li><code>supervisord</code>,运行 Supervisor 时会启动一个进程 supervisord,它负责启动所管理的进程,并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启。</li>
<li><code>supervisorctl</code>,是命令行管理工具,可以用来执行 stop、start、restart 等命令,来对这些子进程进行管理。</li>
</ol>
<h2 id="安装">安装</h2>
<pre><code class="hljs cmake">sudo pip <span class="hljs-keyword">install</span> supervisor</code></pre>
<h2 id="创建配置文件">创建配置文件</h2>
<pre><code class="hljs javascript">echo_supervisord_conf > <span class="hljs-regexp">/etc/</span>supervisord.conf</code></pre>
<p>如果出现没有权限的问题,可以使用<a href="http://blog.csdn.net/orangleliu/article/details/45057377">这条命令</a></p>
<pre><code class="hljs swift">sudo su - root -<span class="hljs-built_in">c</span> <span class="hljs-string">"echo_supervisord_conf > /etc/supervisord.conf"</span></code></pre>
<h2 id="配置文件说明">配置文件说明</h2>
<p>想要了解怎么配置需要管理的进程,只要打开 supervisord.conf 就可以了,里面有很详细的注释信息。</p>
<p>打开配置文件</p>
<pre><code class="hljs dts">vim <span class="hljs-meta-keyword">/etc/</span>supervisord.conf</code></pre>
<p>默认的配置文件是下面这样的,但是这里有个坑需要注意,supervisord.pid 以及 supervisor.sock 是放在 /tmp 目录下,但是 /tmp 目录是存放临时文件,里面的文件是会被 Linux 系统删除的,一旦这些文件丢失,就无法再通过 supervisorctl 来执行 restart 和 stop 命令了,将只会得到 <code>unix:///tmp/supervisor.sock</code> 不存在的错误 。</p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="kw"><span class="hljs-section">[unix_http_server]</span></span>
<span class="co"><span class="hljs-comment">;file=/tmp/supervisor.sock ; (the path to the socket file)</span></span>
<span class="co"><span class="hljs-comment">;修改为 /var/run 目录,避免被系统删除</span></span>
<span class="dt"><span class="hljs-attr">file</span></span><span class="ot">=</span><span class="st">/var/run/supervisor.sock </span><span class="co">; (the path to the socket file)</span>
<span class="co"><span class="hljs-comment">;chmod=0700 ; socket file mode (default 0700)</span></span>
<span class="co"><span class="hljs-comment">;chown=nobody:nogroup ; socket file uid:gid owner</span></span>
<span class="co"><span class="hljs-comment">;username=user ; (default is no username (open server))</span></span>
<span class="co"><span class="hljs-comment">;password=123 ; (default is no password (open server))</span></span>
<span class="co"><span class="hljs-comment">;[inet_http_server] ; inet (TCP) server disabled by default</span></span>
<span class="co"><span class="hljs-comment">;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for ;all iface)</span></span>
<span class="co"><span class="hljs-comment">;username=user ; (default is no username (open server))</span></span>
<span class="co"><span class="hljs-comment">;password=123 ; (default is no password (open server))</span></span>
<span class="dt">...</span>
<span class="hljs-section">
</span><span class="kw"><span class="hljs-section">[supervisord]</span></span>
<span class="co"><span class="hljs-comment">;logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)</span></span>
<span class="co"><span class="hljs-comment">;修改为 /var/log 目录,避免被系统删除</span></span>
<span class="dt"><span class="hljs-attr">logfile</span></span><span class="ot">=</span><span class="st">/var/log/supervisor/supervisord.log </span><span class="co">; (main log file;default <span class="hljs-variable">$CWD</span>/supervisord.log)</span>
<span class="dt"><span class="hljs-attr">logfile_maxbytes</span></span><span class="ot">=</span><span class="st"><span class="hljs-number">50</span>MB </span><span class="co">; (max main logfile bytes b4 rotation;default <span class="hljs-number">50</span>MB)</span>
<span class="dt"><span class="hljs-attr">logfile_backups</span></span><span class="ot">=</span><span class="dv"><span class="hljs-number">10</span></span><span class="st"> </span><span class="co">; (num of main logfile rotation backups;default <span class="hljs-number">10</span>)</span>
<span class="dt"><span class="hljs-attr">loglevel</span></span><span class="ot">=</span><span class="st">info </span><span class="co">; (log level;default info; others: debug,warn,trace)</span>
<span class="co"><span class="hljs-comment">;pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid)</span></span>
<span class="co"><span class="hljs-comment">;修改为 /var/run 目录,避免被系统删除</span></span>
<span class="dt"><span class="hljs-attr">pidfile</span></span><span class="ot">=</span><span class="st">/var/run/supervisord.pid </span><span class="co">; (supervisord pidfile;default supervisord.pid)</span>
<span class="dt">...</span>
<span class="co"><span class="hljs-comment">;设置启动supervisord的用户,一般情况下不要轻易用root用户来启动,除非你真的确定要这么做</span></span>
<span class="co"><span class="hljs-comment">;user=chrism ; (default is current user, required if root)</span></span>
<span class="dt">...</span>
<span class="hljs-section">
</span><span class="kw"><span class="hljs-section">[supervisorctl]</span></span>
<span class="co"><span class="hljs-comment">; 必须和‘unix_http_server‘里面的设定匹配</span></span>
<span class="co"><span class="hljs-comment">;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket</span></span>
<span class="co"><span class="hljs-comment">;修改为 /var/run 目录,避免被系统删除</span></span>
<span class="dt"><span class="hljs-attr">serverurl</span></span><span class="ot">=</span><span class="st">unix:///var/run/supervisor.sock </span><span class="co">; use a unix:// URL for a unix socket</span>
<span class="co"><span class="hljs-comment">;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket</span></span>
<span class="co"><span class="hljs-comment">;username=chris ; should be same as http_username if set</span></span>
<span class="co"><span class="hljs-comment">;password=123 ; should be same as http_password if set</span></span>
<span class="dt">...</span></code></pre></div>
<p>默认情况下,进程的日志文件达到50MB时,将进行分割,最多保留10个文件,当然这些配置也可以对每个进程单独配置。</p>
<h3 id="权限问题">权限问题</h3>
<p>设置好配置文件后,应先创建上述配置文件中新增的文件夹。如果指定了启动用户 user,这里以 oxygen 为例,那么应注意相关文件的权限问题,包括日志文件,否则会出现没有权限的错误。例如设置了启动用户 oxygen,然后启动 supervisord 出现错误</p>
<pre><code class="hljs css"><span class="hljs-selector-tag">Error</span>: <span class="hljs-selector-tag">Cannot</span> <span class="hljs-selector-tag">open</span> <span class="hljs-selector-tag">an</span> <span class="hljs-selector-tag">HTTP</span> <span class="hljs-selector-tag">server</span>: <span class="hljs-selector-tag">socket</span><span class="hljs-selector-class">.error</span> <span class="hljs-selector-tag">reported</span> <span class="hljs-selector-tag">errno</span><span class="hljs-selector-class">.EACCES</span> (13)</code></pre>
<p>就是由于上面的配置文件中 /var/run 文件夹,没有授予启动 supervisord 的用户 oxygen 的写权限。/var/run 文件夹实际上是链接到 /run,因此我们修改 /run 的权限。</p>
<pre><code class="hljs perl">sudo <span class="hljs-keyword">chmod</span> <span class="hljs-number">777</span> /run</code></pre>
<p>一般情况下,我们可以用 root 用户启动 supervisord 进程,然后在其所管理的进程中,再具体指定需要以那个用户启动这些进程。</p>
<h3 id="使用浏览器来管理">使用浏览器来管理</h3>
<p>supervisor 同时提供了通过浏览器来管理进程的方法,只需要注释掉如下几行就可以了。</p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="co"><span class="hljs-comment">;[inet_http_server] ; inet (TCP) server disabled by default</span></span>
<span class="co"><span class="hljs-comment">;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for ;all iface)</span></span>
<span class="co"><span class="hljs-comment">;username=user ; (default is no username (open server))</span></span>
<span class="co"><span class="hljs-comment">;password=123 ; (default is no password (open server))</span></span>
<span class="hljs-section">
</span><span class="kw"><span class="hljs-section">[supervisorctl]</span></span>
<span class="dt">...</span>
<span class="co"><span class="hljs-comment">;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket</span></span>
<span class="co"><span class="hljs-comment">;username=chris ; should be same as http_username if set</span></span>
<span class="co"><span class="hljs-comment">;password=123 ; should be same as http_password if set</span></span></code></pre></div>
<p><img src="https://images2015.cnblogs.com/blog/343468/201510/343468-20151004155112027-670589086.jpg" alt="http_supervisorctl"></p>
<h3 id="使用-include">使用 include</h3>
<p>在配置文件的最后,有一个 [include] 的配置项,跟 Nginx 一样,可以 include 某个文件夹下的所有配置文件,这样我们就可以为每个进程或相关的几个进程的配置单独写成一个文件。</p>
<pre><code class="hljs ini"><span class="hljs-section">[include]</span>
<span class="hljs-attr">files</span> = /etc/supervisord.d/*.ini</code></pre>
<h2 id="进程的配置样例">进程的配置样例</h2>
<p>一个简单的例子如下</p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="co"><span class="hljs-comment">; 设置进程的名称,使用 supervisorctl 来管理进程时需要使用该进程名</span></span>
<span class="kw"><span class="hljs-section">[program:your_program_name]</span></span><span class="dt"> </span>
<span class="dt"><span class="hljs-attr">command</span></span><span class="ot">=</span><span class="st">python server.py --port=</span><span class="dv"><span class="hljs-number">9000</span></span>
<span class="co"><span class="hljs-comment">;numprocs=1 ; 默认为1</span></span>
<span class="co"><span class="hljs-comment">;process_name=%(program_name)s ; 默认为 %(program_name)s,即 [program:x] 中的 x</span></span>
<span class="dt"><span class="hljs-attr">directory</span></span><span class="ot">=</span><span class="st">/home/python/tornado_server </span><span class="co">; 执行 command 之前,先切换到工作目录</span>
<span class="dt"><span class="hljs-attr">user</span></span><span class="ot">=</span><span class="st">oxygen </span><span class="co">; 使用 oxygen 用户来启动该进程</span>
<span class="co"><span class="hljs-comment">; 程序崩溃时自动重启,重启次数是有限制的,默认为3次</span></span>
<span class="dt"><span class="hljs-attr">autorestart</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">true</span></span><span class="st"> </span>
<span class="dt"><span class="hljs-attr">redirect_stderr</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">true</span></span><span class="st"> </span><span class="co">; 重定向输出的日志</span>
<span class="dt"><span class="hljs-attr">stdout_logfile</span> </span><span class="ot">=</span><span class="st"> /var/log/supervisord/tornado_server.log</span>
<span class="dt"><span class="hljs-attr">loglevel</span></span><span class="ot">=</span><span class="st">info</span></code></pre></div>
<h3 id="设置日志级别">设置日志级别</h3>
<p><code>loglevel</code> 指定了日志的级别,用 Python 的 print 语句输出的日志是不会被记录到日志文件中的,需要搭配 Python 的 logging 模块来输出有指定级别的日志。</p>
<h3 id="多个进程">多个进程</h3>
<p>按照官方文档的定义,一个 [program:x] 实际上是表示一组相同特征或同类的进程组,也就是说一个 [program:x] 可以启动<code>多个进程</code>。这组进程的成员是通过 <code>numprocs</code> 和 <code>process_name</code> 这两个参数来确定的,这句话什么意思呢,我们来看这个例子。</p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="co"><span class="hljs-comment">; 设置进程的名称,使用 supervisorctl 来管理进程时需要使用该进程名</span></span>
<span class="kw"><span class="hljs-section">[program:foo]</span></span><span class="dt"> </span>
<span class="co"><span class="hljs-comment">; 可以在 command 这里用 python 表达式传递不同的参数给每个进程</span></span>
<span class="dt"><span class="hljs-attr">command</span></span><span class="ot">=</span><span class="st">python server.py --port=</span><span class="dv"><span class="hljs-number">90</span></span><span class="st">%(process_num)<span class="hljs-number">02</span>d</span>
<span class="dt"><span class="hljs-attr">directory</span></span><span class="ot">=</span><span class="st">/home/python/tornado_server </span><span class="co">; 执行 command 之前,先切换到工作目录</span>
<span class="co"><span class="hljs-comment">; 若 numprocs 不为1,process_name 的表达式中一定要包含 process_num 来区分不同的进程</span></span>
<span class="dt"><span class="hljs-attr">numprocs</span></span><span class="ot">=</span><span class="dv"><span class="hljs-number">2</span></span><span class="st"> </span>
<span class="dt"><span class="hljs-attr">process_name</span></span><span class="ot">=</span><span class="st">%(program_name)s_%(process_num)<span class="hljs-number">02</span>d</span><span class="co">; </span>
<span class="dt"><span class="hljs-attr">user</span></span><span class="ot">=</span><span class="st">oxygen </span><span class="co">; 使用 oxygen 用户来启动该进程</span>
<span class="dt"><span class="hljs-attr">autorestart</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">true</span></span><span class="st"> </span><span class="co">; 程序崩溃时自动重启</span>
<span class="dt"><span class="hljs-attr">redirect_stderr</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">true</span></span><span class="st"> </span><span class="co">; 重定向输出的日志</span>
<span class="dt"><span class="hljs-attr">stdout_logfile</span> </span><span class="ot">=</span><span class="st"> /var/log/supervisord/tornado_server.log</span>
<span class="dt"><span class="hljs-attr">loglevel</span></span><span class="ot">=</span><span class="st">info</span></code></pre></div>
<p>上面这个例子会启动两个进程,process_name 分别为 <code>foo:foo_01</code> 和 <code>foo:foo_02</code>。通过这样一种方式,就可以用一个 [program:x] 配置项,来启动一组非常类似的进程。</p>
<p>再介绍两个配置项 <code>stopasgroup</code> 和 <code>killasgroup</code></p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="co"><span class="hljs-comment">; 默认为 false,如果设置为 true,当进程收到 stop 信号时,会自动将该信号发给该进程的子进程。如果这个配置项为 true,那么也隐含 killasgroup 为 true。例如在 Debug 模式使用 Flask 时,Flask 不会将接收到的 stop 信号也传递给它的子进程,因此就需要设置这个配置项。</span></span>
<span class="dt"><span class="hljs-attr">stopasgroup</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">false</span></span><span class="st"> </span><span class="co">; send stop signal to the UNIX process </span>
<span class="co"><span class="hljs-comment">; 默认为 false,如果设置为 true,当进程收到 kill 信号时,会自动将该信号发给该进程的子进程。如果这个程序使用了 python 的 multiprocessing 时,就能自动停止它的子线程。</span></span>
<span class="dt"><span class="hljs-attr">killasgroup</span></span><span class="ot">=</span><span class="kw"><span class="hljs-literal">false</span></span><span class="st"> </span><span class="co">; SIGKILL the UNIX process group (def <span class="hljs-literal">false</span>)</span></code></pre></div>
<p>更详细的配置例子,可以参考如下,官方文档在<a href="http://supervisord.org/configuration.html#program-x-section-settings">这里</a></p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="co"><span class="hljs-comment">;[program:theprogramname]</span></span>
<span class="co"><span class="hljs-comment">;command=/bin/cat ; the program (relative uses PATH, can take args)</span></span>
<span class="co"><span class="hljs-comment">;process_name=%(program_name)s ; process_name expr (default %(program_name)s)</span></span>
<span class="co"><span class="hljs-comment">;numprocs=1 ; number of processes copies to start (def 1)</span></span>
<span class="co"><span class="hljs-comment">;directory=/tmp ; directory to cwd to before exec (def no cwd)</span></span>
<span class="co"><span class="hljs-comment">;umask=022 ; umask for process (default None)</span></span>
<span class="co"><span class="hljs-comment">;priority=999 ; the relative start priority (default 999)</span></span>
<span class="co"><span class="hljs-comment">;autostart=true ; start at supervisord start (default: true)</span></span>
<span class="co"><span class="hljs-comment">;autorestart=unexpected ; whether/when to restart (default: unexpected)</span></span>
<span class="co"><span class="hljs-comment">;startsecs=1 ; number of secs prog must stay running (def. 1)</span></span>
<span class="co"><span class="hljs-comment">;startretries=3 ; max # of serial start failures (default 3)</span></span>
<span class="co"><span class="hljs-comment">;exitcodes=0,2 ; ‘expected‘ exit codes for process (default 0,2)</span></span>
<span class="co"><span class="hljs-comment">;stopsignal=QUIT ; signal used to kill process (default TERM)</span></span>
<span class="co"><span class="hljs-comment">;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)</span></span>
<span class="co"><span class="hljs-comment">;stopasgroup=false ; send stop signal to the UNIX process group (default false)</span></span>
<span class="co"><span class="hljs-comment">;killasgroup=false ; SIGKILL the UNIX process group (def false)</span></span>
<span class="co"><span class="hljs-comment">;user=chrism ; setuid to this UNIX account to run the program</span></span>
<span class="co"><span class="hljs-comment">;redirect_stderr=true ; redirect proc stderr to stdout (default false)</span></span>
<span class="co"><span class="hljs-comment">;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO</span></span>
<span class="co"><span class="hljs-comment">;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)</span></span>
<span class="co"><span class="hljs-comment">;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)</span></span>
<span class="co"><span class="hljs-comment">;stdout_capture_maxbytes=1MB ; number of bytes in ‘capturemode‘ (default 0)</span></span>
<span class="co"><span class="hljs-comment">;stdout_events_enabled=false ; emit events on stdout writes (default false)</span></span>
<span class="co"><span class="hljs-comment">;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO</span></span>
<span class="co"><span class="hljs-comment">;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)</span></span>
<span class="co"><span class="hljs-comment">;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10)</span></span>
<span class="co"><span class="hljs-comment">;stderr_capture_maxbytes=1MB ; number of bytes in ‘capturemode‘ (default 0)</span></span>
<span class="co"><span class="hljs-comment">;stderr_events_enabled=false ; emit events on stderr writes (default false)</span></span>
<span class="co"><span class="hljs-comment">;environment=A="1",B="2" ; process environment additions (def no adds)</span></span>
<span class="co"><span class="hljs-comment">;serverurl=AUTO ; override serverurl computation (childutils)</span></span></code></pre></div>
<h3 id="将多个进程按组管理">将多个进程按组管理</h3>
<p>Supervisor 同时还提供了另外一种进程组的管理方式,通过这种方式,可以使用 supervisorctl 命令来管理一组进程。跟 [program:x] 的进程组不同的是,这里的进程是一个个的 [program:x] 。</p>
<div class="sourceCode"><pre class="sourceCode ini"><code class="sourceCode ini hljs"><span class="kw"><span class="hljs-section">[group:thegroupname]</span></span>
<span class="dt"><span class="hljs-attr">programs</span></span><span class="ot">=</span><span class="st">progname1,progname2 </span><span class="co">; each refers to <span class="hljs-string">‘x‘</span> in [program:x] definitions</span>
<span class="dt"><span class="hljs-attr">priority</span></span><span class="ot">=</span><span class="dv"><span class="hljs-number">999</span></span><span class="st"> </span><span class="co">; the relative start priority (default <span class="hljs-number">999</span>)</span></code></pre></div>
<p>当添加了上述配置后,<code>progname1</code> 和 <code>progname2</code> 的进程名就会变成 <code>thegroupname:progname1</code> 和 <code>thegroupname:progname2</code> 以后就要用这个名字来管理进程了,而不是之前的 <code>progname1</code>。</p>
<p>以后执行 <code>supervisorctl stop thegroupname:</code> 就能同时结束 <code>progname1</code> 和 <code>progname2</code>,执行 <code>supervisorctl stop thegroupname:progname1</code> 就能结束 <code>progname1</code>。supervisorctl 的命令我们稍后介绍。</p>
<h2 id="启动-supervisord">启动 supervisord</h2>
<p>执行 supervisord 命令,将会启动 supervisord 进程,同时我们在配置文件中设置的进程也会相应启动。</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash hljs"><span class="co"><span class="hljs-comment"># 使用默认的配置文件 /etc/supervisord.conf</span></span>
<span class="kw">supervisord</span>
<span class="co"><span class="hljs-comment"># 明确指定配置文件</span></span>
<span class="kw">supervisord</span> -c /etc/supervisord.conf
<span class="co"><span class="hljs-comment"># 使用 user 用户启动 supervisord</span></span>
<span class="kw">supervisord</span> -u user</code></pre></div>
<p>更多参数请参考<a href="http://supervisord.org/running.html#supervisord-command-line-options">文档</a></p>
<h2 id="supervisorctl-命令介绍">supervisorctl 命令介绍</h2>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash hljs"><span class="co"><span class="hljs-comment"># 停止某一个进程,program_name 为 [program:x] 里的 x</span></span>
<span class="kw">supervisorctl</span> stop program_name
<span class="co"><span class="hljs-comment"># 启动某个进程</span></span>
<span class="kw">supervisorctl</span> start program_name
<span class="co"><span class="hljs-comment"># 重启某个进程</span></span>
<span class="kw">supervisorctl</span> restart program_name
<span class="co"><span class="hljs-comment"># 结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)</span></span>
<span class="kw">supervisorctl</span> stop groupworker:
<span class="co"><span class="hljs-comment"># 结束 groupworker:name1 这个进程 (start,restart 同理)</span></span>
<span class="kw">supervisorctl</span> stop groupworker:name1
<span class="co"><span class="hljs-comment"># 停止全部进程,注:start、restart、stop 都不会载入最新的配置文件</span></span>
<span class="kw">supervisorctl</span> stop all
<span class="co"><span class="hljs-comment"># 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程</span></span>
<span class="kw">supervisorctl</span> reload
<span class="co"><span class="hljs-comment"># 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启</span></span>
<span class="kw">supervisorctl</span> update</code></pre></div>
<p>注意:显示用 stop 停止掉的进程,用 reload 或者 update 都不会自动重启。也可以参考<a href="http://feilong.me/2011/03/monitor-processes-with-supervisord">这里</a></p>
<h2 id="开机自动启动-supervisord">开机自动启动 Supervisord</h2>
<p>Supervisord 默认情况下并没有被安装成服务,它本身也是一个进程。官方已经给出了脚本可以将 Supervisord 安装成服务,可以参考<a href="https://github.com/Supervisor/initscripts">这里</a>查看各种操作系统的安装脚本,但是我用官方这里给的 Ubuntu 脚本却无法运行。</p>
<p>安装方法可以参考 <a href="http://serverfault.com/questions/96499/how-to-automatically-start-supervisord-on-linux-ubuntu">serverfault</a> 上的回答。</p>
<p>比如我是 Ubuntu 系统,可以这么安装,这里选择了另外一个脚本</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash hljs"><span class="co"><span class="hljs-comment"># 下载脚本</span></span>
<span class="kw">sudo</span> su - root -c <span class="st"><span class="hljs-string">"sudo curl https://gist.githubusercontent.com/howthebodyworks/176149/raw/d60b505a585dda836fadecca8f6b03884153196b/supervisord.sh > /etc/init.d/supervisord"</span></span>
<span class="co"><span class="hljs-comment"># 设置该脚本为可以执行</span></span>
<span class="kw">sudo</span> chmod +x /etc/init.d/supervisord
<span class="co"><span class="hljs-comment"># 设置为开机自动运行</span></span>
<span class="kw">sudo</span> update-rc.d supervisord defaults
<span class="co"><span class="hljs-comment"># 试一下,是否工作正常</span></span>
<span class="kw">service</span> supervisord stop
<span class="kw">service</span> supervisord start</code></pre></div>
<p><strong>注意</strong>:这个脚本下载下来后,还需检查一下与我们的配置是否相符合,比如默认的配置文件路径,pid 文件路径等,如果存在不同则需要进行一些修改。</p>
<p>其实还有一个简单的方法,因为 Linux 在启动的时候会执行 <code>/etc/rc.local</code> 里面的脚本,所以只要在这里添加执行命令就可以</p>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash hljs"><span class="co"><span class="hljs-comment"># 如果是 Ubuntu 添加以下内容</span></span>
<span class="kw">/usr/<span class="hljs-built_in">local</span>/bin/supervisord</span> -c /etc/supervisord.conf</code></pre></div>
<div class="sourceCode"><pre class="sourceCode sh"><code class="sourceCode bash hljs"><span class="co"><span class="hljs-comment"># 如果是 Centos 添加以下内容</span></span>
<span class="kw">/usr/bin/supervisord</span> -c /etc/supervisord.conf</code></pre></div>
<p>以上内容需要添加在 exit 命令前,而且由于在执行 rc.local 脚本时,PATH 环境变量未全部初始化,因此命令需要使用绝对路径。</p>
<p>在添加前,先在终端测试一下命令是否能正常执行,如果找不到 supervisord,可以用如下命令找到</p>
<pre><code class="hljs swift">sudo <span class="hljs-built_in">find</span> / -name supervisord</code></pre>
</div>