IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Linux后台运行服务的几种方式

    chancel发表于 2023-12-03 00:00:00
    love 0
    <![CDATA[

    Linux后台运行程序的方法有以下常见的几种

    • ctrl+z
    • screen
    • nohup
    • supervisor
    • systemd

    以下实践基于Ubuntu2204系统,理论上其他Linux发行版也适用

    1. 区分使用场景

    如果命令执行时间稍长且不需要查看输出结果,使用&作为后台运行标志或在运行之后使用ctrl+z挂起进程到后台,结合jobs以及fg来切换当前会话的后台任务

    如果希望命令在会话结束之后保持运行,则需要考虑使用screen与nohup,screen适合运行一些短时任务(如脚本),nohup则适合运行一些长时任务(如代理程序)

    如果对日志记录/权限控制方面有需求,screen与nohup就显得不太够用了,这个时候适合使用supervisor与systemd等daemon程序创建后台守护进程(Web后台)

    2. 使用例子

    2.1. ctrl-z

    以ping为例,向114.114.114.114发送4个icmp包并记录结果

    Bash
    ping -c 4 114.114.114.114 > 114-ping.txt &
    

    &符号的效果与运行之后ctrl-z是类似的,如果不希望记录结果,要随时方便切换回来查看结果,则可以考虑使用ctrl+z挂起进程到后台

    Bash
    ping 114.114.114.114 # 按ctrl+z挂起
    

    挂起后,使用jobs -l查看被挂起的后台进程

    Bash
    ➜  jobs -l
    [1]  - 241975 suspended  ping 114.114.114.114
    

    使用指令fg %num可以将后台任务进程重新唤起,可以看到进程重新执行了

    Bash
    ➜  fg %1
    64 bytes from 114.114.114.114: icmp_seq=3 ttl=117 time=6.19 ms
    64 bytes from 114.114.114.114: icmp_seq=4 ttl=117 time=6.37 ms
    

    以上的方法只在当前会话有效,如果会话结束,则程序会结束运行

    2.2. screen

    如果希望程序在会话结束之后继续运行,则可以考虑使用screen,部分Linux发行版需自行安装该程序

    Bash
    sudo apt install screen
    

    使用screen创建一个ping的会话

    Bash
    screen -R ping
    

    退出会话之后,重新创建会话并再次使用创建ping会话的指令

    Bash
    screen -R ping
    

    可以看到命令依旧在运行

    2.3. nohup

    screen相较于nohup而言,更适合执行一些脚本,nohup则适合运行长时任务,nohup全称是no hang up,即不挂起地运行程序,无视系统的Hang Up信号

    在网络上搜索nohup的使用方法,比较常见的运行方法如下

    Bash
    nohup command > command.log 2>&1 &
    

    这里面比较费解的是2>&1的含义

    在Linux中定义了三种输入输出,分别是

    • 0:标准输入
    • 1:标准输出
    • 2:错误输出

    标准输出1在运行时可以不写,所以执行command > command.log等价于command 1 > command.log,在理解到这点后,2>&1的含义就比较清晰了,表示将错误输出2重定向到标准输出变量&1中,再结合>一起输出到日志中的意思

    把命令写全了等价于

    Bash
    nohup command 1> command.log 2>&1 &
    

    注意:nohup command 2>&1 > command.log & 是不正确的写法(感谢leafee98指正),错误输出(2)被重定向到标准输出(1),随后标准输出(1)被重定向到文件,所以错误输出失效了

    以nc程序扫描端口为例,用nuhup执行如下

    Bash
    nohup nc -ztv -w 2 114.114.114.114 1-100 > /tmp/nc.log 2>&1 &
    

    检查/tmp/nc.log文件,可以看到正在执行

    Bash
    ➜  ~ tail -f /tmp/nc.log 
    nc: connect to 114.114.114.114 port 1 (tcp) timed out: Operation now in progress
    nc: connect to 114.114.114.114 port 2 (tcp) timed out: Operation now in progress
    ...
    

    nohup用于执行一些简易后台任务效果还是非常不错的,但如果对输出日志切割、运行用户、开机自启等有要求,则需要考虑daemon类程序,如supervisor与systemd

    2.4. supervisor

    supervisor是与systemd类似的轻量级进程控制系统,用于长时间运行程序,常用于web后台程序、代理程序等,在大部分Linux发行版上需要自行安装,如在ubuntu2204中安装并启动服务

    Bash
    sudo apt install supervisor
    sudo systemctl enable supervisor
    sudo systemctl start supervisor
    

    supervisor相较于nohup,支持非常丰富的参数设定,环境设定以及守护进程,安装supervisor后,以同步软件syncthing为例

    创建/etc/supervisor/conf.d/syncthing.conf文件,具体如下

    INI
    [program:syncthing]
    directory=/home/apps/syncthing/syncthing-linux-amd64-v1.19.0
    command=/home/apps/syncthing/syncthing-linux-amd64-v1.19.0/syncthing
    autostart=true
    autorestart=true
    startsecs=10
    stdout_logfile=/var/log/supervisor/%(program_name)s-stdout.log
    stdout_logfile_maxbytes=5MB
    stdout_capture_maxbytes=5MB
    stdout_logfile_backups=5
    stderr_logfile=/var/log/supervisor/%(program_name)s-stderr.log
    stderr_logfile_maxbytes=5MB
    stderr_capture_maxbytes=5MB
    stderr_logfile_backups=5
    user = apps
    environment = HOME="/home/apps/syncthing/syncthing-linux-amd64-v1.19.0"
    

    大部分参数非常简洁易懂,其中

    • autorestart:开机自启
    • stdout_*:标准输出日志
    • strerr_*:异常输出日志
    • user:运行程序的用户
    • environment:设定运行的环境参数

    使新创建的服务生效

    Bash
    sudo supervisorctl update
    

    supervisorctl支持多个操作,如

    • update:表示更新服务列表,对新建/修改的服务重新运行
    • status:查看所有服务运行状态
    • start/stop/restart:启动/停止/重启服务

    2.5. systemd

    在2015年后,systemd是大部分发行版自带用于取代SysV init的系统套件,在引导过程中提供可靠并行性以及对进程、守护进程、服务和挂载点进行集中管理的程序

    如果对现代Linux操作系统熟悉,对systemd大概率是不会感到陌生的,systemd是比较重量级的系统套件,除非有明确使用需求,否则一般不考虑作为小应用的后台运行方式,supervisor足够应付绝大部分应用场景了

    systemd常见用户单元配置目录如下(区别于系统单元配置)

    • $HOME/.config/systemd/user
    • /usr/lib/systemd/user
    • $HOME/.local/share/systemd/user
    • /etc/systemd/user

    还是以同步软件syncthing为例,添加一个配置文件$HOME/.config/systemd/user/syncthing.service,内容如下

    INI
    [Unit]description=Sync Files
    Documentation=https://syncthing.net
    After=network.target
    
    [Service]
    Type=simple
    Environment=HOME="/home/apps/syncthing/syncthing-linux-amd64-v1.19.0"
    ExecStart=/home/apps/syncthing/syncthing-linux-amd64-v1.19.0/syncthing
    # 日志记录需systemd版本 > 240
    StandardOutput=append:/home/apps/syncthing/syncthing-linux-amd64-v1.19.0/logs/standard-output.log
    StandardError=append:/home/apps/syncthing/syncthing-linux-amd64-v1.19.0/logs/standard-error.log
    
    [Install]
    WantedBy=multi-user.target
    

    启动服务

    Bash
    systemctl start syncthing --user
    

    如修改配置单,需要运行刷新systemd

    Bash
    systemctl daemon-reload --user
    

    配置单具体怎么写?可以参考 Systemd入门教程:实战篇 - 阮一峰,以下是对配置文件的重点部分进行说明

    INI
    [Unit]description= # 程序描述
    Documentation= # 参考文档
    After= # 服务启动顺序,如network.target表示在network服务启动之后再启动该服务
    Before= # 同上,表示在某服务启动之前
    Wants= # 服务弱依赖,在启动服务前确保wants所指服务已正常启动
    Requires= # 强依赖关系,如果Requires所指服务已停止运行,则本服务也会结束
    
    [Service]
    Type= # 服务类型,值类型可为simple/fork/oneshot/dbus/notify/idle
    Environment= # 环境变量在此添加
    EnvironmentFile= # 环境变量文件(如.bashrc)
    ExecStart= # 启动进程时执行的命令
    ExecReload= # 重启服务时执行的命令
    ExecStop= # 停止服务时执行的命令
    ExeStartPre= # 启动进程之前执行的命令
    ExeStartPost= # 启动进程之后执行的命令
    ExeStopPost= # 停止进程之后执行的命令
    Restart= # 定义退出后是否要重启服务,值可为no/on-success/on-failure/on-abnormal/on-abort/onwatchdog/always
    RestartSec= # 进程退出之后重启的时间间隔
    
    [Install]
    WantedBy= # 表示归属的target,这部分比较复杂,常用的是multi-user.target与graphical.target
    



沪ICP备19023445号-2号
友情链接