天天看點

Linux下的程序管理工具:Supervisor的安裝與使用

Supervisor的介紹

Supervisor (http://supervisord.org) 是一個用 Python 寫的程序管理工具,可以很友善的用來啟動、重新開機、關閉程序(不僅僅是 Python 程序)。除了對單個程序的控制,還可以同時啟動、關閉多個程序,比如很不幸的伺服器出問題導緻所有應用程式都被殺死,此時可以用 supervisor 同時啟動所有應用程式而不是一個一個地敲指令啟動。

此外,它還有一個用途,當你有一個程序需要每時每刻不斷的跑,但是這個程序又有可能由于各種原因有可能中斷時,Supervisor可以在當程序中斷的時候自動重新啟動它。

Supervisor的安裝與配置

一、安裝:

Supervisor的安裝非常簡單,可以根據自己的喜好選擇合适的安裝方式。實在不行,可以去官網下載下傳安裝包進行安裝。

1 2 3 4 5 6 7 8 #可以通過pip進行安裝 sudo pip install supervisor   #easy_install工具 easy_install supervisor   #Ubuntu\Debian下安裝 sudo apt - get install supervisor

二、配置:

Supervisor 是一個 C/S 模型的程式,supervisord 是server 端,對應的有 client 端:supervisorctl。Supervisor 的配置檔案是/etc/supervisord.conf,通常情況下我們不需要修改它。在安裝完 supervisor 之後,我們可以運作echo_supervisord_conf 指令輸出預設的配置項。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #去除裡面大部分注釋和“不相關”的部分,主要看下這些配置: [ unix_http_server ] file = / tmp / supervisor . sock    ; UNIX socket檔案, supervisorctl會使用 ; chmod = 0700                  ; socket檔案的 mode,預設是 0700 ; chown = nobody : nogroup        ; socket檔案的 owner,格式: uid : gid   ; [ inet_http_server ]          ; HTTP伺服器,提供 web管理界面 ; port = 127.0.0.1 : 9001          ; Web管理背景運作的 IP和端口,如果開放到公網,需要注意安全性 ; username = user                ;登入管理背景的使用者名 ; password = 123                ;登入管理背景的密碼   [ supervisord ] logfile = / tmp / supervisord . log ;日志檔案,預設是 $ CWD / supervisord . log logfile_maxbytes = 50MB          ;日志檔案大小,超出會 rotate,預設 50MB logfile_backups = 10            ;日志檔案保留備份數量預設 10 loglevel = info                  ;日志級别,預設 info,其它 : debug , warn , trace pidfile = / tmp / supervisord . pid ; pid檔案 nodaemon = false                ;是否在前台啟動,預設是 false,即以 daemon的方式啟動 minfds = 1024                    ;可以打開的檔案描述符的最小值,預設 1024 minprocs = 200                  ;可以打開的程序數的最小值,預設 200   ; the below section must remain in the config file for RPC ; ( supervisorctl / web interface ) to work , additional interfaces may be ; added by defining them in separate rpcinterface : sections [ rpcinterface : supervisor ] supervisor . rpcinterface_factory = supervisor . rpcinterface : make_main _rpcinterface   [ supervisorctl ] serverurl = unix : ///tmp/supervisor.sock ; 通過 UNIX socket 連接配接 supervisord,路徑與 unix_http_server 部分的 file 一緻 ; serverurl = http : //127.0.0.1:9001 ; 通過 HTTP 的方式連接配接 supervisord   ;包含其他的配置檔案 [ include ] files = relative / directory / * . ini      ;可以是 * . conf或 * . ini

supervisord配置檔案的啟動順序是:$CWD/supervisord.conf,$CWD/etc/supervisord.conf,/etc/supervisord.conf,也可以通過 -c 選項指定配置檔案路徑。

我們可以把所有配置項都寫到 supervisord.conf 檔案裡,也可以把每個程序的配置檔案單獨分拆,放在/etc/supervisor/conf.d/目錄下,以.conf作為擴充名來添加我們需要監管的程式。如果想要把配置檔案存放在其他的路徑下,也可以通過 include 的方式把不同的程式(組)寫到不同的配置檔案裡(修改/etc/supervisord.conf 裡 include 部分的的配置)。

因為我的目的僅僅隻在于讓python腳本随着Linux系統開機自啟動,而且能夠在出現錯誤的時候自動重新開機,是以我使用的是最簡的配置:

1 2 3 4 5 [ program : py_website ] command = python / home / shawn / Desktop / test / website . py autorestart = true autostart = true user = nobody

其中,程序名稱的定義在[program:py_website]中,command是指令,autorestart是當程式崩潰時自動重新開機程式,autostart是在supervisor開啟時自動啟動,user是程序運作的使用者身份。當然,我們也可以根據自己的需求添加一些配置,如下所示:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [ program : usercenter ] directory = / home / leon / projects / usercenter ;程式的啟動目錄 command = gunicorn - c gunicorn . py wsgi : app    ;啟動指令,可以看出與手動在指令行啟動的指令是一樣的 autostart = true      ;在 supervisord啟動的時候也自動啟動 startsecs = 5          ;啟動 5秒後沒有異常退出,就當作已經正常啟動了 autorestart = true    ;程式異常退出後自動重新開機 startretries = 3      ;啟動失敗自動重試次數,預設是 3 user = leon            ;用哪個使用者啟動 redirect_stderr = true    ;把 stderr重定向到 stdout,預設 false stdout_logfile_maxbytes = 20MB    ; stdout日志檔案大小,預設 50MB stdout_logfile_backups = 20      ; stdout日志檔案備份數 ; stdout日志檔案,需要注意當指定目錄不存在時無法正常啟動,是以需要手動建立目錄( supervisord會自動建立日志檔案) stdout_logfile = / data / logs / usercenter_stdout . log   ;可以通過 environment來添加需要的環境變量,一種常見的用法是修改 PYTHONPATH ; environment = PYTHONPATH = $ PYTHONPATH : / path / to / somewhere

更多配置可以查詢supervisor的官方文檔 http://supervisord.org/configuration.html

Supervisor的使用

Supervisor 的配置檔案修改好了之後,我們就可以啟動程式了。輸入supervisorctl,就可以進入特定的 shell 界面,然後可以執行不同的指令了。

1 2 3 4 5 6 > status      # 檢視程式狀态 > stop usercenter    # 關閉 usercenter 程式 > start usercenter    # 啟動 usercenter 程式 > restart usercenter      # 重新開機 usercenter 程式 > reread     #讀取有更新(增加)的配置檔案,不會啟動新添加的程式 > update     #重新開機配置檔案修改過的程式

當然,我們也可以在bash終端下直接輸入以下指令:

1 2 3 4 5 6 $ supervisorctl status $ supervisorctl stop usercenter $ supervisorctl start usercenter $ supervisorctl restart usercenter $ supervisorctl reread $ supervisorctl update

以上兩種方法的效果是一樣的,對于剛接觸supervisor的朋友建議使用第一種,相對直覺一些。

最後

如果純粹把 Supervisor 作為一款程序管理軟體,用來實作設定開機自啟動及崩潰後自動重新開機的功能,是一件非常簡單的事情。僅僅隻需要根據這篇文章一步步的操作下去,它當然還有很多非常強大的功能,諸如:

除了 supervisorctl 之外,還可以配置 supervisrod 啟動 web 管理界面,這個 web 背景使用 Basic Auth 的方式進行身份認證。

除了單個程序的控制,還可以配置 group,進行分組管理。

經常檢視日志檔案,包括 supervisord 的日志和各個 pragram 的日志檔案,程式 crash 或抛出異常的資訊一半會輸出到 stderr,可以檢視相應的日志檔案來查找問題。

更多的内容可以翻閱官方的文檔(http://supervisord.org/index.html),或者借助搜尋引擎進行拓展閱讀。

Supervisor的錯誤記錄

最早之前設定好 Supervisor 後,我的網站可用性監控腳本就一直随着開機自動啟動,沒有出現啥問題。今天為了測試Nginx + Supervisor + Gunicorn的Flask項目環境配置,重建立了一個配置檔案,然後出現了一堆問題。

unix:///tmp/supervisor.sock 不存在的錯誤

預設的配置檔案是下面這樣的,但是這裡有個坑需要注意,supervisord.pid 以及 supervisor.sock 是放在 /tmp 目錄下,但是 /tmp 目錄是存放臨時檔案,裡面的檔案是會被 Linux 系統删除的,一旦這些檔案丢失,就無法再通過 supervisorctl 來執行 restart 和 stop 指令了,将隻會得到 unix:///tmp/supervisor.sock 不存在的錯誤。

1 2 3 4 file = / var / run / supervisor . sock    ; ( the path to the socket file ) logfile = / var / log / supervisor / supervisord . log ; ( main log file ; default $ CWD / supervisord . log ) pidfile = / var / run / supervisord . pid ; ( supervisord pidfile ; default supervisord . pid ) serverurl = unix : ///var/run/supervisor.sock ; use a unix:// URL  for a unix socket

權限問題

設定好配置檔案後,應先建立上述配置檔案中新增的檔案夾。如果指定了啟動使用者 user,這裡以 oxygen 為例,那麼應注意相關檔案的權限問題,包括日志檔案,否則會出現沒有權限的錯誤。例如設定了啟動使用者 oxygen,然後啟動 supervisord 出現錯誤

Error: Cannot open an HTTP server: socket.error reported errno.EACCES (13)

就是由于上面的配置檔案中 /var/run 檔案夾,沒有授予啟動 supervisord 的使用者 oxygen 的寫權限。/var/run 檔案夾實際上是連結到 /run,是以我們修改 /run 的權限。

sudo chmod 777 /run

一般情況下,我們可以用 root 使用者啟動 supervisord 程序,然後在其所管理的程序中,再具體指定需要以那個使用者啟動這些程序。

Error: Another program is already listening on a port that one of our HTTP servers is configured to use. Shut this program down first before starting

解決方法:

1 2 find / - name supervisor . sock unlink / name / supervisor . sock

error: <class 'socket.error'="">, [Errno 13] Permission denied: file: /usr/lib/python2.7/socket.py line: 224