首页 > 系统相关 >ubuntu 使用systemd systmctl配置服务开机启动,服务包含多个子进程

ubuntu 使用systemd systmctl配置服务开机启动,服务包含多个子进程

时间:2023-12-07 19:14:40浏览次数:36  
标签:systemd 21 service systmctl sh ubuntu 进程 bash

背景:

需求是这样的,有一个服务,有6个子进程,每次系统重启都要一个一个启动,很繁琐,需要配置到开机启动里

而目前系统已经抛弃了chkconfig的配置方式,转而使用systemd来配置开机启动进程了

所以需求就变成了把服务配置到systemd开机启动中,服务包含6个子进程

配置这个踩了不少坑,特地记录下:

首先这里贴出systemd的基础知识:

https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html

https://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html

https://blog.csdn.net/bandaoyu/article/details/124358513

 

下面为我主要遇到的问题:

1.Syntax error: "(" unexpected

参考文档:https://blog.csdn.net/weixin_45312249/article/details/126368386

                  https://www.u72.net/jishu/show-88269.html

这个问题的原因为:

debian/ubuntu上sh命令默认是指向dash,而不是bash

又因为dash是比bash还轻量的,只支持基本的shell功能,

其中不包括刚才那种数组初始化,所以才会识别不了,直接报Syntx error

 

解决办法:
第一种方案:直接用 bash test.sh,或者./test.sh,这两种方式来执行脚本。这里每次都需要指定用bash解析脚本

第二种方案:通过配置文件取消dash(一劳永逸的方法)
1) sudo dpkg-reconfigure dash 在选择项中选No,搞定了!

我分析后认为既然ubuntu使用dash肯定有他的考量,我直接使用bash就行,所以我写的启动脚本如下

其中需要有个传参:start|stop|status|restart,就是把每个模块的启动脚本合到一个脚本 startkd.sh

#!/bin/bash

bash /data/deploy/LBS/service/2d-tile-server/2dtile.sh $1
bash /data/deploy/LBS/service/3d-tile-server/3dtile.sh $1
bash /data/deploy/LBS/service/krs-pdds/krs-pdds.sh $1
bash /data/deploy/LBS/service/webapi/run.sh $1
bash /data/deploy/LBS/service/mspserver/run.sh $1
bash /data/deploy/LBS/service/pdds-search/pdds-search.sh $1

 

2.直接执行启动脚本可以实现程序启停,但是通过systemctl start 程序起不来

这个问题真的困扰了我好久,还好一步一步去摸索逐渐摸清了头绪

(1)systemctl 配置参数Type

首先参照这个文档:https://blog.csdn.net/propor/article/details/130871521

在/usr/lib/systemd/system下新建文件kd.service

[Unit]
Description=Kuandeng server
After=network.target

[Service]
Type=simple
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/java11/bin"
User=appadmin
Group=appadmin
ExecStart=/data/deploy/LBS/service/startkd.sh start
ExecStop=/data/deploy/LBS/service/startkd.sh stop
Restart=on-failure

[Install]
WantedBy=multi-user.target

配置完成,执行

sudo systemctl daemon-reload

systemctl start kd

本以为一气呵成的时候,一看进程傻眼了,程序都没起来

一开始只会折腾ExecStart这个启动命令,但是改了一圈一点用没有

我逐渐意识到可能不是启动命令的问题,直到看到这篇文章才有了头绪

https://www.cnblogs.com/startscorpio/p/12915088.html

Type类型有:
simple(默认):#以Execstart字段启动的进程为主进程

  forking:#Execstart 字段以fox()方式启动,,此时父进程将退出,子进程将成为主进程(后台运行),一般都设置为forking

  oneshot : #类似于simple,但只执行一次,systemd会等他执行完,才执行其他服务

   dbus: #类似于simple,但会等待D—Bus信号后启动

  notify: #类似与simple ,但结束后会发出通知信号,然后systemd才启动其他服务

  idle: #类似与simple,但要等到其他任务都执行完,才启动该服务

 

我不禁灵机一动,forking不就是正适合我的应用场景吗,start.sh主进程执行完退出,他启动的子进程常驻后台

然后我着重搜索关键词:systemd forking

找到了这篇:https://blog.csdn.net/icandoit_2014/article/details/121467310

觉得可行之后我修改了kd.service脚本

[Unit]
Description=Kuandeng server
After=network.target

[Service]
Type=forking
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/java11/bin"
User=appadmin
Group=appadmin
ExecStart=/data/deploy/LBS/service/startkd.sh start
ExecStop=/data/deploy/LBS/service/startkd.sh stop
Restart=on-failure

[Install]
WantedBy=multi-user.target

sudo systemctl daemon-reload

systemctl start kd

一顿操作之后还是报错,于是来到第二个问题

 

(2)systemd启动是如何判断主进程和健康程度的

操作完,还是没有起来,我又去仔细查看了那个forking文档,直到看到这句给了我启发

回到forking类型的服务。由于daemon类的进程会有一个瞬间退出的中间父进程(如上面PID=7913的nginx进程),systemd是如何知道哪个进程是应该被监控的服务主进程(Main PID)呢?

答案是靠猜。没错,systemd真的就是靠猜的。当设置Type=forking时,有一个GuessMainPID指令其默认值为yes,它表示systemd会通过一些算法去猜测Main PID。当systemd的猜测无法确定哪个为主进程时,后果是严重的:systemd将不可靠。因为systemd无法正确探测服务是否真的失败,当systemd误认为服务失败时,如果本服务配置了自动重启(配置了Restart指令),重启服务时可能会和当前正在运行但是systemd误认为失败的服务冲突(比如出现端口已被占用问题)。

多数情况下的猜测过程很简单,systemd只需去找目前存活的属于本服务的leader进程即可。但有些服务(少数)情况可能比较复杂,在多进程之间做简单的猜测并非总是可靠。

systemd是如何判断主进程呢,如果靠猜的话,那得保证执行过程尽量干净才行,这样他才会准确,突然我想到了手动执行脚本时,里面有一些报错

虽然不影响服务启动,但是会影响systemd判断,

 于是我找到最后一个启动脚本,把里面的报错排除了,确保启动没有异常信息后,再执行

sudo systemctl daemon-reload

systemctl start kd

这时候奇迹出现了!服务起来了!

 但是高兴的太早了,仔细一看少了一个服务

本来以为是不是脚本顺序问题,特地调整了几次startkd.sh脚本启动顺序,还是无济于事

于是我想到要不去看看那个服务的启动脚本

 好家伙果然有报错,那就说得通了,systemd发现启动有报错,所以把这个进程杀了,这也就是为什么手动执行脚本能正常启动,systemd起不来的原因了!

看到这里我不禁感叹systemd这个进程做的真的很完善

于是后面就着重处理这个问题了,其实本机配置了默认java_home,所以有没有这个配置无所谓,但是这个配置在哪里呢,找了一圈没找到

后来想到了搜索下试试

 这不就找到了吗,果断把这行注释掉

然后再执行

sudo systemctl daemon-reload

systemctl start kd

这次重终于成功了!6个进程都起来了

 

3.意外发现的其他问题场景:systemd systemctl ExecStart超时处理

参考文档:https://blog.csdn.net/xht555/article/details/110674215

执行“systemctl status 服务名”查看服务状态,可以看到由于systemd一直在等待run.sh脚本执行完成,但超时时间到了,自动结束了服务:leanote.service start operation timed out. Terminating.

# systemctl status leanote.service
● leanote.service
Loaded: loaded (/usr/lib/systemd/system/leanote.service; enabled; vendor preset: disabled)
Active: failed (Result: timeout) since 五 2020-12-04 21:32:28 CST; 2min 24s ago
Process: 4279 ExecStart=/data/leanote/bin/run.sh & (code=killed, signal=TERM)

12月 04 21:30:58 db-srv run.sh[4279]: DEBUG 21:30:58 revel controller_type.go:64: Registered controller: App\memberindex section=controller
12月 04 21:30:58 db-srv run.sh[4279]: DEBUG 21:30:58 revel controller.go:523: RegisterController:Registered controller section=controller controller=App\\memberindex
12月 04 21:30:58 db-srv run.sh[4279]: DEBUG 21:30:58 revel controller_type.go:64: Registered controller: App\memberuser section=controller
12月 04 21:30:58 db-srv run.sh[4279]: DEBUG 21:30:58 revel controller.go:523: RegisterController:Registered controller section=controller controller=App\\memberuser
12月 04 21:30:58 db-srv run.sh[4279]: DEBUG 21:30:58 revel server.go:106: InitServerEngine: Found server engine and invoking section=server name=go
12月 04 21:30:58 db-srv run.sh[4279]: Listening on.. 0.0.0.0:9000
12月 04 21:32:28 db-srv systemd[1]: leanote.service start operation timed out. Terminating.
12月 04 21:32:28 db-srv systemd[1]: Failed to start leanote.service.
12月 04 21:32:28 db-srv systemd[1]: Unit leanote.service entered failed state.
12月 04 21:32:28 db-srv systemd[1]: leanote.service failed.

解决这个问题也很简单,借助“bash -c”,bash -c的作用是将一个长字符串当做一条完整的命令来执行,如果在脚本路径后面加上后台运行符号(&),run.sh脚本就会在后台运行,不会一直处于挂起状态,systemd也就不会一直等待run.sh执行完成了。经过测试,完全符合预期,因此,最终的解决方案是:

ExecStart=/bin/bash -c "/data/leanote/bin/run.sh &"

标签:systemd,21,service,systmctl,sh,ubuntu,进程,bash
From: https://www.cnblogs.com/allay/p/17883733.html

相关文章

  • ubuntu20.04下搭建EDK2开发环境
    EDK2是UEFI应用程序的官方开发环境。它是由开源的Tianocore项目开发的,英特尔、惠普和微软是该项目的主要贡献者。虽然它可能比GNU-EFI大,但它有更多的功能,因此,一些操作系统开发人员可能更喜欢它而不是GNU-EFI。什么是EDK2?EDK2完全实现了UEFI规范。它包含开放虚拟机固件(OVMF)UE......
  • VMware桥接模式设置Ubuntu 22固定IP
    Ubuntu22桥接模式下面设置固定IP1、进入netplan网络配置目录cd/etc/netplan修改sudovim00-network-manager-all.yaml我的文件是:01-network-manager-all.yaml2、查看主机的网络信息Windows系统ipconfigLinux系统ifconfig例如主机网络信息: 3、修改配置......
  • Ubuntu上文件系统根目录磁盘空间扩充
    今天使用Ubuntu的时候,出现了磁盘根目录空间不足的提示,需要我们对于根目录磁盘空间进行扩充。1.打开终端输入命令,安装gparted管理器sudoapt-getinstallgparted接着输入Y接受,安装完成后输入命令sudogparted打开管理器2.进入gparted管理器界面如下,选择/dev/sda3根目......
  • ubuntu中vim乱码以及执行shell脚本时出现乱码
    vim打开文件中文出现乱码情况,可以参考如下办法:在vim/usr/share/vim/vimrc文件末尾中加入(这个vimrc文件是Vim的系统级配置文件、文档、插件、语法高亮定义、颜色方案等)setencoding=utf-8setfileencodings=utf-8,gbksettermencoding=utf-8保存退出就ok了 如果还不行......
  • 迅为RK3588开发板定制Ubuntu和Debian系统-系统定制(无法联网)
    在上一个小节中讲解了ubuntu和debian文件系统的定制,但那是在可以运行脚本正常构建系统的前提下,而本小节则是针对部分特殊用户无法联网的情况。在source目录下存放了已经构建完成的压缩包,如下图所示然后使用以下命令将该压缩包解压到build目录下,解压完成如下图所示:tar-vxf......
  • Systemd 入门教程:实战篇
    一、开机启动对于那些支持Systemd的软件,安装的时候,会自动在/usr/lib/systemd/system目录添加一个配置文件。如果你想让该软件开机启动,就执行下面的命令(以httpd.service为例)。$sudosystemctlenablehttpd上面的命令相当于在/etc/systemd/system目录添加一个符号链接,指......
  • Systemd 入门教程:命令篇
    Systemd是Linux系统工具,用来启动守护进程,已成为大多数发行版的标准配置。本文介绍它的基本用法,分为上下两篇。今天介绍它的主要命令,下一篇介绍如何用于实战。一、由来历史上,Linux的启动一直采用init进程。下面的命令用来启动服务。$sudo/etc/init.d/apache2start#......
  • 如何优雅的使用 Systemd 管理服务
    背景:我们在构建Kubernetes容器化平台时,会在节点上部署各种agent,虽然容器化当道的今天很多程序可以直接采用docker方式进行运行,但我们在整个集群内部仍然大量使用了 systemd 来管理基础服务。不过在使用过程中发现可能出现相关依赖的服务组件异常后导致节点上服务不可用......
  • systemd使用示例
    [Unit]Description=monitorsg_ai_framework_boxAfter=network.target[Service]User=rootType=forkingExecStart=/data/script/run/start.shExecStop=/data/script/run/stop.shPrivateTmp=trueRestart=always[Install]WantedBy=multi-user.target 1.启动nfs服务systemctl s......
  • ubuntu 22.04 设置网桥 - netplan
    添加/编辑虚拟网桥/etc/netpaln/br0.yaml ipv4dhcp:network:version:2ethernets:eno8303:#替换为实际网卡dhcp4:falsedhcp6:falsebridges:br0:interfaces:[eno8303]#替换为实际网卡dhcp4:trueparameters:......