Linux_Systemd_service自定义实践

[TOC]

区分 sevice 和 systemctl

service

  • 脚本位置:/etc/init.d

  • 脚本内容:常为 /bin/sh 或者 /bin/bash

    • function 部分,提供 startstop 等函数
    • **main(case-swicth)**部分,根据 $1 传入参数,调用前文定义好的 func
  • 脚本举例,例子来自 /etc/init.d/dubs,为方便理解,内容有删减

    #!/bin/sh
    ### BEGIN INIT INFO
    # Provides: dbus
    # Required-Start: $remote_fs $syslog
    # Required-Stop: $remote_fs $syslog
    # Default-Start: 2 3 4 5
    # Default-Stop:
    # Short-Description: D-Bus systemwide message bus
    # Description: D-Bus is a simple interprocess messaging system, used
    # for sending messages between applications.
    ### END INIT INFO
    # -*- coding: utf-8 -*-
    # Debian init.d script for D-BUS
    # Copyright © 2003 Colin Walters <walters@debian.org>
    # Copyright © 2005 Sjoerd Simons <sjoerd@debian.org>

    # ..........................................................................................
    set -e
    DAEMON=/usr/bin/dbus-daemon
    UUIDGEN=/usr/bin/dbus-uuidgen
    UUIDGEN_OPTS=--ensure
    NAME=dbus
    DAEMONUSER=messagebus
    PIDDIR=/var/run/dbus
    PIDFILE=$PIDDIR/pid
    DESC="system message bus"
    # ................................ function part BEGIN .....................................
    create_machineid() {
    # Create machine-id file
    if [ -x $UUIDGEN ]; then
    $UUIDGEN $UUIDGEN_OPTS
    fi
    }

    start_it_up()
    {
    if [ ! -d $PIDDIR ]; then
    mkdir -p $PIDDIR
    chown $DAEMONUSER $PIDDIR
    chgrp $DAEMONUSER $PIDDIR
    fi

    if ! mountpoint -q /proc/ ; then
    log_failure_msg "Can't start $DESC - /proc is not mounted"
    return
    fi

    if [ -e $PIDFILE ]; then
    if $0 status > /dev/null ; then
    log_success_msg "$DESC already started; not starting."
    return
    else
    log_success_msg "Removing stale PID file $PIDFILE."
    rm -f $PIDFILE
    fi
    fi

    create_machineid

    log_daemon_msg "Starting $DESC" "$NAME"
    start-stop-daemon --start --quiet --pidfile $PIDFILE \
    --exec $DAEMON -- --system $PARAMS
    log_end_msg $?
    }

    shut_it_down()
    {
    log_daemon_msg "Stopping $DESC" "$NAME"
    start-stop-daemon --stop --retry 5 --quiet --oknodo --pidfile $PIDFILE \
    --user $DAEMONUSER
    # We no longer include these arguments so that start-stop-daemon
    # can do its job even given that we may have been upgraded.
    # We rely on the pidfile being sanely managed
    # --exec $DAEMON -- --system $PARAMS
    log_end_msg $?
    rm -f $PIDFILE
    }

    reload_it()
    {
    create_machineid
    log_action_begin_msg "Reloading $DESC config"
    dbus-send --print-reply --system --type=method_call \
    --dest=org.freedesktop.DBus \
    / org.freedesktop.DBus.ReloadConfig > /dev/null
    # hopefully this is enough time for dbus to reload it's config file.
    log_action_end_msg $?
    }
    # ................................ function part Over .....................................
    # ............................... Main case-switch BEGIN .....................................
    case "$1" in
    start)
    start_it_up
    ;;
    stop)
    shut_it_down
    ;;
    reload|force-reload)
    reload_it
    ;;
    restart)
    shut_it_down
    start_it_up
    ;;
    status)
    status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $?
    ;;
    *)
    echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart|force-reload|status}" >&2
    exit 2
    ;;
    esac
    # ............................... Main case-switch Over .....................................
  • 优缺点:

    • 优点:方便,简单。其实就是,service 按指定格式访问用户自定义脚本。
    • 优点:通用。因为 serviceLinux 发行版基本都有的,称得上是 Linux 核心能力了。
    • 缺点:太简单,基本只能做到 start、stop、status 的统一管理,没啥别的能力了。

systemctl

  • 脚本位置:/etc/systemd/system 或者 /usr/lib/systemd/system

    • 前缀是 /etc 还是 /usr/lib 由发行版决定。据说 Ubuntu 是前者,Centos 是后者
    • 其实 /etc/systemd 就算是「模块根目录」了
    • 不过 systemctl daemon-reload 读取的还是 /etc/systemd/system
    • 注意,systemctl 也是会读取 /etc/init.d 中的内容的。—— 这就是他俩的关系。
  • 脚本内容:

    • 类 ini 格式,支持以 # 开头的行注释
    • 可以在 VSCode 找到 coolbear.systemd-unit-file 扩展,体验其语法支持与关键字高亮
    • systemctl 把注册文件称之为 unit ,后面细说。
  • 脚本举例:

    [Unit]
    Description=OpenBSD Secure Shell server
    Documentation=man:sshd(8) man:sshd_config(5)
    After=network.target auditd.service
    ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

    [Service]
    EnvironmentFile=-/etc/default/ssh
    ExecStartPre=/usr/sbin/sshd -t
    ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
    ExecReload=/usr/sbin/sshd -t
    ExecReload=/bin/kill -HUP $MAINPID
    KillMode=process
    Restart=on-failure
    RestartPreventExitStatus=255
    Type=notify
    RuntimeDirectory=sshd
    RuntimeDirectoryMode=0755

    [Install]
    WantedBy=multi-user.target
    Alias=sshd.service
  • 优缺点:

    其实是,systemd 和 systemctl

    systemd 是 一个系统管理守护进程、工具和库的集合

    systemctl 是 命令行用户接口

    • 优点:systemctl 是 Linux 系统继 init.d 之后的一个 systemd 工具,主要负责控制 systemd 系统和管理系统服务
      • 如果没什么比 service 优秀的,肯定就不会用它了啊
    • 优点:设计目标是
      • 提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动。
      • 抽象出 unit 的概念,方便用户将进程交付给系统来管理。
    • systemctl 提供相当多的模块管理功能,甚至包括依赖的树状查询。其在服务的模块管理上,比简陋的 service 完备很多。
    • 缺点:unit 的注册文件虽然比较简单,但毕竟还是有一定的学习成本

详解 systemctl - 常用 CLI

  • 更详细更完整的详讯官方文档 man systemctl
systemctl < start | stop | status | restart > < UnitName > # 基础能力,不多赘述
systemctl list-units [--all] # 列出所有 unit,--all 会把不活动的也列出来
systemctl list-dependencies # 列出所有依赖
systemctl list-dependencies --all # 列出所有(含非活动)依赖
systemctl list-dependencies [UnitName] # 列出指定 unit 依赖了谁
systemctl list-dependencies [UnitName] --reverse # 列出谁依赖了指定 unit
  • 基本格式 systemctl [command] [unit]
  • command 主要有:
    • start | stop | restart:启动 | 关闭 | 关闭了再启动
    • reload:不关闭,但是重新载入配置文件
    • enable:开机自启,其实就是在 wants 里面加了一个软链接
    • disable:关闭开机自启
    • status:打印状态和日志信息
    • is-active:当前活着不
    • is-enabled:当前是否是开机自启的
    • kill :发送 kill 信号给 unit
    • show:展示一下 unit 注册文件里的配置信息
    • mask:注销指定 unit,注销后无法启动这个 unit 了
    • unmask:取消指定 unit 的注销

详解 systemctl - unit File

  • systemd 的 unit 文件详解,可以用 man systemd.unit 查阅
  • 我在 CentOS8 Linux4.18 的服务器上 man systemd 查到 unit 有十一种
    • Service、Socket、Target、Device、Mount、Automount、Timer、Swap、Path、Slice、Scope
    • 想查看他们的详细信息,可以 man systemd.service 或者 man systemd.scope 这样子
  • 文件支持行注释,以 # 开始的行将作为注释

.mount 文件

定义挂载点,仅有 Mount 一节

  • [Mount]
    • What
    • Where
    • Type

.service 文件

定义服务,分 Unit、Service、Install 三节

value 如果是数组,则数组元素间用空格隔开即可

  • [Unit]
    • Description
    • Before
    • After
    • ConditionPathExists:执行条件。满足条件才会去start。不写也行,我反正没用到过。
  • [Service]
    • EnvironmentFile:环境变量可以从这个文件导入
    • Restart=always:失败后总是重启
    • RestartSec=5:等5秒再重启
    • StartLimitInterval=0:重启次数不限制
    • Exec…
      • ExecStart:必填
      • ExecStop:必填
      • …..
      • ExecRestart:非必填
      • ExecStatus:非必填
  • [Install]
    • Alias:别名
    • WantedBy=multi-user.target:之后配置 enable,需要这个配置项

.target 文件

供 service 调用的,一般不需要用户编辑

.wants 文件夹

  • 需要了解前置知识:Linux RunLevel
  • multi-user 可以理解成就是服务器正常工作的时候,99% 都是在这个状态的。
  • 这文件夹里面都是软链接,都是 service 的链接,在系统进入 multi-user 这个 level 的时候,会把这里的服务都启动一遍