18

我最近才来跨傀儡继承。围绕它的几个问题:

  1. 使用 puppet 继承是一个好习惯吗?一些有经验的puppet同事告诉我puppet的继承不是很好,我不太相信。

  2. 来自 OO 世界,我真的很想深入了解 puppet 继承是如何工作的,以及覆盖是如何工作的。

4

2 回答 2

42
  1. 这取决于,因为有两种类型的继承,你没有提到你的意思。

    1. 节点继承:从一个node fqdn { }定义继承到另一个。强烈建议不要这样做,因为它往往不符合最小意外原则。抓住人们的经典例子是这样的:

      node base {
        $mta_config = "main.cf.normal"
        include mta::postfix  # uses $mta_config internally
      }
      node mailserver inherits base {
        $mta_config = "main.cf.mailserver"
      }
      

      $mta_config变量在基本范围内进行评估,因此在邮件服务器中尝试的“覆盖”不起作用。

      没有办法直接影响父节点中的内容,因此对组合没有什么好处。这个例子可以通过从两者中删除继承和包括mta::postfix(或另一个“通用”/“基”类)来修复。然后,您也可以使用参数化类

    2. 类继承:类继承的用途是您可以覆盖父类中定义的资源的参数。以这种方式重新实现上面的示例,我们得到:

      class mta::postfix {
        file { "/etc/postfix/main.cf":
          source => "puppet:///modules/mta/main.cf.normal",
        }
        service { ... }
      }
      
      class mta::postfix::server inherits mta::postfix {
        File["/etc/postfix/main.cf"]:
          source => "puppet:///modules/mta/main.cf.server",
        }
        # other config...
      }
      

      这确实有效,但我会避免深入一层以上的继承,因为维护起来很头疼。

    3. 不过,在这两个示例中,可以通过提前指定数据(通过 ENC)或通过 extlookup 或 hiera 查询内联数据来轻松改进它们。

  2. 希望以上示例有所帮助。类继承只允许覆盖参数 - 您不能删除以前定义的资源(一个常见问题)。始终使用大写类型名称引用资源(file { ..: }将成为File[..])。

    同样有用的是,您还可以将参数定义为undef,有效地取消设置它们。

于 2012-06-22T17:43:50.110 回答
3

首先,我只是说明两者之间的区别,继承是一种“is-a”关系,Composition 是一种“has-a”关系。

1) 在 puppet 继承中是单继承,这意味着我们不能从多个类派生。继承在傀儡中很好,但我们应该知道它适用于何处。例如,Puppet 文档部分["Aside:When to Inherit" 在此链接https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#aside-when-to-inherit],它们实际上准确地命名应该发生继承的两种情况:

  • 当您想要覆盖在父类中定义的资源的参数时
  • 当您想从参数类继承标准参数值时

但请注意这里的一些重要事项:

2)另一方面,组合是实现has-a关系的设计技术。我们可以使用include puppet 关键字class { 'baseclass': }来完成,如果你想使用参数的话。

请注意:在 puppet 中,我们可以多次使用“include”,但不能使用“class”语法,因为 puppet 会抱怨重复的类定义)

所以在 Puppet 中使用哪个(继承或组合)更好:这取决于我的意思是什么上下文,你现在正在编写什么 puppet 代码,以及理解 puppet 继承的局限性以及何时使用组合。

所以,我会尽量把这一切保持在几点:

1)首先,puppet 使用单继承模型。

2) 在 puppet 中,关于继承的普遍共识是仅在需要从 Base/Parent 继承默认值时使用它

3)但是看看这个问题,你想从父级继承默认值:

class apache {
}

class tomcat inherits apache {
}

class mysql inherits tomcat {
}

class commerceServer inherits mysql {
}

乍一看这看起来合乎逻辑,但请注意 MySQL 模块现在从 tomcat 类继承默认值和资源。这不仅没有任何意义,因为这些服务是不相关的,而且它还为错误最终出现在您的 puppet 清单中提供了机会。

4)因此,更好的方法是简单地对您希望使用的每个类(我的意思是组合)执行包含,因为这消除了所有这种性质的范围问题。

结论:我们可以尝试通过使用继承来简化我们的 puppet manifest,这可能就足够了,但它只能在一定程度上可行。如果您的环境增长到数百甚至数千台服务器,由 20 或 30 多种不同类型组成服务器,一些具有共享属性和细微差异,分布在多个环境中,您可能最终会得到一个无法管理的继承模块的错综复杂的网络。在这一点上,显而易见的选择是组合。

通过这些链接,它有助于以良好的方式理解 puppet 的组成和继承(他们个人帮助了我):

  1. 设计木偶——真的很好,http://www.craigdunn.org/2012/05/239/
  2. 维基链接:http ://en.wikipedia.org/wiki/Composition_over_inheritance
  3. 使用参数化类对类组合建模: https ://puppetlabs.com/blog/modeling-class-composition-with-parameterized-classes

我基本上是一名程序员,个人是控制反转/依赖注入的坚定支持者,这是可以通过组合实现的概念/模式。

于 2015-06-04T04:08:23.803 回答