CFEngine

本文档基于 CFEngine Core 3.9.1

Cfengine 是历史最悠久的配置管理软件. 虽然受到了来自众多后起之秀(puppet, saltstack, Chef...)的挑战, 但是 CFE 还是成功的活了下来. 相对于其他配置管理软件, CFE 最明显的优势有:

  • 依赖少, 部署方便.

    当前版本只需要安装一个包, 执行一个命令即可完成部署.

  • 运行开销小, 效率高

    CFE 使用 c/c++ 编写, 运行效率毋庸置疑.

  • 架构简单

    最核心的组件只有 cf-agent 一个, 其他的组件其实都是可选的.

    cf-serverd 通常只是一个提供策略文件下载的文件服务器. 策略文件的解析是在 agent 端进行的. 所以, 相对于其他配置管理软件, CFE 的 server 端能够管理更多的 agent 端.

    cf-execd 也不过是个定时器.

    所以, 如果你用 rsync 同步策略文件, 用 crond 定期执行 cf-agent, 完全可以不启动 cf-agent 和 cf-serverd.

  • DSL不依赖于特定编程语言.

  • 安全

    外部只能触发 cf-agent 执行, 以及类的定义. 无法利用 cf-agent 执行策略文件之外的命令.

Install

参考官方文档

软件安装完成后, 需要执行/var/cfengine/bin/cf-agent --bootstrap <IP address of policy server>来进行初始化.

COMPONENT

cf-execd

周期性触发 cf-agent 执行. 默认间隔 5 分钟.

cf-runagent

cf-runagent 可以远程批量触发 cf-agent 运行(通过 cf-serverd). 在这个过程中, 可以通过 --define-class, -D value 选项来定义 cf-agent 执行时候的 class; 可以通过 --select-class, -s value 来筛选需要被触发的 cf-agent. 实际使用的时候, 这些机制大概有两方面的作用:

  1. 测试. 通过指定 class 可以在目标机器上应用任意的策略.
  2. 可以远程批量触发命令执行, 从而部分替代批量执行工具, 例如: ansible. 但是通过这种方式触发的命令需要在策略文件中预先定义, 而且无法传递参数, 所以灵活性上稍有欠缺.

Modules

用法有两种

  1. Set variables and classes based on command output

    • lines which begin with a ^ are protocol extensions
      • ^context=xyz sets the module context to xyz instead of the default
      • ^meta=a,b,c sets the class and variable tags for any following definitions to a, b, and c
    • lines which begin with a + are treated as classes to be defined (like -D)
    • lines which begin with a - are treated as classes to be undefined (like -N)
    • lines which begin with = are scalar variables to be defined
    • lines which begin with = and include [] are array variables to be defined
    • lines which begin with @ are lists.
    • lines which begin with % are data containers. The value needs to be valid JSON and will be decoded.
  2. usemodule()

Promis

Command

Files

edit_line

虽然 edit_line 可以很灵活的控制文件内容, 尤其是以"行"为单位的/简单的配置文件. 但是对于复杂的, 结构化的配置文件就显得力不从心.

另一个问题是, 基于 edit_line 来控制文件内容, 很难控制配置文件的完整内容, 配置难以收敛. 所以强烈不推荐使用 edit_line.

edit template

  • template_method => "cfengine", native-CFEngine template format, default. v3.3.0
  • template_method => "mustache". v3.6.0

edit_template 是多年来一直希望添加的功能. 但是即便是在不支持模板的 cfengine2 时代, 也不是实现不了, 只是稍微麻烦一点而已.

edit_xml

有了模板其实就不需要这个东西了, 和 edit_line 问题一样, 无法控制配置的完整内容, 配置难以收敛.

Q&A

如何确定 policy_server.

/var/cfengine/policy_server.dat 中保存着 policy_server 的地址.

default:cfe_autorun_inventory_cmdb.sys#policy_hub 192.168.80.136           source=agent
default:def.policy_servers                {"192.168.80.136"}               source=promise
default:def.sys#policy_hub               192.168.80.136                    source=agent
default:sys.policy_hub                   192.168.80.136                    source=bootstrap

这些变量的值都是通过policy_server.dat的内容决定的.

默认情况下policy file 是如何更新的?

controls/cf_serverd.cf

!windows::
  # last single quote in cfruncommand is left open, so that
  # arguments (like -K and --remote-bundles) are properly appended.
  cfruncommand => "$(def.cf_runagent_shell) -c \'
                       $(sys.cf_agent) -I -D cfruncommand -f $(sys.update_policy_path)  ;
                       $(sys.cf_agent) -I -D cfruncommand";

controls/cf_execd.cf

!windows::
  exec_command => "$(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated -f \"$(sys.update_policy_path)\" ; $(sys.cf_agent) -Dfrom_cfexecd,cf_execd_initiated";

从 cf_serverd.cf 和 cf_execd.cf 中我们可以看到, 不管是通过 cf_serverd 还是 cf_execd 执行 cf_agent 都会先执行sys.update_policy_path中的策略来更新策略文件. 那么sys.update_policy_path是谁呢? 我们可以通过下面的命令查看.

$ cf-promises --show-vars |grep update.cf

default:sys.update_policy_path           /var/cfengine/inputs/update.cf              source=agent

/var/cfengine/inputs/update.cf 引入了大量更新相关的策略文件

body common control
{
      bundlesequence => {
                          "update_def",
                          "u_cfengine_enterprise",
                          @(u_cfengine_enterprise.def),
                          "cfe_internal_dc_workflow",
                          "cfe_internal_bins",
                          "cfe_internal_update_policy",
                          "cfe_internal_update_bins",
                          "cfe_internal_update_processes",
      };

      version => "update.cf $(update_def.current_version)";

      inputs => {
                  @(cfengine_update_controls.update_def_inputs),
                  "cfe_internal/update/update_bins.cf",
                  "cfe_internal/update/cfe_internal_dc_workflow.cf",
                  "cfe_internal/update/cfe_internal_local_git_remote.cf",
                  "cfe_internal/update/cfe_internal_update_from_repository.cf",
                  "cfe_internal/update/update_policy.cf",
                  "cfe_internal/update/update_processes.cf"
      };
}

主要的更新逻辑包含在 cfe_internal/update/update_policy.cf 中.

!am_policy_hub::  # policy hub should not alter inputs/ uneccessary

  "$(inputs_dir)/cf_promises_validated"
  comment => "Check whether a validation stamp is available for a new policy update to reduce the distributed load",
  handle => "cfe_internal_update_policy_check_valid_update",
  copy_from => u_rcp("$(master_location)/cf_promises_validated", @(update_def.policy_servers)),
  action => u_immediate,
  classes => u_if_repaired("validated_updates_ready");

这一段通过检查policy_servers 上的 cf_promises_validated 是否更新, 来确定policy_servers 上的策略文件是否有变化.

am_policy_hub|validated_updates_ready::  # policy hub should always put masterfiles in inputs in order to check new policy

  "$(inputs_dir)"
  comment => "Copy policy updates from master source on policy server if a new validation was acquired",
  handle => "cfe_internal_update_policy_files_inputs_dir",
  copy_from => u_rcp("$(master_location)", @(update_def.policy_servers)),
  depth_search => u_recurse("inf"),
  file_select  => u_input_files,
  action => u_immediate;

如果policy_server 上的策略文件有变化, 则更新本地的策略文件. 这里我们看到客户端 和 policy_server 本身的更新逻辑是相同的.

  "validated_updates_ready"
    expression => "cfengine_internal_disable_cf_promises_validated",
    comment => "If cf_promises_validated is disabled, then updates are
                always considered validated.";

cfengine_internal_disable_cf_promises_validated 如果被设置, 那么无论服务器端的 cf_promises_validated 文件是否有变化, validated_updates_ready 这个类都会被设置, 也就是说: 会触发客户端进行更新.

  "cfengine_internal_disable_cf_promises_validated"
    expression => "!any",
    comment => "When cf_promises_validated is disabled remote agents will
               always scan all of masterfiles for changes. Disabling this
               is not recomended as it will increase the load on the policy
               server and increases the possibility for remote agents to
               recieve broken policy.";

但是在 controls/update_def.cf 中我们可以看到 cfengine_internal_disable_cf_promises_validated 默认情况下是不被设置的, 也就是说默认情况下需要通过 cf_promises_validated 文件的状态来判断是否更新.

body copy_from u_rcp(from,server)
{
      source      => "$(from)";
      compare     => "digest";
      trustkey    => "false";

    !am_policy_hub::

      servers => { "$(server)" };

    cfengine_internal_encrypt_transfers::
      encrypt => "true";

    cfengine_internal_purge_policies::
      purge => "true";

    cfengine_internal_preserve_permissions::
      preserve => "true";
}

在 copy_from u_rcp 的定义中我们看到, 客户端更新时 servers 属性(policy_server) 被设置为传入的参数, 但是没有指定 policy_server 更新时的 servers. 实际上, copy_from 的默认 servers 是 localhost, policy_server 更新的时候是从本机同步文件, 所以无需指定.

Link

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • OSSIM架构与组成综述 一、背景 如果运维工程师手里没有高效的管理工具支持,就很难快速处理故障。市面上有很多运维...
    OSSIMCN阅读 1,407评论 0 1
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 6,320评论 0 6
  • 一、基础知识篇:Http Header之User-AgentUser Agent中文名为用户代理,是Http协议中...
    iPhone阅读 15,694评论 0 13
  • 今天是第46天,孕期软件说郭小米现在有黑豆那么大了,什么鬼,瓜子变黑豆?那不是更小了吗,莫非逆生长?看来程序员的语...
    little_R阅读 299评论 0 0