debian使用说明
===============

Debian 12，也被称为“Bookworm”，是 Debian Linux 发行版的一个版本。

目录结构
------------

.. code:: text

        ├── bin # 主要二进制程序，如常用的 shell 命令（ls, cp, etc）
        ├── boot # 启动加载器文件，如内核、initramfs
        ├── dev # 设备文件，如 /dev/sda, /dev/tty
        ├── etc # 配置文件
        ├── home # 用户的主目录
        ├── lib # 系统库文件，如共享库和内核模块
        ├── media # 可移除媒体的挂载点，如 CD-ROMs, USB drives
        ├── mnt # 临时文件系统挂载点
        ├── opt # 可选的、附加的应用程序软件包
        ├── proc # 虚拟文件系统，展现系统信息（如 /proc/cpuinfo）
        ├── root # root 用户的主目录
        ├── run # 运行时变量
        ├── sbin # 系统管理员的系统管理程序
        ├── srv # 服务数据
        ├── sys # 用于访问和设置内核参数的虚拟文件系统
        ├── tmp # 临时文件
        ├── usr # 用户相关的程序和数据
        │ ├── bin # 用户二进制文件
        │ ├── lib # 用户级库文件
        │ ├── include # 标准包含文件
        │ ├── sbin # 非必要的系统二进制
        │ ├── share # 架构独立的数据
        │ └── src # 源代码
        └── var # 变量文件，如日志、数据库、邮件等


systemd
---------------

systemd service基本格式
~~~~~~~~~~~~~~~~~~~~~~~~

.. code:: text

        [Unit]
        Description=My Service
        [Service]
        ExecStart=/usr/bin/my-service
        Restart=on-failure
        RestartSec=5s
        [Install]
        WantedBy=multi-user.target

systemd常用关键字
~~~~~~~~~~~~~~~~~~~~~~

Type
^^^^^^^^

Systemd 中的服务单元 (service units) 可以有多种类型，由 Type= 指令在服务文件的 [Service] 部分指定。这个指令定义了服务的启动行为和如何管理服务。以下是 systemd 支持的服务类型：

- simple：这是默认的服务类型，如果没有指定 Type，则 systemd 假定服务为 simple 类型。在这种类型中，systemd 在启动服务时直接执行 ExecStart 指令指定的命令，认为服务已经立即启动。服务一旦启动，控制立即返回给 systemd，而不管服务是否已经准备好接受请求。
- forking：这种类型用于那些传统的守护进程，它们在启动时会产生一个子进程，然后父进程立即退出。systemd 认为，一旦父进程退出，服务已经启动。这对于那些需要实现“双重启动”（double-fork）以摆脱终端和启动脚本控制的传统 UNIX 服务来说是有用的。
- oneshot：这种类型通常用于执行一次性任务并退出的服务。systemd 会等待 ExecStart 过程完成。如果服务需要在系统引导或关闭时执行一次性任务，这种类型是合适的。
- dbus：这种类型适用于实现了 D-Bus 接口的守护进程。当服务通过 D-Bus 成功注册其服务名称时，systemd 认为它已经启动。
- notify：在这种类型中，服务必须显式地通过 sd_notify 函数或类似机制告知 systemd 它何时已经启动完毕或已经准备好。这允许服务的启动同步精确地与 systemd 的状态同步。
- idle：systemd 会等待所有作业处理完毕并且没有其他作业待处理时，再启动 idle 类型的服务。这主要用于避免在引导过程中混乱打印信息到控制台的情况。

ExecStartPre
^^^^^^^^^^^^^

ExecStartPre指令用于指定在主服务进程 (ExecStart) 启动之前需要执行的命令或脚本。这些预执行命令通常用于设置必要的前置条件或执行一些预备任务，以确保主服务能够成功启动。如果 ExecStartPre 中的任何命令失败（退出状态码非零），systemd 会认为服务启动失败，并且不会继续执行后面的 ExecStart 和 ExecStartPost。


ExecStartPost
^^^^^^^^^^^^^

指定了在主进程启动后要运行的命令。

- 如果 ExecStart 指定的主进程以非零退出状态退出，systemd 将不会执行 ExecStartPost 指令。
- 如果有多个 ExecStartPost 命令，它们将按照在配置文件中出现的顺序执行。
- ExecStartPost 命令的执行结果不影响服务的启动状态。即使 ExecStartPost 命令失败，服务仍然可能被视为已成功启动。

ExecStart
^^^^^^^^^^^^^

指定了服务主进程启动时要运行的命令。


Restart
^^^^^^^^^^^^^

服务退出时的重启策略。可配置的属性如下

- no: 服务在退出时不会自动重启。
- always: 无论服务以何种状态或退出码退出，服务都将被重启。
- on-success: 仅当服务正常退出时（退出状态码为0），服务才会被重启。
- on-failure: 当服务以错误代码退出时，会被重启。这通常包括信号导致的终止和超时。
- on-abnormal: 仅当服务由于未捕获的信号或超时而异常退出时，才会重启。
- on-abort: 仅当服务因收到未捕获的信号而终止时，才会重启。
- on-watchdog: 仅当服务未能进行“看门狗”心跳时，才会重启

RestartSec
^^^^^^^^^^^^^

在尝试重启服务之前等待的秒数。

StartLimitBurst & StartLimitIntervalSec
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

在 systemd 中，StartLimitBurst 关键字与 StartLimitIntervalSec 关键字一起使用，以控制在指定时间窗口内可以尝试启动服务的次数。这对于防止服务在失败后不断尝试重启，无限循环消耗资源非常有用。
StartLimitBurst 定义了在 StartLimitIntervalSec 时间段内允许启动的最大次数。如果超过这个阈值，systemd 将停止尝试重启服务，并且必须显式地用 systemctl reset-failed 命令清除状态，或者等待时间窗口结束才能再次尝试启动服务。

- Restart=on-failure 表示服务失败后 systemd 会尝试重启。
- RestartSec=5s 表示每次重启尝试之间将等待 5 秒。
- StartLimitBurst=3 表示在 StartLimitIntervalSec 时间内，允许最多尝试重启服务 3 次。
- StartLimitIntervalSec=60s 表示时间窗口为 60 秒。

Nice
^^^^^^^^^^^^^

设置服务进程的调度优先级。

TimeoutStartSec
^^^^^^^^^^^^^^^

指定了服务启动操作的超时时间。如果服务的启动时间超过了这个值，systemd 会认为服务启动失败，并将采取相应的措施，通常是终止服务的启动过程。TimeoutStartSec的值的单位可以是s、ms、min、h等，也可以是特殊值 infinity 。infinity可以用来指定无限的超时，这意味着 systemd 将永远不会因为超时而终止服务。
这个时间限制有助于捕捉服务启动过程中的问题，确保系统不会无限期地等待一个服务启动，这对于维持系统的可靠性和快速启动非常重要。TimeoutStartSec 的默认值由系统的 systemd 配置决定，但通常是 90 秒。

Requires
^^^^^^^^^^^^^

强依赖 A Requires B, A启动前，B必须是活动状态。在 [Unit] 部分中使用 Requires 关键字，可以确保被依赖的单元（如果还没有激活的话）在当前单元启动时一起启动。如果被依赖的单元在启动过程中失败了，发起单元（包含 Requires 指令的单元）也不会启动。如果被依赖的单元在运行中失败了，发起单元也会被停止。 Requires 并不能保证服务启动的顺序，它仅仅表示启动依赖。要控制服务启动的顺序，还需要使用 After 或 Before 指令来明确指定。因此Requires和After经常配合使用。

Wants
^^^^^^^^^^^^^

弱依赖，A Wants B，启动A之前会尝试启动B，但是即使B启动失败，A仍会继续启动

Conflicts
^^^^^^^^^^^^^

冲突说明这个 A Conflicts B，如果B已经处于活动状态，systemd 将尝试停止它以便启动A

Environment & EnvironmentFile
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

参数用于设置环境变量。这些环境变量在服务进程的上下文中生效，通常用来配置程序运行时的某些行为。
指令用于指定一个包含环境变量定义的文件的路径。这个文件里的每一行都应该包含一个环境变量定义，格式和直接在服务文件中定义环境变量的格式一样。在 systemd 单元（unit）文件中，WantedBy 参数是一个安装（[Install]）部分中的指令，它定义了一个单元在哪些目标（targets）下是被“期望”的。当一个单元被“期望”时，这意味着如果这个目标被激活，那么这个单元也应该被激活。

WantedBy
^^^^^^^^^^

用于创建符号链接，这些链接位于 /etc/systemd/system/ 目录的 .wants/ 子目录中。[Install] 部分定义了如何安装（即使能够启动）该单元，有助于控制单元是如何集成和激活的。它包含的指令主要和单元的“启用”（systemctl enable）和“禁用”（systemctl disable）操作有关。当你启用一个服务时，[Install] 部分告诉 systemd 要创建哪些符号链接，这些符号链接用于在特定的目标（target）中激活服务。这些符号链接用于在启动系统时或者启动特定的目标时自动启动单元。这是 systemd 实现依赖性管理的方式之一。这表明当系统进入多用户模式（multi-user.target）时，这个服务是“期望”的，因此应该被启动。安装这个服务单元（通过 systemctl enable 命令）将会创建一个符号链接，通常是在 /etc/systemd/system/multi-user.target.wants/ 目录中，链接到这个服务单元的文件。
实际上，这意味着当系统达到多用户运行级别时，systemd 会检查 multi-user.target.wants 目录下的所有符号链接，并启动这些链接指向的服务。
WantedBy 是配置单元启动顺序和依赖性的一种方法，但不是强制性的。即使目标激活，单元也可能因为其他原因（比如条件检查失败）而不启动。这与 RequiredBy 不同，后者表示如果目标被激活，单元必须启动，否则整个目标的启动会因为这个单元的失败而失败。

RequiredBy
^^^^^^^^^^^^^

这与 WantedBy 类似，但它创建的符号链接表示服务对于指定目标是必需的，而不是可选的。

Alias
^^^^^^^^^^^^^

这个选项允许为服务定义别名，当服务被启用时，将创建一个额外的符号链接，使用这个别名指向服务的单元文件。

Also
^^^^^^^^^^^^^

当启用或禁用此单元时，Also 选项指定了其他单元也应该同时被启用或禁用。


systemd常用命令
~~~~~~~~~~~~~~~~~~~~~~

- 启动服务

  ``systemctl start example.service``

- 暂停服务

  ``systemctl stop example.service``

- 重启服务

  ``systemctl restart example.service``

- 查看服务状态

  ``systemctl status example.service``

往代码仓库添加systemd service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- 添加服务

在hbre/boot-utils/hb-init-scripts/lib/systemd/system添加一个service，service格式参考“systemd service基本格式”章节。

- 创建软链接

在hbre/boot-utils/hb-init-scripts/DEBIAN/postinst内添加软链接，例子如下：

.. code:: text

        ln -sf /lib/systemd/system/hobot-example.service /etc/systemd/system/basic.target.wants/hobot-example.service

系统配置
---------------

环境变量
~~~~~~~~~~~~~~~~~~~~~~

- 临时：
  ``export MY_VAR=value``

- 永久：修改/etc/environment或者/etc/profile。需要注意的是在开启dm-verity时，重启后配置失效。

时间
~~~~~~~~~~~~~~~~~~~~~~

- 时间同步：
  ``systemctl start systemd-timesyncd``

如果需要测试内部的时间同步，请将systemd-timesyncd关闭。

注意事项
~~~~~~~~~~~~~~~~~~~~~~

debian系统的根目录是/以ovelayrootfs的形式挂载的，其依附的存储分区system开启了dm-verity保护,系统启动时会将system存储分区映射到内存上生成根目录。
对根目录的读写本质上是对内存的读写，生成的数据会在掉电后丢失。当根目录被写满后可能会影响debian系统的正常运行，重启可以恢复，建议不要在根目录上写数据。

