###序章

簡単に言うと、サーバー構成管理(一般にITオートメーションとも呼ばれます)は、インフラストラクチャ管理をコードベースに変換するソリューションであり、バージョン管理して簡単に再利用できる一連のプロビジョニングスクリプトでサーバーを展開するために必要なすべてのプロセスを記述します。 時間の経過とともに、サーバーインフラストラクチャの整合性を大幅に向上させることができます。

以前のガイドでは、サーバーインフラストラクチャに構成管理戦略を実装する主な利点、構成管理ツールの仕組み、およびこれらのツールに通常共通するものについて説明しました。

シリーズのこのパートでは、マスターサーバーを使用してノードの構成を調整し、複雑なインフラストラクチャを透過的に管理できる一般的な構成管理ツールであるPuppetを使用してサーバープロビジョニングを自動化するプロセスについて説明します。 Apacheを使用してUbuntu18.04Webサーバーのデプロイを完全に自動化するための簡略化された例を作成するために必要な言語の用語、構文、および機能に焦点を当てます。

これは、目標を達成するために自動化する必要がある手順のリストです。

  1. aptキャッシュを更新します
  2. Apacheをインストールします
  3. カスタムドキュメントルートディレクトリを作成します
  4. index.htmlファイルをカスタムドキュメントルートに配置します
  5. テンプレートを適用して、カスタム仮想ホストを設定します
  6. Apacheを再起動します

まず、Puppetで使用される用語を確認し、次にマニフェストの作成に使用できる主な言語機能の概要を説明します。 このガイドの最後に、完全な例を共有して、自分で試してみることができるようにします。

注:このガイドは、Puppet言語と、サーバープロビジョニングを自動化するためのマニフェストの作成方法を紹介することを目的としています。 このツールのインストールと開始に必要な手順を含む、Puppetの詳細については、Puppetの公式ドキュメントを参照してください。

##入門

Puppetのより実践的なビューに移る前に、このツールによって導入された重要な用語と概念を理解することが重要です。

###人形の用語

  • Puppet Master :ノードの構成を制御するマスターサーバー
  • Puppet Agentノード:Puppetマスターによって制御されるノード
  • マニフェスト:実行される一連の命令を含むファイル
  • Resource :システムの要素とその状態を変更する方法を宣言するコードの一部。 たとえば、パッケージをインストールするには、 package リソースを定義し、その状態が「installed」に設定されていることを確認する必要があります
  • Module :プロビジョニングの一部の共有と再利用を容易にするために、事前定義された方法で編成されたマニフェストおよびその他の関連ファイルのコレクション
  • クラス:通常のプログラミング言語と同様に、クラスはPuppetで使用され、プロビジョニングをより適切に整理し、コードの一部を再利用しやすくします。
  • 事実:ネットワークインターフェイスやオペレーティングシステムなど、システムに関する情報を含むグローバル変数
  • サービス:サービスの再開や停止など、サービスステータスの変更をトリガーするために使用されます

Puppetのプロビジョニングは、Rubyに基づくカスタムDSL(ドメイン固有言語)を使用して記述されています。 ###リソースPuppetでは、タスクまたはステップはリソースを宣言することで定義されます。 リソースは、パッケージ、ファイル、サービス、ユーザー、およびコマンドを表すことができます。 それらには状態がある場合があり、宣言されたリソースの状態が現在システム上にあるものと異なる場合にシステム変更をトリガーします。 たとえば、マニフェストで package リソースをinstalledに設定すると、パッケージが以前にインストールされていない場合、システムにパッケージがインストールされます。

パッケージリソースは次のようになります。

package { 'nginx':
    ensure  => 'installed'
}

次のように、execリソースを宣言することにより、任意のコマンドを実行できます。

exec { 'apt-get update':
    command => '/usr/bin/apt-get update'
}

最初の行のapt-get updateの部分は実際のコマンド宣言ではなく、この一意のリソースの識別子であることに注意してください。 多くの場合、リソース内から他のリソースを参照する必要があり、そのためにそれらの識別子を使用します。 この場合、識別子はapt-get updateですが、他の文字列でもかまいません。 ###リソースの依存関係マニフェストを作成するときは、Puppetが定義されているのと同じ順序でリソースを評価しないことに注意することが重要です。 これは、Puppetを使い始めた人にとって一般的な混乱の原因です。 リソースは相互の依存関係を明示的に定義する必要があります。そうしないと、どのリソースが最初に評価され、結果として実行されるかが保証されません。

簡単な例として、コマンドを実行したいが、最初に依存関係がインストールされていることを確認する必要があるとします。

package { 'python-software-properties':
    ensure => 'installed'
}

exec { 'add-repository':
    command => '/usr/bin/add-apt-repository ppa:ondrej/php5 -y'
    require => Package['python-software-properties']
}

requireオプションは、パラメーターとして別のリソースへの参照を受け取ります。 この場合、python-software-propertiesとして識別されるPackageリソースを参照しています。 リソースの宣言(小文字)にはexecpackageなどを使用しますが、以前に定義したリソースを参照する場合は、ExecPackageなど(大文字)。

ここで、タスクが前に実行されることを確認する必要があるとします。 このような場合、代わりにbeforeオプションを使用できます。

package { 'curl':
    ensure => 'installed'
    before => Exec['install script']
}

exec { 'install script':
    command => '/usr/bin/curl http://example.com/some-script.sh'

###マニフェスト形式マニフェストは基本的に、拡張機能.ppを使用したリソース宣言のコレクションです。 以下に、2つのタスクを実行する簡単なプレイブックの例を示します。aptキャッシュを更新し、後でvimをインストールします。

exec { 'apt-get update':
    command => '/usr/bin/apt-get update'
}

package { 'vim':
    ensure => 'installed'
    require => Exec['apt-get update']
}

このガイドが終了する前に、マニフェストのより実際的な例を詳しく説明します。 次のセクションでは、Puppetマニフェストの作成に使用できる最も重要な要素と機能の概要を説明します。 ##マニフェストの記述###変数の操作変数は、マニフェストの任意の時点で定義できます。 最も一般的なタイプの変数は文字列と文字列の配列ですが、ブール値やハッシュなどの他のタイプもサポートされています。

次の例では、後でリソース内で使用される文字列変数を定義しています。

$package = "vim"

package { $package:
   ensure => "installed"
}

###ループの使用ループは通常、異なる入力値を使用してタスクを繰り返すために使用されます。 たとえば、10個の異なるパッケージをインストールするために10個のタスクを作成する代わりに、単一のタスクを作成し、ループを使用して、インストールするすべての異なるパッケージでタスクを繰り返すことができます。

Puppetで異なる値を使用してタスクを繰り返す最も簡単な方法は、次の例のように配列を使用することです。

$packages = ['vim', 'git', 'curl']

package { $packages:
   ensure => "installed"
}

バージョン4の時点で、Puppetはタスクを反復処理するための追加の方法をサポートしています。 以下の例は前の例と同じことを行いますが、今回はeachイテレーターを使用します。 このオプションを使用すると、リソース定義をより柔軟にループできます。

$packages.each |String $package| {
  package { $package:
    ensure => "installed"
  }
}

###条件付きの使用条件付きを使用すると、たとえば、変数やコマンドからの出力に基づいて、コードのブロックを実行するかどうかを動的に決定できます。

Puppetは、if/elsecaseステートメントなど、従来のプログラミング言語で見られるほとんどの条件付き構造をサポートしています。 さらに、execなどの一部のリソースは、条件付きのように機能する属性をサポートしますが、条件としてコマンド出力のみを受け入れます。

factに基づいてコマンドを実行するとします。 この場合、変数の値をテストするため、if/elseなどのサポートされている条件付き構造の1つを使用する必要があります。

if $osfamily != 'Debian' {
 warning('This manifest is not supported on this OS.')
}
else {
 notify { 'Good to go!': }
}

もう1つの一般的な状況は、別のコマンドからの出力に基づいてコマンドの実行を条件付けする場合です。 このような場合は、次の例のように、onlyifまたはunlessを使用できます。 このコマンドは、/bin/which phpからの出力が成功した場合、つまり、コマンドがステータス0で終了した場合にのみ実行されます。

exec { "Test":
 command => "/bin/echo PHP is installed here > /tmp/test.txt",
 onlyif => "/bin/which php"
}

同様に、unlessは、unlessの下のコマンドが正常に終了した場合を除いて、常にコマンドを実行します。

exec { "Test":
 command => "/bin/echo PHP is NOT installed here > /tmp/test.txt",
 unless => "/bin/which php"
}

###テンプレートの操作テンプレートは通常、構成ファイルを設定するために使用され、これらのファイルをより用途が広く再利用可能にすることを目的とした変数やその他の機能を使用できるようにします。 Puppetは、Embedded Puppet(EPP)とEmbedded Ruby(ERB)の2つの異なる形式のテンプレートをサポートしています。 ただし、EPP形式は、最近のバージョンのPuppet(バージョン4.0以降)でのみ機能します。

以下は、このホストのドキュメントルートを設定するための変数を使用して、Apache仮想ホストを設定するためのERBテンプレートの例です。

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    <Directory <%= @doc_root %>>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

テンプレートを適用するには、templateメソッドを使用してテンプレートコンテンツをレンダリングするfileリソースを作成する必要があります。 これは、このテンプレートを適用してデフォルトのApache仮想ホストを置き換える方法です。

file { "/etc/apache2/sites-available/000-default.conf":
    ensure => "present",
    content => template("apache/vhost.erb") 
}    

Puppetは、編成とモジュール性を強化するために、ローカルファイルを処理するときにいくつかの仮定を行います。 この場合、Puppetは、モジュールディレクトリ内のフォルダapache/templates内でvhost.erbテンプレートファイルを検索します。

###サービスの定義とトリガーサービスリソースは、サービスが初期化されて有効になっていることを確認するために使用されます。 また、サービスの再起動をトリガーするためにも使用されます。

Apache仮想ホストをセットアップした以前のテンプレートの使用例を考慮に入れましょう。 仮想ホストの変更後にApacheが確実に再起動されるようにする場合は、最初にApacheサービスのserviceリソースを作成する必要があります。 このようなリソースがPuppetで定義される方法は次のとおりです。

service { 'apache2':
    ensure => running,
    enable => true
}

ここで、リソースを定義するときに、再起動をトリガーするためにnotifyオプションを含める必要があります。

file { "/etc/apache2/sites-available/000-default.conf":
    ensure => "present",
    content => template("vhost.erb"),
    notify => Service['apache2'] 
} 

##マニフェストの例次に、このガイドの概要で説明されているように、Ubuntu14.04システム内でのApacheWebサーバーのインストールを自動化するマニフェストを見てみましょう。

Apacheを設定するためのテンプレートファイルとWebサーバーによって提供されるHTMLファイルを含む完全な例は、Githubにあります。 このフォルダーには、 Vagrant によって管理される仮想マシンを使用して、簡略化されたセットアップでマニフェストをテストできるVagrantfileも含まれています。

以下に完全なマニフェストを示します。

default.pp
  1. $doc_root = "/var/www/example"
  2. exec { 'apt-get update':
  3. command => '/usr/bin/apt-get update'
  4. }
  5. package { 'apache2':
  6. ensure => "installed",
  7. require => Exec['apt-get update']
  8. }
  9. file { $doc_root:
  10. ensure => "directory",
  11. owner => "www-data",
  12. group => "www-data",
  13. mode => 644
  14. }
  15. file { "$doc_root/index.html":
  16. ensure => "present",
  17. source => "puppet:///modules/main/index.html",
  18. require => File[$doc_root]
  19. }
  20. file { "/etc/apache2/sites-available/000-default.conf":
  21. ensure => "present",
  22. content => template("main/vhost.erb"),
  23. notify => Service['apache2'],
  24. require => Package['apache2']
  25. }
  26. service { 'apache2':
  27. ensure => running,
  28. enable => true
  29. }

###マニフェストの説明

####行1マニフェストは、変数定義$doc_rootで始まります。 この変数は、後でリソース宣言で使用されます。

####3-5行目このexecリソースは、apt-get updateコマンドを実行します。

####行7-10このパッケージリソースはパッケージapache2をインストールし、apt-get updateリソースが要件であることを定義します。つまり、次の後にのみ実行されます。必要なリソースが評価されます。

#### 12〜17行目ここでは file リソースを使用して、ドキュメントルートとして機能する新しいディレクトリを作成します。 fileリソースは、ディレクトリとファイルの作成に使用できます。また、テンプレートの適用やローカルファイルのリモートサーバーへのコピーにも使用されます。 このタスクはプロビジョニングのどの時点でも実行できるため、ここでrequireを設定する必要はありませんでした。

####行19〜23ここでは、別の file リソースを使用して、ローカルのindex.htmlファイルをサーバー内のドキュメントルートにコピーします。 sourceパラメーターを使用して、元のファイルの場所をPuppetに通知します。 この命名法は、Puppetがローカルファイルを処理する方法に基づいています。 Githubサンプルリポジトリを見ると、Puppetがこのリソースを見つけられるようにするためにディレクトリ構造を作成する方法がわかります。 このリソースを実行する前にドキュメントルートディレクトリを作成する必要があるため、前のリソースを参照するrequireオプションを含めます。

#### 25〜30行目新しい file リソースを使用して、Apacheテンプレートを適用し、サービスに再起動を通知します。 この例では、プロビジョニングは main というモジュールで構成されているため、テンプレートソースは main /vhost.erbです。 requireステートメントを使用して、パッケージapache2がインストールされた後にのみテンプレートリソースが実行されるようにします。そうしないと、Apacheで使用されるディレクトリ構造がまだ存在しない可能性があります。

#### lines 32-35最後に、 serviceリソースはapache2サービスを宣言します。これは、仮想ホストテンプレートを適用するリソースからの再起動を通知します。

##結論Puppetは、表現力豊かなカスタムDSLを使用してサーバーリソースを管理し、タスクを自動化する強力な構成管理ツールです。 その言語は、プロビジョニング設定に追加の柔軟性を与えることができる高度なリソースを提供します。 リソースは定義されたのと同じ順序で評価されないことを覚えておくことが重要です。そのため、正しい実行チェーンを確立するために、リソース間の依存関係を定義する際には注意が必要です。

このシリーズの次のガイドでは、Rubyプログラミング言語を活用してインフラストラクチャの管理とプロビジョニングを自動化するもう1つの強力な構成管理ツールであるChefについて説明します。