CFEngine 3.27.2 配置参数详解

CFEngine 3.27.2 配置参数详解:masterfiles 到 inputs 的同步机制、promises.cf 主配置(bundlesequence/inputs)逐项解析、def.json 覆盖机制实测、body agent/executor/server control 全参数说明,含邮件开关与 ACL 覆盖链实测

CFEngineCFEngineLinux自动化配置管理2026/10/17

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.jsonJSON 格式的变量/类覆盖层,优先级高于 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.cfMPF 全部默认值定义(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_managementCFEngine 自管理(保证 inputs 同步、服务运行等)
mpf_mainMPF 主体(内置承诺的落地点)
@(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:定义变量,加载进 def bundle,策略里用 $(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,未列出的条目保持默认即可):

属性默认值说明
ifelapsed1(分钟)同一条 promise 两次评估的最小间隔。改小会显著增加评估频率;手动 -K 就是跳过该锁
evaluation_orderclassicpromise 评估顺序(3.27 新增 top_down 选项,按书写顺序评估)
skipidentifytrue连接时跳过 IP/名字反查(DNS 异常环境下防卡顿)
abortclassescfengine_3_3、cfengine_3_4 等命中即整体终止的「熔断」类(检测到极旧版本数据结构时防误操作)
abortbundleclasses空(正则列表)命中即终止当前 bundle 的类正则
maxconnections10(def.cf 默认)到单台 cf-serverd 的最大并发连接数
default_directory_create_mode770files 承诺自动建目录时的默认权限
agentfacilitycfe(内部日志前缀)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.";
属性默认值说明
splaytime4(分钟)把大批主机的执行起点打散在 0–4 分钟内随机错开,防止策略服务器瞬时被打爆;单机场景无感
agent_expireafter120(分钟)agent 运行超过此时长且无输出则被 cf-execd 杀掉,防僵尸进程
scheduleMin00–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",
属性默认值说明
mailtoroot@<域名>运行结果邮件收件人
mailfromroot@<主机名>.<域名>发件人
smtpserverlocalhost投递服务器;系统无 smtp 服务时报 unable to lookup smtp service(处置见 4.2 与《CFEngine 3.27.2 Ubuntu 22.04 安装指南》10.3)
mailmaxlines30邮件正文最多携带的输出行数

注意原文的类守卫 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"));

推导链完整解读:

  1. def.acl 默认 $(sys.policy_hub)/16——策略服务器 IP 所在 /16 网段(sys.policy_hub 是自举时写入 policy_server.dat 的地址);
  2. acl_derived 再并上策略服务器自身地址;
  3. 最终 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 写法生效方式
开启 autorunclasses.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。

九、参考链接