跳转到内容

Salt 部署与自定义配置 ​

OMV 用 Salt 把配置数据库里的设置变成系统里真正的配置文件。读完这一篇,你能说清点击应用之后发生了什么,用 omv-salt 手动部署,并且在界面和扩展选项都做不到的时候,追加一个不会被 OMV 覆盖的自定义状态。

开始之前 ​

自定义 Salt 状态写错,会让整个模块无法部署

影响范围:你追加的状态文件和这个模块自带的状态在同一次部署里一起运行。只要有一个状态报错,这个模块的部署就失败,之后在界面点应用也会失败,直到你删掉或修好它。

前置条件:先在测试机或虚拟机上验证;确认没有更简单的办法(见下文「先问自己」);部署前界面里没有待应用的更改。

怎么回退:删除你添加的 .sls 文件,再运行 omv-salt deploy run <模块>,配置文件会被重新生成为 OMV 的默认内容。

点击「应用」之后发生了什么 ​

  1. 保存设置时,界面把改动写进 config.xml,相关模块的名字被记进 /var/lib/openmediavault/dirtymodules.json,界面顶部出现黄色提示条。
  2. 点击应用,界面调用 RPC Config.applyChangesBg,参数是 {"modules": [], "force": false},意思是「处理所有被标记的模块」。
  3. 后台锁住数据库,按模块之间的先后依赖排序,对每个模块执行部署。
  4. 每个服务类模块的部署,实际上就是运行 omv-salt deploy run --no-color <模块名>。
  5. Salt 读取数据库和环境变量,渲染模板,写入配置文件,必要时重启服务。
  6. 成功后,模块从待应用列表里移除,config.xml.NNNN 修订文件被删除,界面提示 The following modules have been updated: …。

所以你在命令行运行 omv-salt deploy run,和界面里点应用走的是同一条路,区别只在于:命令行不会自动清空待应用列表(见下一节)。

omv-salt 的用法 ​

sh
omv-salt deploy list                 # 所有可部署的模块
omv-salt deploy list-dirty           # 已保存但尚未应用的模块
omv-salt deploy run <模块>...        # 部署一个或多个模块
omv-salt deploy run --append-dirty   # 部署所有待应用模块,成功后清空待应用列表
omv-salt stage list                  # 列出阶段
omv-salt stage run <阶段>            # 运行一个阶段
  • deploy run 不带 --append-dirty 时,只部署你指定的模块,不会把它们从待应用列表里移除,黄色提示条还在。带上 --append-dirty 时,会把所有待应用模块(连同你写的模块名)一起部署,成功后清空列表。
  • --no-color 关闭彩色输出,-q(--quiet)不输出信息。
  • 模块名不存在时报 The state '...' does not exist,退出码 100。

四个阶段的含义:

阶段做什么什么时候用
setup安装 OMV 软件包之后只运行一次,初始化系统不要手动运行
prepare同步 Salt 的自定义模块,并根据 /etc/default/openmediavault 重新生成 Salt 的环境变量数据(pillar)改了环境变量之后
deploy先刷新 pillar,再部署所有模块想让全部配置重新生成时
allprepare 加 deploy同上,一步到位

stage run deploy 会重写所有服务的配置并重启它们,比部署单个模块的影响大得多,日常用 deploy run <模块> 就够了。

模块名从哪里查 ​

omv-salt deploy list 列出的就是 /srv/salt/omv/deploy/ 下的目录名。界面上常用的对应关系如下:

模块对应的界面或功能
samba服务 → SMB/CIFS
nfs服务 → NFS
ssh服务 → SSH
rsync、rsyncd服务 → Rsync(任务、服务器)
nginx、phpfpmWeb 管理界面本身
postfix、monit、smartmontools、apt、apticron邮件通知、系统监测、S.M.A.R.T.、更新管理
fstab、quota文件系统的挂载条目与配额
systemd-networkd、hosts、hostname、iptables网络、防火墙
chrony、timezone日期和时间
cron计划任务
cpupower、systemd-logind电源管理
collectd、rrdcached性能统计

状态目录的结构 ​

OMV 的 Salt 文件在 /srv/salt/omv/,运行时在本机以 masterless 方式执行,不需要 Salt master。

text
/srv/salt/omv/deploy/<模块>/
  init.sls          入口,include 同目录的 default
  default.sls       主体:include 编号状态,并管理服务的启停
  10xxx.sls         编号状态,按编号升序依次运行
  20xxx.sls
  files/            Jinja 模板,例如 smb.conf 的各个片段
/srv/pillar/omv/    pillar 数据:default.sls 由环境变量生成,另有产品信息和文件头注释
/srv/salt/_modules/ 自定义 Salt 模块:omv_conf、omv_utils、omv_pillar 等
/srv/salt/_states/  自定义 Salt 状态:omv_dpkg

状态文件里最常见的三种写法:

jinja
{% set config = salt['omv_conf.get']('conf.service.smb') %}
{% set value = salt['pillar.get']('default:OMV_SAMBA_SOCKETOPTIONS', 'TCP_NODELAY IPTOS_LOWDELAY') %}
{{ pillar['headers']['multiline'] }}
  • omv_conf.get 读配置数据库,参数就是 配置数据库 里的数据模型 ID。
  • pillar.get('default:OMV_...', 默认值) 读环境变量,没设置就用后面的默认值。这就是 环境变量 能改变部署结果的原因。
  • pillar['headers']['multiline'] 是写在生成文件开头的提示:「此文件由 OpenMediaVault 自动生成,修改会丢失」。

哪些模块可以追加自己的状态 ​

模块的 default.sls 里有一段循环,把同目录下符合命名规则的 .sls 文件都 include 进来。规则有两种:

  • 编号状态:文件名以数字开头,匹配 ^\d+.+\.sls$,例如 20configure.sls,samba、ssh、postfix、monit、cron、fstab 等大多数模块是这种。按文件名排序依次运行,建议自己的文件用两位数的编号,例如 60local-xxx.sls,让它排在系统文件之后。
  • 所有 .sls:sysctl 模块 include 目录下除 init.sls、default.sls 之外的全部 .sls 文件。

chrony、cpupower、nfs、quota、rsync、rsyncd、timezone 等模块没有这段循环,不能靠放一个文件来追加状态。用下面的命令自己确认:

sh
grep -l "regex_match" /srv/salt/omv/deploy/*/default.sls

先问自己:真的要写 Salt 吗 ​

按下面的顺序,前面的办法能解决就不要往后走:

  1. 界面里的选项。
  2. 扩展选项(Extra options)。 SMB、SSH、NFS 等服务的页面里都有,内容会原样追加到生成的配置里。
  3. 环境变量。 很多服务的默认值可以用环境变量调整,见 环境变量。
  4. OMV 没有接管的文件。 例如 /etc/sysctl.d/ 里不以 99-openmediavault- 开头的文件、/etc/systemd/system/ 下的覆盖配置,直接按 Debian 的做法写就行,OMV 不会动它们。
  5. 自定义 Salt 状态。 只有 OMV 会反复重写的文件,并且前面的办法都不行时才用,做法是在它重写之后再追加或修正。

示例:给 Postfix 追加一行配置 ​

邮件通知发不出去时,需要看 Postfix 的 TLS 握手日志。smtp_tls_loglevel 没有对应的界面选项,也不在 OMV 的环境变量里,而 /etc/postfix/main.cf 每次部署都会被重写,所以用一个自定义状态在重写之后追加这一行。

创建 /srv/salt/omv/deploy/postfix/60local-tls-loglevel.sls,内容如下:

yaml
local_postfix_tls_loglevel:
  file.append:
    - name: "/etc/postfix/main.cf"
    - text: |
        smtp_tls_loglevel = 1

注意两点:状态的 ID(第一行)在整个部署里必须唯一,所以加了 local_ 前缀;YAML 用空格缩进,不能用 Tab。

然后部署 postfix 模块:

sh
omv-salt deploy run postfix

排查完以后,删除这个文件,再部署一次,配置就回到 OMV 的默认内容:

sh
rm /srv/salt/omv/deploy/postfix/60local-tls-loglevel.sls
omv-salt deploy run postfix

检查结果 ​

sh
omv-salt deploy list-dirty            # 输出 No dirty states found.,或只剩你预期的模块
postconf smtp_tls_loglevel            # 示例:应显示 smtp_tls_loglevel = 1
systemctl is-active postfix           # 邮件通知已启用时应为 active

部署命令的输出末尾有一段汇总,看 Failed 是否为 0。

常见问题 ​

The state '...' does not exist。 模块名拼错了。先 omv-salt deploy list,也可以按 Tab 补全。

放进去的 .sls 没有运行。 先确认这个模块的 default.sls 里有 include 循环(见上面的 grep 命令),再确认文件名以数字开头、扩展名是 .sls。

部署报 YAML 或 Jinja 错误。 先把你的文件移走,确认模块能正常部署,再逐行修好自己的文件。YAML 对缩进敏感,Jinja 语法错误会指出行号。

升级 OMV 之后自定义状态失效或报错。 OMV 的模块结构和文件编号会随版本变化,尤其是大版本。每次升级之后重新部署一次相关模块,并检查你的状态是否还有效。

参考资料 ​

OpenMediaVault 非官方中文使用指南,与 openmediavault 项目及其开发者无隶属关系。