CFEngine 3.27.2 配置参数详解
CFEngine 3.27.2 配置参数详解:masterfiles 到 inputs 的同步机制、promises.cf 主配置(bundlesequence/inputs)逐项解析、def.json 覆盖机制实测、body agent/executor/server control 全参数说明,含邮件开关与 ACL 覆盖链实测
CFEngine 3.27.2 配置参数详解
目标:吃透 CFEngine 3.27.2 社区版的策略配置体系——
/var/cfengine/masterfiles到inputs的同步机制、主配置promises.cf、MPF 默认值库controls/def.cf、def.json覆盖机制,以及三大守护进程的控制体(body agent/executor/server control)逐项参数。全部内容在 Ubuntu 22.04 实测环境(3.27.2,自举完成)验证,关键结论附实测证据。
一、环境信息
本文所有命令与回显在以下环境实测通过,读者可按同样配置复现:
- 操作系统与内核:Ubuntu 22.04 LTS(Jammy Jellyfish,单机自举完成),内核 6.8.0-138-generic
- 架构:x86_64(amd64)
- CFEngine 版本:3.27.2(社区版 / Community Edition,自带 MPF 策略库)
- 常驻组件:cf-agent(策略执行)、cf-execd(每 5 分钟定时调度)、cf-serverd(策略分发)、cf-monitord(指标采集)
- 通信端口:TCP 5308(cf-serverd 监听,访问控制由 body server control 的 allowconnects 决定)
- 工作目录:
/var/cfengine/ - 策略文件路径:权威源
/var/cfengine/masterfiles/,生效副本/var/cfengine/inputs/,主配置/var/cfengine/inputs/promises.cf,同步策略/var/cfengine/inputs/update.cf,默认值库/var/cfengine/inputs/controls/def.cf,用户覆盖层/var/cfengine/masterfiles/def.json
二、配置体系总览
CFEngine 的「配置」分三层,理解分层是改配置不翻车的前提:
| 层 | 位置 | 角色 |
|---|---|---|
| 权威源(Masterfiles) | /var/cfengine/masterfiles/ | 官方 MPF 策略库 + 用户自定义,改这里 |
| 生效副本(inputs) | /var/cfengine/inputs/ | agent 实际解析执行的策略,不要直接改(会被下次同步覆盖) |
| 数据覆盖(def.json) | /var/cfengine/masterfiles/def.json | JSON 格式的变量/类覆盖层,优先级高于 MPF 内置默认值 |
masterfiles → inputs 的同步由 update.cf 负责,带哈希缓存(cf_promises_validated 哨兵文件):masterfiles 内容没变化时跳过同步。实测证据(手动改 masterfiles 后强制同步的输出节选):
info: Copied file '/var/cfengine/masterfiles/services/autorun/dup_test.cf' to '/var/cfengine/inputs/services/autorun/dup_test.cf.cfnew' (mode '600')
info: Moved '/var/cfengine/inputs/services/autorun/dup_test.cf.cfnew' to '/var/cfengine/inputs/services/autorun/dup_test.cf'
info: Updated file '/var/cfengine/inputs/services/autorun/dup_test.cf' from 'localhost:/var/cfengine/masterfiles/services/autorun/dup_test.cf'
cf-execd 每 5 分钟的调度会自动执行 update.cf 完成同步;开发调试时可手动强制:
/var/cfengine/bin/cf-agent -KIf /var/cfengine/inputs/update.cf --define validated_updates_ready
MPF 的核心文件布局(inputs 与 masterfiles 结构一致):
| 文件/目录 | 作用 |
|---|---|
promises.cf | 主入口:bundlesequence(执行序列)+ inputs(待加载文件清单) |
update.cf | 同步策略:masterfiles → inputs(含 failsafe 自愈) |
controls/ | 三大守护进程的控制体(cf_agent.cf / cf_execd.cf / cf_serverd.cf / cf_monitord.cf / cf_runagent.cf) |
controls/def.cf | MPF 全部默认值定义(def. 前缀变量) |
def.json | 用户覆盖层(augments),可覆盖 controls 里的默认值 |
services/autorun/ | 用户 bundle 自动加载目录(需启用,见《CFEngine 3.27.2 快速入门与策略编写示例》第八章) |
inventory/、lib/、cfe_internal/ | MPF 内置库(一般不改) |
💡 技术拓展:MPF(Masterfiles Policy Framework)是官方维护的策略框架,随 CFEngine 一起发布。改配置有三条路——(1) 直接改
controls/def.cf:最直白但升级 MPF 时会被覆盖(冲突风险高);(2)def.json(augments):JSON 覆盖层,MPF 的默认值全部带if => not(isvariable(...))守卫,def.json 里定义了同名变量则以 def.json 为准,官方推荐方式,升级安全;(3) autorun bundle:不改默认值而是用自己的 bundle 去「再收敛」。三种方式按「改动小 → 大」排序:def.json < autorun < 改 def.cf/promises.cf,本文以 def.json 为主线。
三、promises.cf:主配置解析
/var/cfengine/inputs/promises.cf 的核心是 body common control(实测原文节选):
body common control
{
bundlesequence => {
# Common bundle first (Best Practice)
inventory_control,
@(inventory.bundles),
def,
@(cfengine_enterprise_hub_ha.classification_bundles),
# Custom classification
@(def.bundlesequence_classification),
# autorun system
services_autorun,
@(services_autorun.bundles),
# Agent bundle
cfe_internal_management, # See cfe_internal/CFE_cfengine.cf
mpf_main,
@(cfengine_enterprise_hub_ha.management_bundles),
@(def.bundlesequence_end),
};
inputs => {
# User policy init, for example for defining custom promise types:
"services/init.cf",
# File definition for global variables and classes
@(cfengine_controls.def_inputs),
# Inventory policy
@(inventory.inputs),
3.1 bundlesequence:执行序列逐项
bundlesequence 决定 agent 每轮按什么顺序执行哪些 bundle:
| 条目 | 作用 |
|---|---|
inventory_control + @(inventory.bundles) | inventory 采集(生成 sys./inventory 变量) |
def | 加载 def.cf 默认值与 def.json 覆盖——必须排最前,后续 bundle 都依赖它 |
@(def.bundlesequence_classification) | 用户自定义分类 bundle 挂载点(def.json 可注入) |
services_autorun + @(services_autorun.bundles) | autorun 机制本体:前者负责扫描目录,后者是扫描出的用户 bundle 列表(所以 def.json 里启用 services_autorun 类是 autorun 的总开关) |
cfe_internal_management | CFEngine 自管理(保证 inputs 同步、服务运行等) |
mpf_main | MPF 主体(内置承诺的落地点) |
@(def.bundlesequence_end) | 用户 bundle 的尾部挂载点 |
注意 @(...) 语法:展开一个 slist(列表),每个元素当作一个 bundle 名。企业版专属条目(cfengine_enterprise_hub_ha.*)在社区版上为空列表,不报错。
3.2 inputs:待加载文件清单
inputs 决定解析哪些 .cf 文件,同样用 @(...) 展开各组件的文件清单(@(cfengine_controls.def_inputs)、@(inventory.inputs) 等)。用户自己的策略目录要进入解析,标准做法是放进 services/(autorun 目录已含在其中)或在 def.json 里用 inputs 键追加——本文推荐 autorun,零改动。
四、def.json:用户覆盖层(augments)
4.1 JSON 结构与两个核心键
def.json 是标准 JSON,两个最常用键:
{
"classes": {
"services_autorun": ["any"],
"cfengine_internal_disable_agent_email": ["any"]
},
"variables": {
"acl": ["127.0.0.1/16", "172.27.0.0/16"],
"app_name": "demo-app"
}
}
classes:定义类。键是类名,值是「何时成立」的类表达式数组——"any"表示任何情况都成立,也可以写"ubuntu_22_04"、"Monday"等。MPF 大量功能开关(autorun、邮件、报表)都靠这个键打开。variables:定义变量,加载进defbundle,策略里用$(def.键名)引用。键acl有特殊含义(覆盖服务器 ACL,见第七章)。
4.2 实测一:开关邮件(cfengine_internal_disable_agent_email)
MPF 默认开启「agent 运行结果邮件通知」,没有 smtp 服务的机器每次调度都会在 journal 留下报错。在 def.json 的 classes 中加入 "cfengine_internal_disable_agent_email": ["any"] 并同步重启后,实测 /var/cfengine/bin/cf-execd -FO 前台单次运行无任何输出、退出码 0,报错消失。控制体里的实现(第六章引用原文)显示该开关通过类守卫直接跳过全部 mail 属性行——这就是 def.json classes 精准关功能的标准范式。
4.3 实测二:自定义变量与上下文边界
在 def.json 的 variables 中加 "greeting": "hello-from-defjson",写一个 autorun bundle 引用 $(def.greeting):
cat > /var/cfengine/masterfiles/services/autorun/defvar_demo.cf <<'EOF'
bundle agent defvar_demo
{
meta:
"tags" slist => { "autorun" };
reports:
"def.json greeting: $(def.greeting)";
}
EOF
chmod 600 /var/cfengine/masterfiles/services/autorun/defvar_demo.cf
/var/cfengine/bin/cf-agent -KIf /var/cfengine/inputs/update.cf --define validated_updates_ready
/var/cfengine/bin/cf-agent -KI
实测回显:
R: def.json greeting: hello-from-defjson
重要边界:同一个策略文件用 -f 单文件方式执行时(cf-agent -KI -f /tmp/defvar.cf),def bundle 不在解析范围内,变量不展开——实测输出原样打印 R: def.json greeting: $(def.greeting)。结论:def.json 变量只在完整策略上下文(bundlesequence 正常运行、或 autorun)中可用,调试时不要用 -f 单文件方式测 def 相关引用。
4.4 defvar 优先级规则
def.cf 里的每个默认值都带 if => not(isvariable(...)) 守卫(第四章引用原文可见),且关键条目带 meta => { "defvar" } 标记——含义是:def.json(augments)先于 def.cf 加载,同名变量 def.json 定义后 isvariable 为真,def.cf 的默认值自动让位。因此永远用 def.json 覆盖默认值,不改 def.cf。文件权限建议 0600(含网络 ACL 等敏感信息时防泄露)。
五、body agent control:cf-agent 全局行为
文件 controls/cf_agent.cf(实测原文节选,仅保留生效行):
body agent control
{
ifelapsed => "1";
skipidentify => "true";
abortclasses => {
"cfengine_3_3", "cfengine_3_4", @(def.control_agent_abortclasses)
};
abortbundleclasses => { @(def.control_agent_abortbundleclasses) };
maxconnections => "$(def.control_agent_maxconnections)";
default_directory_create_mode => "$(def.control_agent_default_directory_create_mode)";
}
逐项说明(默认值取自 def.cf,未列出的条目保持默认即可):
| 属性 | 默认值 | 说明 |
|---|---|---|
ifelapsed | 1(分钟) | 同一条 promise 两次评估的最小间隔。改小会显著增加评估频率;手动 -K 就是跳过该锁 |
evaluation_order | classic | promise 评估顺序(3.27 新增 top_down 选项,按书写顺序评估) |
skipidentify | true | 连接时跳过 IP/名字反查(DNS 异常环境下防卡顿) |
abortclasses | cfengine_3_3、cfengine_3_4 等 | 命中即整体终止的「熔断」类(检测到极旧版本数据结构时防误操作) |
abortbundleclasses | 空(正则列表) | 命中即终止当前 bundle 的类正则 |
maxconnections | 10(def.cf 默认) | 到单台 cf-serverd 的最大并发连接数 |
default_directory_create_mode | 770 | files 承诺自动建目录时的默认权限 |
agentfacility | cfe(内部日志前缀) | syslog/journal 里 CFEngine(agent) 前缀的来源 |
💡 说明:
ifelapsed与cf-execd的 5 分钟调度是两层独立节流:调度层决定「多久跑一轮 agent」,ifelapsed 决定「同一 promise 两次评估最小间隔」。若某条 promise 需要「每次调度都重新评估」(如时间敏感的 commands),在该 promise 上单独设ifelapsed => "1"并配合action => immediate("0")覆盖。
六、body executor control:cf-execd 调度与邮件
文件 controls/cf_execd.cf(实测原文节选):
body executor control
{
any::
splaytime => "$(def.control_executor_splaytime)";
agent_expireafter => "$(def.control_executor_agent_expireafter)";
cfengine_internal_agent_email.!cfengine_internal_disable_agent_email::
mailto => "$(def.mailto)";
mailfrom => "$(def.mailfrom)";
smtpserver => "$(def.smtpserver)";
mailmaxlines => "$(default:def.control_executor_mailmaxlines)";
any::
schedule => { @(def.control_executor_schedule_value) };
!windows::
exec_command => "$(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated -f \"$(sys.update_policy_path)\" ; $(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated";
}
6.1 调度三参数(def.cf 默认值实测)
def.cf 中的默认定义(实测原文节选):
"control_executor_splaytime"
string => "4",
if => not(isvariable("control_executor_splaytime")),
comment => "Splaytime controls the number of minutes hosts execution
should be splayed over. ...";
"control_executor_agent_expireafter"
string => "120",
if => not(isvariable("control_executor_agent_expireafter")),
comment => "This controls the number of minutes after no data has been
recieved by cf-execd from a cf-agent process before that
cf-agent process is killed.";
| 属性 | 默认值 | 说明 |
|---|---|---|
splaytime | 4(分钟) | 把大批主机的执行起点打散在 0–4 分钟内随机错开,防止策略服务器瞬时被打爆;单机场景无感 |
agent_expireafter | 120(分钟) | agent 运行超过此时长且无输出则被 cf-execd 杀掉,防僵尸进程 |
schedule | Min00–Min55(每 5 分钟共 12 个槽) | 调度时刻表,类名形如 Min05(每小时第 5 分钟) |
exec_command | 两条 cf-agent(update + 主策略) | cf-execd 到点实际执行的命令:先 update.cf 同步策略再跑主策略 |
6.2 邮件参数与类守卫
邮件相关默认值(def.cf 实测原文):
"mailto"
string => "root@$(def.domain)",
if => not(isvariable("mailto"));
"mailfrom"
string => "root@$(sys.uqhost).$(def.domain)",
if => not(isvariable("mailfrom"));
"smtpserver"
string => "localhost",
if => not(isvariable("smtpserver"));
"control_executor_mailmaxlines"
int => "30",
| 属性 | 默认值 | 说明 |
|---|---|---|
mailto | root@<域名> | 运行结果邮件收件人 |
mailfrom | root@<主机名>.<域名> | 发件人 |
smtpserver | localhost | 投递服务器;系统无 smtp 服务时报 unable to lookup smtp service(处置见 4.2 与《CFEngine 3.27.2 Ubuntu 22.04 安装指南》10.3) |
mailmaxlines | 30 | 邮件正文最多携带的输出行数 |
注意原文的类守卫 cfengine_internal_agent_email.!cfengine_internal_disable_agent_email:::邮件功能要「总开关开、关断开关未触发」同时满足,这就是 def.json 一个类就能关掉邮件的原因。另外 mailfilter_exclude/include(3.27)支持按正则过滤进邮件的输出行。
七、body server control:端口与 ACL 覆盖链
文件 controls/cf_serverd.cf 定义 cf-serverd 的监听行为,关键属性 allowconnects 的值来自 def.cf 的推导链(实测原文):
# List here the IP masks that we grant access to on the server
"acl"
slist => {
# Assume /16 LAN clients to start with
"$(sys.policy_hub)/16",
},
comment => "Define an acl for the machines to be granted accesses",
if => and(not(isvariable("override_data_acl")), not(isvariable("acl"))),
meta => { "defvar" };
!disable_always_accept_policy_server_acl::
"acl_derived" -> { "ENT-10951" }
slist => { @(def.acl), "$(sys.policy_hub)" };
any::
"control_server_allowconnects"
slist => { "127.0.0.1", "::1", @(def.acl) },
if => not(isvariable("control_server_allowconnects"));
推导链完整解读:
def.acl默认$(sys.policy_hub)/16——策略服务器 IP 所在 /16 网段(sys.policy_hub是自举时写入policy_server.dat的地址);acl_derived再并上策略服务器自身地址;- 最终
control_server_allowconnects= 本机环回(127.0.0.1、::1)+ 上述网段。
在 def.json 中覆盖 ACL 的实测闭环(《CFEngine 3.27.2 进阶实战与运维》有完整排障过程):多机部署时客户端网段不在服务器的 /16 内会被拒绝连接,在 /var/cfengine/masterfiles/def.json 中写入:
{
"variables": {
"acl": ["127.0.0.1/16", "172.27.0.0/16"]
}
}
同步并重启 cfengine3 后客户端重新自举即通过——因为 def.cf 的 acl 定义带 if => not(isvariable("acl")) 守卫,def.json 先定义了 acl,默认值让位。其余 server control 常用项:denybadclocks(拒绝时钟偏差过大的连接,默认 true)、max_connections(并发上限)、allowusers(cf-runagent 远程执行的用户白名单)。
八、常用可调项速查表
| 需求 | def.json 写法 | 生效方式 |
|---|---|---|
| 开启 autorun | classes.services_autorun: ["any"] | 同步后生效 |
| 关闭结果邮件 | classes.cfengine_internal_disable_agent_email: ["any"] | 同步 + 重启 |
| 放行客户端网段 | variables.acl: ["127.0.0.1/16", "10.0.0.0/8"] | 同步 + 重启 |
| 自定义业务变量 | variables.<名>: <值> | 策略中 $(def.<名>) |
| 修改调度节奏 | variables.control_executor_schedule_value: ["Min00","Min30"] | 同步 + 重启 |
| 追加 bundle 序列 | variables.bundlesequence_end: ["my_bundle"] | 同步后生效 |
| 追加输入文件 | inputs: { "services/my.cf" }(def.json 顶层键) | 同步后生效 |
💡 说明:def.json 的完整 JSON Schema 里还有
augments(嵌套引用其他 JSON)、inputs(追加解析文件)、remove_files等键;classes 值数组中的每一项都是独立的类表达式(可写ubuntu_22_04只在 Ubuntu 22.04 上开某功能)。所有control_*变量与类开关的权威清单,直接读/var/cfengine/inputs/controls/def.cf(带注释)——本文引用的每一行原文都出自该文件,版本为 3.27.2 自带的 MPF。
九、参考链接
- MPF 官方仓库(def.cf/controls 全文):https://github.com/cfengine/masterfiles
- augments(def.json)官方文档:https://docs.cfengine.com/latest/enterprise-cfengine-guide-1.html
- CFEngine 官方配置文档(Components and control bodies):https://docs.cfengine.com/latest/reference-components.html
- 同系列文档:《CFEngine 3.27.2 Ubuntu 22.04 安装指南》《CFEngine 3.27.2 CentOS 8 安装指南》《CFEngine 3.27.2 快速入门与策略编写示例》《CFEngine 3.27.2 进阶实战与运维》