構成管理101:Chefレシピの作成

簡単に言えば、サーバー構成管理(一般的にITオートメーションとも呼ばれます)は、インフラストラクチャ管理をコードベースに変換するソリューションであり、バージョン管理および再利用が容易なプロビジョニングスクリプトのセットでサーバーを展開するために必要なすべてのプロセスを記述します。 サーバーインフラストラクチャの整合性を長期にわたって大幅に改善できます。

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

シリーズのこの部分では、Rubyプログラミング言語を活用してインフラストラクチャの管理とプロビジョニングを自動化する強力な構成管理ツールであるChefを使用して、サーバープロビジョニングを自動化するプロセスを説明します。 Apacheを使用したUbuntu 18.04 Webサーバーの展開を完全に自動化するための簡単な例を作成するために必要な言語用語、構文、および機能に焦点を当てます。

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

  1. aptキャッシュを更新します

  2. Apacheをインストールする

  3. カスタムドキュメントルートディレクトリを作成する

  4. index.htmlファイルをカスタムドキュメントルートに配置します

  5. テンプレートを適用して、カスタム仮想ホストをセットアップします

  6. Apacheを再起動します

まず、シェフが使用する用語を見てから、レシピの作成に使用できる主な言語機能の概要を説明します。 このガイドの最後で、完全な例を共有するので、自分で試してみることができます。

[.note]#Note:このガイドは、Chef言語と、サーバープロビジョニングを自動化するためのレシピの作成方法を紹介することを目的としています。 このツールのインストールと開始に必要な手順を含む、Chefの概要については、Chef’s official documentation
#を参照してください。

入門

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

シェフ規約

  • Chef Server:情報を格納し、ノードのプロビジョニングを管理する中央サーバー

  • Chef Node:Chefサーバーによって管理される個々のサーバー

  • Chef Workstation:プロビジョニングが作成されてChefサーバーにアップロードされるコントローラーマシン

  • Recipe:実行される一連の命令(リソース)を含むファイル。 レシピはCookbook内に含まれている必要があります

  • Resource:システムの要素と実行するアクションを宣言するコードの一部。 たとえば、パッケージをインストールするには、アクションinstallpackageリソースを宣言します。

  • Cookbook:プロビジョニングの一部の共有と再利用を容易にするために、事前定義された方法で編成されたレシピとその他の関連ファイルのコレクション

  • Attributes:特定のノードに関する詳細。 属性は自動にすることができ(次の定義を参照)、レシピ内で定義することもできます

  • Automatic Attributes:ネットワークインターフェイスやオペレーティングシステムなど、システムに関する情報を含むグローバル変数(他のツールではfactsとして知られています)。 これらの自動属性は、Ohaiと呼ばれるツールによって収集されます

  • Services:サービスの再起動や停止など、サービスステータスの変更をトリガーするために使用されます

レシピ形式

シェフのレシピは、Rubyを使用して記述されています。 レシピは基本的に、ノードによって実行されるステップバイステップの命令セットを作成するリソース定義のコレクションです。 これらのリソース定義をRubyコードと組み合わせて、柔軟性とモジュール性を高めることができます。

以下に、apt-get updateを実行し、後でvimをインストールするレシピの簡単な例を示します。

execute "apt-get update" do
 command "apt-get update"
end

apt_package "vim" do
 action :install
end

レシピを書く

変数の使用

ローカル変数は、通常のRubyローカル変数としてレシピ内で定義できます。 以下の例は、後でリソース定義内で使用されるローカル変数を作成する方法を示しています。

package  = "vim"

apt_package package do
 action :install
end

ただし、これらの変数のスコープは限定されており、定義されたファイル内でのみ有効です。 変数を作成してグローバルに利用できるようにし、クックブックやレシピから使用できるようにする場合は、custom attributeを定義する必要があります。

属性を使用する

属性はノードに関する詳細を表します。 Chefには自動属性があります。これは、Ohaiというツールによって収集され、システムに関する情報(プラットフォーム、ホスト名、デフォルトIPアドレスなど)を含む属性ですが、独自のカスタム属性を定義することもできます。

属性には、作成する属性のタイプによって定義される異なる優先レベルがあります。 default属性は、必要に応じて他の属性タイプで上書きできるため、最も一般的な選択です。

次の例は、ローカル変数の代わりにdefaultノード属性を使用した前の例がどのように見えるかを示しています。

node.default['main']['package'] = "vim"

apt_package node['main']['package'] do
 action :install
end

この例には、次の2つの詳細事項があります。

ノード変数を定義する際の推奨される方法は、使用中の現在のクックブックをキーとして使用してハッシュとして編成することです。 この場合、同じ名前のクックブックがあるため、mainを使用しました。 これにより、類似した名前の属性を持つ可能性のある複数のクックブックを操作している場合の混乱を回避できます。
属性を定義するときにnode.defaultを使用しましたが、後でその値にアクセスするときにnodeを使用したことに注意してください。直接。 node.defaultの使用法は、タイプdefaultの属性を作成することを定義します。 この属性の値は、normal属性やoverride属性など、優先順位の高い別のタイプによって上書きされる可能性があります。

属性の優先順位は、最初は少しわかりにくいかもしれませんが、ある程度練習すれば慣れるでしょう。 動作を説明するために、次の例を検討してください。

node.normal['main']['package']  = "vim"

node.override['main']['package'] = "git"

node.default['main']['package'] = "curl"

apt_package node['main']['package'] do
 action :install
end

この場合、どのパッケージがインストールされるか知っていますか? gitを推測した場合は、正しく推測しました。 属性が定義された順序に関係なく、タイプoverrideの優先順位が高いほど、+node['main']['package'] be evaluated to+`gitになります。

ループを使用する

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

Chefは、レシピ内でループを作成するためのすべてのRubyループ構造をサポートしています。 簡単な使用法では、eachが一般的な選択です。

['vim', 'git', 'curl'].each do |package|
 apt_package package do
   action :install
 end
end

インライン配列を使用する代わりに、ループ内で使用するパラメーターを定義するための変数または属性を作成することもできます。 これにより、物事がより整理され、読みやすくなります。 以下に、ローカル変数を使用してインストールするパッケージを定義する同じ例:

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

packages.each do |package|
 apt_package package do
   action :install
 end
end

条件付きの使用

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

Chefは、レシピ内で条件ステートメントを作成するためのすべてのRuby条件をサポートしています。 さらに、すべてのリソースタイプは、タスクを実行するかどうかを決定する前に式を評価する2つの特別なプロパティif_onlynot_ifをサポートしています。

以下の例では、拡張機能php-pearをインストールする前に、phpの存在を確認します。 このシステムに現在インストールされているphp実行可能ファイルがあるかどうかを確認するために、コマンドwhichを使用します。 コマンドwhich phpがfalseを返した場合、このタスクは実行されません。

apt_package "php-pear" do
 action :install
 only_if "which php"
end

逆に、条件がtrueと評価されたときに常にexceptでコマンドを実行する場合は、代わりにnot_ifを使用します。 この例では、システムがCentOSでない限り、php5をインストールします。

apt_package "php5" do
 action :install
 not_if { node['platform'] == 'centos' }
end

特定の条件下で複数のタスクを実行する場合のより複雑な評価を実行するには、標準のRuby条件のいずれかを使用できます。 次の例では、システムがDebianor Ubuntuの場合にのみapt-get updateを実行します。

if node['platform'] == 'debian' || node['platform'] == 'ubuntu'
 execute "apt-get update" do
   command "apt-get update"
 end
end

属性node['platform']は、Chefからの自動属性です。 最後の例は、より複雑な条件付き構築を示すことだけでしたが、自動属性node['platform_family']を使用した単純なテストに置き換えることができ、DebianシステムとUbuntuシステムの両方で「debian」を返します。

テンプレートの使用

テンプレートは通常、構成ファイルをセットアップするために使用され、変数やその他の機能を使用して、これらのファイルをより汎用的で再利用可能にすることを目的としています。

Chefは、Embedded Ruby(ERB)テンプレートを使用します。これは、Puppetで使用されるのと同じ形式です。 条件、ループ、その他のRuby機能をサポートしています。

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


    ServerAdmin webmaster@localhost
    DocumentRoot <%= @doc_root %>

    >
        AllowOverride All
        Require all granted
    

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

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
end

Chefは、組織とモジュール性を強化するために、ローカルファイルを扱う際にいくつかの仮定を行います。 この場合、Chefは、このレシピが配置されているのと同じクックブックにあるはずのtemplatesフォルダー内のvhost.erbテンプレートファイルを探します。

これまで見てきた他の構成管理ツールとは異なり、Chefには変数のより厳密なスコープがあります。 つまり、templateリソースを定義するときに、テンプレート内で使用する予定の変数を明示的に指定する必要があります。 この例では、variablesメソッドを使用して、仮想ホストテンプレートで必要なdoc_root属性を渡しました。

サービスの定義とトリガー

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

Chefでは、通知する前にサービスリソースを宣言する必要があります。そうしないと、エラーが発生します。

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

service "apache2" do
  action [ :enable, :start ]
end

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

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

レシピ例

このガイドの概要で説明したように、Ubuntu 14.04システム内でのApache Webサーバーのインストールを自動化するマニフェストを見てみましょう。

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

以下に完全なレシピがあります。

node.default['main']['doc_root'] = "/vagrant/web"

execute "apt-get update" do
 command "apt-get update"
end

apt_package "apache2" do
 action :install
end

service "apache2" do
 action [ :enable, :start ]
end

directory node['main']['doc_root'] do
 owner 'www-data'
 group 'www-data'
 mode '0644'
 action :create
end

cookbook_file "#{node['main']['doc_root']}/index.html" do
 source 'index.html'
 owner 'www-data'
 group 'www-data'
 action :create
end

template "/etc/apache2/sites-available/000-default.conf" do
 source "vhost.erb"
 variables({ :doc_root => node['main']['doc_root'] })
 action :create
 notifies :restart, resources(:service => "apache2")
end

レシピの説明

ライン1

レシピは、attribute定義、node['main']['doc_root']で始まります。 ここでは単純なローカル変数を使用できますが、ほとんどのユースケースシナリオでは、レシピは含まれるレシピまたは他のファイルから使用されるグローバル変数を定義する必要があります。 これらの状況では、ローカル変数のスコープが制限されているため、ローカル変数の代わりに属性を作成する必要があります。

行3〜5

このexecuteリソースはapt-get updateを実行します。

7〜10行目

このapt_packageリソースは、パッケージapache2をインストールします。

12〜15行目

このserviceリソースは、サービスapache2を有効にして開始します。 後で、サービスの再起動のためにこのリソースに通知する必要があります。 サービスに通知しようとするリソースの前にサービス定義が来ることが重要です。そうしないと、エラーが発生します。

17〜22行目

このdirectoryリソースは、カスタム属性node['main']['doc_root']で定義された値を使用して、document rootとして機能するディレクトリを作成します。

24〜29行目

cookbook_fileリソースは、ローカルファイルをリモートサーバーにコピーするために使用されます。 このリソースは、index.htmlファイルをコピーし、前のタスクで作成したドキュメントルート内に配置します。

31〜36行目

最後に、このtemplateリソースは、Apache仮想ホストテンプレートを適用し、サービスapache2に再起動を通知します。

結論

Chefは、Ruby言語を活用してサーバーのプロビジョニングと展開を自動化する強力な構成管理ツールです。 標準言語機能を自由に使用して最大限の柔軟性を実現し、一部のリソースにカスタムDSLを提供することもできます。