如何避免在人偶节点的 class 声明中重复自己?

How do I avoid repeating myself in class declarations for puppet nodes?

基本上,我发现自己每次都做出相同的长 class 声明:

node 'gluster3redis097.myservice.com' {
    class { 'redis' :
        class {'invoke' : }
        class {'users' : }
        class {'redis' :

        package_ensure        => '3.0.5',

        #extra_config_file    => '/etc/redis.d/redis-gluster3-master.conf',
        daemonize             => 'yes',
        pid_file              => '/var/run/redis.pid',
        log_level             => 'notice',
        log_file              => '/var/log/redis/redis.log',
        #save_db_to_disk       => false,
        workdir               => './',
        bind                  => $::ipaddress,
        slaveof                    => "${$gluster3redis_master_ips[37]}:6379",
        slave_serve_stale_data => true,
        # 2015.12.01  nathan  Do not allow inadvertent writes to the slave
        slave_read_only        => true,
        repl-diskless-sync-delay => '5',
        repl-ping-slave-period => '10',
... and so on ... 
... and so forth ...

让我们假设,对于这个集群,每个 FIFTH 节点都有一个单独的主节点。

所以,猜猜唯一改变的部分?

slaveof                    => "${$gluster3redis_master_ips[37]}:6379",

There has to be a better way.
-- Pocahontas (1995)1

根据 https://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#multiple-names,使用 Puppet inherits 关键字不是个好主意。

此外,令我沮丧的是,在 https://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#aside-best-practices 中,他们描述了以下最佳实践:

Aside: Best Practices

Although node statements can contain almost any Puppet code, we recommend that you only use them to set variables and declare classes. Avoid using resource declarations, collectors, conditional statements, chaining relationships, and functions in them; all of these belong in classes or defined types. This will make it easier to switch between node definitions and an ENC.2

我可以定义自定义类型吗?

我通读了 How to pass node specific information to class in puppet? ,但我不确定他问的是不是和我一样的问题,虽然我非常愿意学习如何定义类型,但我对它们并不熟悉足以决定是否走那条路。

我如何避免对这个 Redis 集群的每个 Puppet 节点定义重复自己?

我什至欢迎一个非常通用的答案,我可以将其应用于我的特定案例,我也已经概括了这一点。

更新:通过 common.yaml 文件为这组环境应用使用 Hiera 的通用配置似乎有效。如果 Dan Bowling 不自愿,我将在答案中进一步阐述。

对于我最初发表的评论,这是一个更简洁的答案:

任何时候您发现自己 re-declaring 设置为 class 参数时,都应考虑 Hiera。来自文档:

Hiera is a key/value lookup tool for configuration data, built to make Puppet better and let you set node-specific data without repeating yourself.

您的第一步是确定层次结构,因为 Hiera 将使用该层次结构为请求的键查找适当的值。在您的示例中,只需要一个简单的层次结构。这是一个示例 hiera.yaml 配置文件:

:backends:
  - yaml

:hierarchy:
  - "node/%{::hostname}"
  - "common"

:yaml:
  :datadir: '/your/hiera/data/directory'

:merge_behavior: deeper    

关于上面的配置:

  1. Hiera 将首先在 /your/hiera/data/directory/node/nodehostname.yaml 中查找值。您可以在此处定义 per-host 配置。
  2. 对于所有其他值,Hiera 将在 /your/hiera/data/directory/node/common.yaml
  3. 中恢复为默认值 common.yaml

因此,您的 common.yaml 可能如下所示:

redis::package_ensure: '3.0.5'
redis::pid_file: '/var/run/redis.pid'

你将有节点{1,2} /your/hiera/data/directory/node/node{1,2}.yaml:

redis::slaveof: 'your redis master value'

节点{3,4}会有这个/your/hiera/data/directory/node/node{3,4}.yaml:

redis::slaveof: 'your other redis master value'

hiera.yaml 中的 :merge_behavior: deeper 如果您想合并不同层级的设置或将复杂的散列组合成单个值,则很有用。有关详细信息,请参阅 Hiera Lookup Types