在《使用shell编写的极简WatchDog》中编写了一个具有看门狗特性的服务,进一步需要将其设为自动启动并在后台持续运行,遇到中断后能够自动重新启动服务。在Ubuntu中实现开机自动启动主要有几种方法:
- 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文件、伺服控制脚本、伺服器程序(含看门狗和应用服务)等文件,设置为可执行,同时相互之间的调用必须一致。
需要注意的是,自动启动的一次性程序和一直运行的伺服程序运行方式有很大的不同,需要自行挂到后台持续运行、然后退出控制程序,还需要实现意外中断后进程重启或网络重连等自动恢复的能力。
启动步骤
包括:
- 执行任务(服务)的script( 一般放在/etc/init.d,Merlin固件在/opt/etc/init.d)。
- WatchDog(看门狗)服务,主要监视任务进程的状态,如果退出则重新拉起。
- 控制函数脚本,用于systemd来启动后台服务进程,包括:
- 控制脚本(nohup启动)
- *.service文件
- 或在rc.local文件。
1、任务脚本
完整的script如下(包含服务控制逻辑、看门狗和任务进程函数):
#!/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(修改里面的服务器地址和用户账号信息),然后修改运行权限。
sudo chmod +x ssht
- 可以拷贝到/etc/init.d/(Merlin /opt/etc/init.d)目录下。
2、控制脚本
编写一个控制脚本,如下:
nohup /etc/init.d/ssht &
- ssht文件可以放到其它目录,需要设为可执行,在上面命令中替换路径即可。
- 将上面内容保存为sshtd,保存到/etc/init.d目录下,将其设为可执行。
如果使用rc.local,可以将上面内容直接写入/etc/rc.local,需要将其设为可执行。
sudo chmod +x /etc/rc.local
按照下面的方法启用rc.local服务,由systemd提供。
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"
- 参见
- https://superuser.com/questions/352268/can-i-make-ssh-fail-when-a-port-forwarding-fails
- Using command:"man ssh" to view ssh manual page.
在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没有效果),因此不需要使用进程检测。直接运行一个循环,正常时为服务,遇异常时退出,自动重新运行。
3、启用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
4、创建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
5、测试
下面针对使用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等环境。
- 可以包装为容器执行。