我有一个编译为单个二进制文件的 go web 应用程序,我试图通过 init.d 进行管理。这是我的 init.d 脚本:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/my-go-app
DAEMON_ARGS="--logFile /var/log/my-go-app/my-go-app.log"
NAME=my-go-app
DESC=my-go-app
RUNDIR=/var/run/my-go-app
PIDFILE=$RUNDIR/my-go-app.pid
test -x $DAEMON || exit 0
if [ -r /etc/default/$NAME ]
then
. /etc/default/$NAME
fi
. /lib/lsb/init-functions
set -e
case "$1" in
start)
echo -n "Starting $DESC: "
mkdir -p $RUNDIR
touch $PIDFILE
chown ubuntu:ubuntu $RUNDIR $PIDFILE
chmod 755 $RUNDIR
if [ -n "$ULIMIT" ]
then
ulimit -n $ULIMIT
fi
if start-stop-daemon --start --quiet --umask 007 --pidfile $PIDFILE --chuid ubuntu:ubuntu --exec $DAEMON -- $DAEMON_ARGS
then
echo "$NAME."
else
echo "failed"
fi
;;
stop)
echo -n "Stopping $DESC: "
if start-stop-daemon --stop --retry forever/TERM/1 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON
then
echo "$NAME."
else
echo "failed"
fi
rm -f $PIDFILE
sleep 1
;;
restart|force-reload)
${0} stop
${0} start
;;
status)
echo -n "$DESC is "
if start-stop-daemon --stop --quiet --signal 0 --name ${NAME} --pidfile ${PIDFILE}
then
echo "running"
else
echo "not running"
exit 1
fi
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
问题是,当我运行 service my-go-app start
时,它只是挂起,如下所示:
ubuntu@ip-10-0-0-40:~$ service my-go-app start
Starting my-go-app:
永远不会回来。在这种状态下,如果我打开一个单独的终端,我可以通过检查日志文件看到应用程序正在运行,但是/var/run/my-go-app/my-go-app.pid 中没有任何内容(尽管pid 文件确实被创建了)。
有没有人遇到过(并希望解决过)这个问题?如何将我的 go 应用作为 init.d 守护进程运行?
编辑:
我能够通过在启动服务时将“-b -m”命令行标志添加到 start-stop-daemon
来让它工作。该行现在看起来像这样:
start-stop-daemon -b -m --start --quiet --umask 007 --pidfile $PIDFILE --chuid ubuntu:ubuntu --exec $DAEMON -- $DAEMON_ARGS
我对这种方法的担忧是 start-stop-daemon
联机帮助页中的警告:
-b, --background
Typically used with programs that don't detach on their own. This option will force start-stop-daemon to fork before starting the process, and
force it into the background. WARNING: start-stop-daemon cannot check the exit status if the process fails to execute for any reason. This is
a last resort, and is only meant for programs that either make no sense forking on their own, or where it's not feasible to add the code for
them to do this themselves.
这对我来说似乎是个坏主意,因为听起来 SysV 不知道进程是否终止。我理解正确吗?有没有其他人尝试过这种方法?
最佳答案
如果您正在运行带有 Upstart 的系统,您可以使用此脚本:
start on runlevel [2345]
stop on runlevel [016] or unmounting-filesystem
# Replace {soft} and {hard} with the soft and hard resource limits you desire
#limit nofile {soft} {hard}
umask 007
setuid ubuntu
setgid ubuntu
exec /usr/bin/my-go-app --logFile /var/log/my-go-app/my-go-app.log
您还可以在您的应用程序已启动并正确初始化的位置将以下代码添加到您的守护程序中:
if ("yes" == os.Getenv("MYAPP_RAISESTOP")) {
p, err := os.FindProcess(os.Getpid())
p.Signal(syscall.SIGSTOP)
}
以及上述 upstart 工作的以下行:
env MYAPP_RAISESTOP="yes"
expect stop
如果 if () { }
不是真正的 Go 语法,我很抱歉;我是一个 C 程序员哈哈(虽然 () 和 {} 里面的东西是真实的,我做了一点研究:)。
最后一点确保 Upstart 会等到您的应用程序正确设置后才会触发 started
事件。如果没有其他工作在等待您的应用程序,那么您真的不需要它。
关于golang webapp init.d 脚本挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25494400/