最近、パペット継承をクロスしました。それに関するいくつかの質問:
パペット継承を使用することは良い習慣ですか? パペットの経験豊富な同僚の何人かから、パペットの継承はあまり良くないと言われました。
OO の世界から来た私は、パペットの継承がどのように機能するか、オーバーライドがどのように機能するかを実際に理解したいと思っています。
最近、パペット継承をクロスしました。それに関するいくつかの質問:
パペット継承を使用することは良い習慣ですか? パペットの経験豊富な同僚の何人かから、パペットの継承はあまり良くないと言われました。
OO の世界から来た私は、パペットの継承がどのように機能するか、オーバーライドがどのように機能するかを実際に理解したいと思っています。
継承には2つのタイプがあり、どちらを意味するのかは言及されていないため、状況によって異なります。
ノードの継承:ある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
両方から(または別の「共通」/「ベース」クラス)を含めることで修正されます。その後、パラメータ化されたクラスも使用できます。
クラス継承:クラス継承の用途は、親クラスで定義されたリソースのパラメーターをオーバーライドできることです。上記の例をこのように再実装すると、次のようになります。
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...
}
これは機能しますが、維持するのが頭痛の種になるので、複数のレベルの継承を深くすることは避けたいと思います。
ただし、これらの例の両方で、事前に(ENCを介して)データを指定するか、extlookupまたはhieraを介してデータをインラインでクエリすることにより、簡単に改善できます。
上記の例がお役に立てば幸いです。クラス継承では、パラメーターのオーバーライドのみが可能です。以前に定義されたリソースを削除することはできません(一般的な質問)。常に大文字のタイプ名でリソースを参照してください(file { ..: }
になりFile[..]
ます)。
undef
また、パラメータを定義して、効果的に設定を解除できることも便利です。
最初に、この 2 つの違いを具体的に説明します。継承は「is-a」関係であり、合成は「has-a」関係です。
1) puppet の継承は単一継承です。つまり、複数のクラスから派生することはできません。パペットでは継承は適切ですが、それが適用される場所に注意する必要があります。たとえば、Puppet ドキュメント セクション["Aside: When to Inherit" at this link https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html#aside-when-to-inherit]、実際には正確に名前が付けられています。継承が発生する 2 つの状況:
ただし、ここでいくつかの重要な点に注意してください。
パペットでは、ノードとクラスの継承の違いです。
puppet の最近の新しいバージョンでは、ノードの継承が許可されていません。このhttps://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#inheritance-is-not-allowedを確認してください。
2) 一方、構成は has-a 関係を実装するための設計手法です。これはinclude puppet キーワードを使用して実行できます。また、パラメーターを使用する場合は、 class { 'baseclass': }を使用して後者を実行できます。
(注: パペットでは、「インクルード」を複数回使用できますが、「クラス」構文は使用できません。パペットはクラス定義が重複していると文句を言うからです)
したがって、(継承または構成のいずれか) が Puppet で使用するのに適しています: それは、コンテキスト、つまり、現在作成している puppet コード、および puppet 継承の制限と構成をいつ使用するかを理解しているかによって異なります。
だから、私はこれらすべてをいくつかの点に留めようとします:
1) 最初に、パペットは単一継承モデルを使用します。
2) パペットでは、継承に関する一般的なコンセンサスは、ベース/親からデフォルトを継承する必要がある場合にのみ使用することです。
3) しかし、親からデフォルトを継承したいこの問題を見てください:
class apache {
}
class tomcat inherits apache {
}
class mysql inherits tomcat {
}
class commerceServer inherits mysql {
}
一見、これは論理的に見えますが、MySQL モジュールが tomcat クラスからデフォルトとリソースを継承していることに注意してください。これらのサービスは無関係であるため、これは無意味であるだけでなく、パペット マニフェストでミスが発生する可能性もあります。
4) したがって、より良いアプローチは、使用したい各クラス (コンポジションを意味します) で単純にインクルードを実行することです。これにより、この性質のすべてのスコープの問題が解消されます。
結論:継承を使用して puppet マニフェストを単純化することができます。これで十分かもしれませんが、ある程度までしか機能しません。環境が数百または数千のサーバーに成長し、20 または 30 を超える異なるタイプで構成されている場合サーバーのいくつかは共有属性と微妙な違いを持ち、複数の環境に分散していると、継承されたモジュールの絡み合った管理不能な Web になる可能性があります。この時点で、明らかな選択はコンポジションです。
これらのリンクをたどると、パペットの構成と継承を適切に理解するのに役立ちます (個人的には役に立ちました)。
私は基本的にプログラマーであり、個人的には Inversion of Control/Dependency Injection の強力な支持者です。これは、コンポジションを通じて可能なコンセプト/パターンです。