ロールとプロファイル: 詳細な例

Included in Puppet Enterprise 2017.2.

適度に簡略化された例を通じて、ロールとプロファイルの完全なワークフローを示します。

ロールとプロファイルの手法の全体像を理解するために活用してください。 この後の例では、このコード例をリファクタリングしてさらに複雑なコードにすることで、高度な設定にする方法を示します。

サンプル: Jenkins master

Jenkinsとは、JVM上で動作する連続的なインテグレーション(CI)アプリケーションです。Jenkins masterサーバーはWebフロントエンドを提供するとともに、指定時間またはイベントへの対応としてCIタスクを実行します。

主な例として、Jenkins masterサーバーの設定を管理します。

ステップ0: 前提条件を設定する

ロールとプロファイルを初めて使用する場合は、新しいコードを記述する前に設定を追加する必要があります。

  1. モジュールを2つ作成します。そのうち1つはrole、もう1つはprofileと名付けます。

    Puppet Enterpriseのコードマネージャやr10kを使用してコードをデプロイする場合、これら2つのモジュールをPuppetfileで宣言するのではなく、管理リポジトリに格納しておくことを推奨します。 コードマネージャとr10kは、modulesディレクトリを各自の用途のために予約しているため、それぞれ個別のディレクトリに格納する必要があります。

    1. リポジトリに、siteという名前の新規ディレクトリを作成します。
    2. environment.confファイルを編集し、modulepathsiteを追加します(例: modulepath = site:modules:$basemodulepath)。
    3. roleおよびprofileモジュールをsiteディレクトリに格納します。
  2. HieraまたはPuppetルックアップに、適切な階層が設定されていて動作していることを確認します。

ステップ1: コンポーネントモジュールを選択する

  1. この例では、Jenkins自体を管理します。標準的なモジュールはrtyler/jenkinsです。
  2. JenkinsにはJavaが必要です。また、rtylerモジュールはJavaを自動的に管理できます。しかし、Javaを細かく管理したいため、ここではrtylerモジュールは無効にします。つまり、Javaモジュールが必要なので、puppetlabs/javaがあればよいでしょう。

まずはそれで十分です。動作させてから、リファクタリングと拡張を行います。

ステップ2: プロファイルを記述する

Puppetから見ると、プロファイルはprofileモジュールに保存された通常クラスの1つです。 .../profile/manifests/jenkins/master.ppprofile::jenkins::masterという名前の新規クラスを作成し、ここにPuppetコードを記述します。

プロファイルクラスのルール

  1. どのプロファイルも、何度でも安全にincludeできることを確認してください。プロファイルにリソースライクなクラス宣言は使用しないでください。
  2. プロファイルには、他のプロファイルをincludeできます。
  3. プロファイルは、コンポーネントクラスのすべてのクラスパラメータを所有します。プロファイルでいずれかのクラスパラメータが省略されている場合、デフォルト値が確実に必要です。コンポーネントクラスはHieraデータの値を使用してはなりません。以前に省略されたクラスパラメータを設定する必要がある場合、プロファイルをリファクタリングします。
  4. コンポーネントクラスを設定するにあたり、プロファイルに必要な情報を入手するには3通りの方法があります。
    • 指定のパラメータに対して常に同じ値を使用する場合は、ハードコード化してください。
    • ハードコード化できない場合は、すでにわかっている情報をもとに計算してください。
    • 最後に、計算できない場合は、データの中で ルックアップを実行します。ルックアップを減らすため、1つの質問に対する回答から複数のパラメータを得られるケースを特定します。

    何らかのトレードオフが必要となるということです。 つまり、ハードコード化されたパラメータは読みやすいものの、柔軟性には欠けます。 一方で、Hieraデータに値を指定すると柔軟性は非常に高まりますが、読みにくくなります。プロファイルの実際の動作を見るには、多数のファイルを確認(または多数のルックアップコマンドを実行)しなければならないことがあります。 その妥協点として、条件分岐を使用して値を生成します。

    可能な手段の中で、最も読みやすいオプションを選んでください。

プロファイルコード例

# /etc/puppetlabs/code/environments/production/site/profile/manifests/jenkins/master.pp
class profile::jenkins::master (
  String $jenkins_port = '9091',
  String $java_dist    = 'jdk',
  String $java_version = 'latest',
) {

  class { 'jenkins':
    configure_firewall => true,
    install_java       => false,
    port               => $jenkins_port,
    config_hash        => {
      'HTTP_PORT'    => { 'value' => $jenkins_port },
      'JENKINS_PORT' => { 'value' => $jenkins_port },
    },
  }

  class { 'java':
    distribution => $java_dist,
    version      => $java_version,
    before       => Class['jenkins'],
  }
}

これは比較的シンプルな例ですが、これだけでもメリットはあります。Jenkinsを構成するためのインターフェースは、Jenkinsクラスの場合は30個のパラメータで構成されていましたが(Javaの場合はそれよりも多い)、わずか3つにまで抑えられています。 ここで、configure_firewallおよびinstall_javaパラメータをハードコード化し、$jenkins_portの値を3か所で再利用していることに注目してください。

データとクラスパラメータについて

通常、プロファイルには何らかの設定が必要で、その設定のためにデータルックアップを使用する必要があります。

このプロファイルでは、自動クラスパラメータルックアップを使用してデータをリクエストします。 しかし、パラメータを省略してlookup関数を使用することもできます。

class profile::jenkins {
  $jenkins_port = lookup('profile::jenkins::jenkins_port', {value_type => String, default_value => '9091'})
  $java_dist    = lookup('profile::jenkins::java_dist',    {value_type => String, default_value => 'jdk'})
  $java_version = lookup('profile::jenkins::java_version', {value_type => String, default_value => 'latest'})
  # ...

一般的に、クラスパラメータの方が適切です。 クラスパラメータはPuppet Stringsのようなツールとも統合でき、設定を見つけられる場所として信頼性が高く、広く知られています。 しかし、自動パラメータルックアップに慣れていない場合は、lookupを使用する方が適切なアプローチです。 グローバルにgrepできるよう、プロファイルに完全なルックアップキーを記述することを好む人もいます。

ステップ3: プロファイル用のHieraデータを設定する

以下の条件を仮定します。

  • カスタムfactを使用する。
    • group: このノードが属するグループ(事業部や多数のノードが共有する大規模な機能など)。
    • stage: このノードのデプロイステージ(dev、test、prodなど)。
  • 4つのレイヤで構成される階層がある。
    • nodes/%{trusted.certname}(ノードごとのオーバーライド用)
    • groups/%{facts.group}/%{facts.stage}(グループ内のステージ固有データの設定用)
    • groups/%{facts.group}(グループ固有のデータの設定用)
    • common(グローバルフォールバックデータ用)
  • 単発的なJenkins masterはありますが、そのほとんどはciグループに属します。
  • 品質エンジニアリング(QE)部では、ciグループのmasterがOracke JDKを使用するようにしたいと考えていますが、単発的なマシンではプラットフォームのデフォルトのJavaしか使用できません。
  • また、prod masterがポート80でリッスンするように設定したいとも考えています。

ここで、次の値をデータに設定します。

# /etc/puppetlabs/code/environments/production/data/nodes/ci-master01.example.com.yaml
# --Nothing. We don't need any per-node values right now.

# /etc/puppetlabs/code/environments/production/data/groups/ci/prod.yaml
profile::jenkins::master::jenkins_port: '80'

# /etc/puppetlabs/code/environments/production/data/groups/ci.yaml
profile::jenkins::master::java_dist: 'oracle-jdk8'
profile::jenkins::master::java_version: '8u92'

# /etc/puppetlabs/code/environments/production/data/common.yaml
# --Nothing. Just use the default parameter values.

ステップ4: ロールを記述する

次に、管理対象のマシンを考慮し、Jenkinsプロファイル以外に必要なものを決定します。

Jenkins masterは、他の目的は果たしません。 しかし、フリートの全マシンには、以下のプロファイルがあることを想定しています(ここではコードは示しません)。

  • profile::baseを、ワークステーションを含むすべてのマシンに割り当てる必要があります。基本的なポリシーを管理し、必要に応じてOS固有のプロファイルを含めるために、条件分岐を使用します。
  • profile::serverは、ネットワーク上でサービスを提供するすべてのマシンに割り当てる必要があります。オペレータがマシンにログインできるようにし、時間管理、ファイアウォール、ロギング、モニタリングなどを設定します。

そのため、Jenkins masterを管理するロールにもこれらのクラスが必要となります。

ロールクラスのルール

ロールクラスを記述する際のルールは以下のとおりです。

  1. ロールが行う唯一のこととは、includeでプロファイルクラスを宣言することです。 ロールでコンポーネントクラスや通常のリソースを宣言しないでください。

    あるいは、ロールで条件分岐を使用し、使用するプロファイルを決定することもできます。 また、ロールが同じルールに準じていれば、他のロールクラスを含めることもできます。

  2. ロールは、独自のクラスパラメータを所有してはなりません。
  3. ロールは、プロファイルのクラスパラメータを設定してはなりません(プロファイルのクラスパラメータはデータルックアップで処理されます)。
  4. ロールの名称は、ビジネスが管理するノードのタイプの通称に基づいて指定されます。

    つまり、マシンに「Jenkins master」という名前を付けている場合は、role::jenkins::masterという名前のロールを記述するということです。 また、「web server」という名前を付けている場合は、role::nginxではなくrole::webという名前を使います。

ロールコードの例

class role::jenkins::master {
  include profile::base
  include profile::server
  include profile::jenkins::master
}

ステップ5: ロールをノードに割り当てる

最後に、Jenkins masterとして動作するすべてのノードにrole::jenkins::masterを割り当てます。

Puppetには、ノードにクラスを割り当てる方法がいくつかあるため、チームに適したツールを使用してください。 主な選択肢は以下のとおりです。

  • PEコンソールノード分類子。factsに基づいてノードをグループ化し、それらのグループにクラスを割り当てます。
  • mainマニフェストノードステートメントまたは条件分岐を使用してクラスを割り当てます。
  • HieraまたはPuppetルックアップ - lookup関数を使用して特殊なclassesキーに対して独自の配列マージを実行し、その結果として生成された配列をinclude関数に渡します。

次の手順

ロールとプロファイルの使用方法がわかると、以下のことが行えるようになります。

↑ Back to top