外观
Salt 部署与自定义配置
OMV 用 Salt 把配置数据库里的设置变成系统里真正的配置文件。读完这一篇,你能说清点击应用之后发生了什么,用 omv-salt 手动部署,并且在界面和扩展选项都做不到的时候,追加一个不会被 OMV 覆盖的自定义状态。
开始之前
- 先读 OMV 是怎么工作的:配置数据库与「应用」按钮,知道「手改配置文件会被覆盖」是怎么回事。
- 命令在 OMV 的 shell(root 身份)里执行。
- 部署会重写配置文件并重启对应的服务。动手前选一个没有人在用 NAS 的时间。
自定义 Salt 状态写错,会让整个模块无法部署
影响范围:你追加的状态文件和这个模块自带的状态在同一次部署里一起运行。只要有一个状态报错,这个模块的部署就失败,之后在界面点应用也会失败,直到你删掉或修好它。
前置条件:先在测试机或虚拟机上验证;确认没有更简单的办法(见下文「先问自己」);部署前界面里没有待应用的更改。
怎么回退:删除你添加的 .sls 文件,再运行 omv-salt deploy run <模块>,配置文件会被重新生成为 OMV 的默认内容。
点击「应用」之后发生了什么
- 保存设置时,界面把改动写进
config.xml,相关模块的名字被记进/var/lib/openmediavault/dirtymodules.json,界面顶部出现黄色提示条。 - 点击应用,界面调用 RPC
Config.applyChangesBg,参数是{"modules": [], "force": false},意思是「处理所有被标记的模块」。 - 后台锁住数据库,按模块之间的先后依赖排序,对每个模块执行部署。
- 每个服务类模块的部署,实际上就是运行
omv-salt deploy run --no-color <模块名>。 - Salt 读取数据库和环境变量,渲染模板,写入配置文件,必要时重启服务。
- 成功后,模块从待应用列表里移除,
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,再部署所有模块 | 想让全部配置重新生成时 |
all | prepare 加 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、phpfpm | Web 管理界面本身 |
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 吗
按下面的顺序,前面的办法能解决就不要往后走:
- 界面里的选项。
- 扩展选项(Extra options)。 SMB、SSH、NFS 等服务的页面里都有,内容会原样追加到生成的配置里。
- 环境变量。 很多服务的默认值可以用环境变量调整,见 环境变量。
- OMV 没有接管的文件。 例如
/etc/sysctl.d/里不以99-openmediavault-开头的文件、/etc/systemd/system/下的覆盖配置,直接按 Debian 的做法写就行,OMV 不会动它们。 - 自定义 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 的模块结构和文件编号会随版本变化,尤其是大版本。每次升级之后重新部署一次相关模块,并检查你的状态是否还有效。