使用shell編寫的極簡Ubuntu Service

在《使用shell編寫的極簡WatchDog》中編寫了一個具備看門狗特性的服務,進一步須要將其設爲自動啓動並在後臺持續運行,遇到中斷後可以自動從新啓動服務。在Ubuntu中實現開機自動啓動主要有幾種方法:shell

  • rc.local,這是傳統的Linux系統初始化方法,只須要將命令寫入/etc/rc.local便可開機自動運行。
    • 但在Ubuntu裏因爲新版使用systemd,再也不有缺省的rc.local文件須要對服務配置一些設置,後面介紹。
  • rcS.d,在Ubuntu 16.04以上版本,採用systemd作系統服務,rcS.d也不會自動啓用了(在lib/systemd/system/rcS.service被設爲/dev/null,能夠修改後予以啓用,與rc-local.service機制相似)。
  • systemd,是Ubuntu 16.04以上版本的啓動控制服務,能夠有兩種方法啓動本身的程序
    • 使用rc.local的兼容模式,開啓/lib/systemd/system/rc.local.service服務,而後編寫/etc/rc.local文件便可,下面詳述。
    • 使用systemd的內置機制,須要編寫*.service文件、伺服控制腳本、伺服器程序(含看門狗和應用服務)等文件,設置爲可執行,同時相互之間的調用必須一致。

須要注意的是,自動啓動的一次性程序和一直運行的伺服程序運行方式有很大的不一樣,須要自行掛到後臺持續運行、而後退出控制程序,還須要實現意外中斷後進程重啓或網絡重連等自動恢復的能力。編程

啓動步驟

包括:ubuntu

  1. 執行任務(服務)的script( 通常放在/etc/init.d,Merlin固件在/opt/etc/init.d)。
  2. WatchDog(看門狗)服務,主要監視任務進程的狀態,若是退出則從新拉起。
  3. 控制函數腳本,用於systemd來啓動後臺服務進程,包括:
    • 控制腳本(nohup啓動)
    • *.service文件
    • 或在rc.local文件。

一、任務腳本

完整的script以下(包含服務控制邏輯、看門狗和任務進程函數):vim

#!/bin/sh

#=======================
grepFlag='220.*openthings'

#=======================
start() {
  echo "Start Service..."
  while true; do
    ret=`ps -aux | grep "$grepFlag" | grep -v grep | wc -l`
    if [ $ret -eq 0 ]; then
      nohup sshpass -p password ssh -y -NgL 2200:localhost:22 username@openthings.x.x &
    fi
    status
    sleep 6
  done
}

#=======================
stop() {
  PID=`ps -aux | grep "$grepFlag" | grep -v grep | awk -F " " '{print $1}'`
  kill -9 $PID
  echo "Stop Service, PID="$PID
}

#=======================
restart() {
  echo "Restart Service..."
  Stop
  Start
  echo "Restarted Service,PID="$PID
}

#=======================
status() {
  echo "Service status."
  ps -aux | grep "$grepFlag" | grep -v grep
}

case "$1" in
  start) start ;;
  stop)  stop  ;;
  restart) restart ;;
  status) status ;;
  *)
    echo "Usage: (start|stop|restart|status)"
    exit 1
    ;;
esac

echo "Service Toosl Done."
exit 0

將上面的文件保存爲ssht(修改裏面的服務器地址和用戶帳號信息),而後修改運行權限。bash

sudo chmod +x ssht
  • 能夠拷貝到/etc/init.d/(Merlin /opt/etc/init.d)目錄下。

二、控制腳本

編寫一個控制腳本,以下:服務器

nohup /etc/init.d/ssht &
  • ssht文件能夠放到其它目錄,須要設爲可執行,在上面命令中替換路徑便可。
  • 將上面內容保存爲sshtd,保存到/etc/init.d目錄下,將其設爲可執行。

若是使用rc.local,能夠將上面內容直接寫入/etc/rc.local,須要將其設爲可執行。網絡

sudo chmod +x /etc/rc.local

按照下面的方法啓用rc.local服務,由systemd提供。ssh

Dropbear遇到的幾個問題和解決辦法

在《Asus Merlin開機啓動設置與服務腳本編寫》中的ssh服務器使用的是Dropbear,系統啓動伺服程序採用Entware調用/opt/etc/init.d中的腳本方式完成。在Merlin固件(384.9)上遇到下面的問題:函數

  • 執行nohup ps | grep 時,沒法返回 dropbear 客戶端ssh的進程信息,其它進程沒有問題,在控制檯執行也沒有問題。
    • ssh進程從列表中無端消失了,致使使用wc -l 時返回的進程數是0。
    • 網上有人說多是busybox+nohup+dropbear+arm這一套組合的問題。
    • 暫時無解決方案。
  • Dropbear在鏈接出故障後只是warning而不退出,致使以進程爲基礎的服務狀態判斷失誤,沒法正常從新啓動。
    • 能夠經過設置-o "ExitOnForwardFailure yes"選項來解決,設爲與OpenSSH的同樣。

設置鏈接異常時退出的參數,以下:測試

-o "ExitOnForwardFailure yes"

在Asus Merlin設備上,上面的任務函數能夠進一步優化爲:

start() {
  echo "Start SSHT Service..."
  while true; do
    ssh -K 30 -o "ExitOnForwardFailure yes" -y -NgR 2200:localhost:22 user@openthings.x.x -i /opt/etc/ssh/id_dropbear_ecdsa
    sleep 10
  done
}

由於ssh缺省採用前臺模式運行(加-f參數爲後臺運行,nohup沒有效果),所以不須要使用進程檢測。直接運行一個循環,正常時爲服務,遇異常時退出,自動從新運行。

三、啓用rc.local服務

  • 注意:
    • 這一段的內容適用於使用rc.local文件的狀況。
    • 若是直接使用systemd,則不須要下面的操做。

在ubuntu 16.04以上版本(含18.04等)使用systemd,提供了一個兼容的執行rc.local的服務,位於/lib/systemd/system目錄。不過,缺省沒有啓用,須要作一些修改。

編輯/lib/systemd/system/rc-local.service文件,以下:

sudo vim /lib/systemd/system/rc-local.service

在文件後加上以下內容:

[Install]
WantedBy=multi-user.target
Alias=rc-local.service

從新載入服務配置。

sudo systemctl daemon-reload

查看一下服務的狀態。

sudo systemctl status rc-local

四、建立Service文件

  • 注意:
    • 這一段的內容適用於使用systemd service的狀況。

若是直接使用systemd,須要編寫一個ssht.service文件,放到/lib/systemd/system目錄下,內容以下。

[Unit]
Description=Secure Shell server Tunnel
After=network.target
#After=sshd.service

[Service]
Type=forking
ExecStart=/home/smt/openthings/tutools/ssht start
ExecStop=/home/smt/openthings/tutools/ssht stop
TimeoutSec=0
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Alias=ssht.service
  • 其中,將啓動文件設爲上面的控制腳本,後臺進程啓動後會退出。

而後,從新載入服務配置。

sudo systemctl daemon-reload

查看一下服務的狀態。

sudo systemctl status ssht

五、測試

下面針對使用systemd的狀況。

咱們在上一步建立了一個名稱爲ssht的服務。使用下面的命令進行測試。

# 從新載入systemd的服務配置。
sudo systemctl daemon-reload

# 查看服務的狀態。
sudo systemctl status ssht

# 啓動服務。
sudo systemctl start ssht

# 中止服務。
sudo systemctl stop ssht

# 重啓服務。
sudo systemctl restart ssht

查看進程信息。

ps -aux | grep "220\|openthings" | grep -v grep

到遠程查看端口信息。

netstat -a | grep "220"

正常狀況下,應該能夠看到映射的端口。

從新啓動機器後,將會自動斷開網絡鏈接致使ssh進程退出,而後過6秒後被看門狗從新拉起,從新鏈接,恢復服務端口。

小結

經過上面的方法和步驟:

  • 使用shell腳本建立了一個任務文件(能夠執行系統命令)。
  • 任務腳本支持看門狗功能,退出後將任務進程自動從新拉起。
  • 能夠經過rc.local文件來自動啓動並在後臺運行。
  • 能夠經過systemd的ssht.service文件來自動啓動並在後臺運行。
  • 能夠支持Merlin等固件和EntWare/OptWare等環境。
  • 能夠包裝爲容器執行。

更多參考

相關文章
相關標籤/搜索