Ansible はじめの一歩
~Part1 Playbookのつくりかた~

Ansible

こんにちは。伊藤忠テクノソリューションズの古川です。
前回はAnsibleの概要とインストールについて触れました。今回から、Ansibleの使い方のコツについて解説していきます。初めにAnsibleを利用する上で必須となる項目を基礎知識として解説し、次に実際に開発をする際に考慮すべき点について解説します。
本稿ではCentOS7を想定して記載しています。

 

押さえておくべき基礎知識

本記事ではAnsibleでインフラ構築のコードを書いていく際の重要な項目ごとに説明を記載します。まずはこれらの項目について理解するとAnsibleを使いこなす第一歩は踏み出せるかと思います。

 

Playbook

前回の記事では動作確認に ansible コマンドを利用しました。インタラクティブにモジュールを実行する場合はこのコマンドを利用しますが、Ansible を利用して構築の自動化を行う場合、Playbook と呼ばれる、実行したい操作群をまとめて定義したファイルを作成し、このPlaybookを呼び出すのが一般的な利用方法です。
Playbook は ansible-playbook コマンドにより呼び出して実行することができます。

また、Playbook作成後は以下のコマンドにより文法的なチェックを行うことができます。

Playbookは、YAML形式で記述します。Playbookの基本的な書き方は、冒頭で操作対象のホストと使用する環境変数を定義し、以降はタスクとして、実際に実行する処理モジュールについて記述します。

Ansibleではあらかじめさまざまなモジュールが用意してあり、リファレンスに従って、必要なパラメータを指定することでそのモジュールで定義されている処理を操作対象のホストで実行することができます。

以下に簡単なPlaybookのサンプルを記載します。

このサンプルではApache webサーバをインストールしてポートを8080に書き換えてから起動しています。

example.yml

name属性は実行する処理についてのラベルとなります。実行時のログに表示されるため、ログ確認時にどの処理のログか判別するための文字列ともなります。

hosts属性で対象となるホストもしくはグループ(後述)を指定します。

tasks属性以下で、実行するモジュールの定義を記載していきます。Ansible自体でも多数のモジュールが用意されていますし、新たなモジュールを開発して呼び出すことも出来ます。モジュールについては、Ansibleのドキュメントのリファレンスを参照して必要なパラメータを確認して記述することでそのモジュールの機能を実行します。

 

includeによる別ファイルの読み込み

さまざなま処理を一つのPlaybookに書いてしまうのは、ファイルが冗長となるだけでなく、同じ処理を行う場合の再利用性も低下してしまいます。Playbookでは、他のPlaybookファイルを呼び出して実行することができます。処理毎に別のファイルに分けることで再利用性を高めることができます。

以下に前述のサンプルをファイル分けした場合の例を記載します。ansible-playbookコマンド実行の際はexample.ymlを指定します。

httpd.yml

 example.yml

この例では、httpdのセットアップ部分を別ファイルであるhttpd.ymlで定義しています。また、includeで呼び出す際に変数を指定するようにすることで設定変更を簡単に行えるようになっています。

 

Ansible設定ファイル

前回の記事の動作確認の項目でも出てきましたが、Ansible設定ファイル(ansible.cfg)ではAnsibleの基本的な振る舞いを定義することができます。設定ファイルはansible関連のコマンド実行時に以下の優先順位で検索され、読み込まれます。

  1. 環境変数 ANSIBLE_CONFIG で定義された PATH
  2. カレントディレクトリの ansible.cfg
  3. ホームディレクトリの .ansible.cfg
  4. /etc/ansible/ansible.cfg (ansibleをインストールした時点でファイルが用意されます)

以下にAnsible設定ファイルで代表的な設定値について記載します。

 設定値  説明
 ask_pass ssh認証にパスワードをインタラクティブに入力するかどうか指定します。デフォルトではFalseです。
 ask_sudo_pass  ssh時のsudoでコマンドを実行する際にパスワードをインタラクティブに入力するかどうか指定します。デフォルトではFalseです。
 inventory  インベントリファイル(後述)のPATHを指定します。ここで指定しない場合、ansible-playbookコマンドで明示的に -i でインベントリファイルを指定する必要があります。
 log_path  ansible 実行時のログを格納するファイルのPATHを指定します。
 private_key_file  sshの際の公開鍵認証に使用するプライベートキーのPATHを指定します。
 remote_port  sshで使用するポートを指定します。デフォルトでは22です。
 remote_user  ansible-playbookコマンド実行の際にssh接続で使用するユーザです。なお、ansibleコマンドの場合は常にコマンド実行のカレントユーザになります。
 sudo_user  Playbookで明示的にsudoの際に使用するユーザが指定されない場合のユーザを指定します。デフォルトではrootです。
 timeout  ssh実行時のタイムアウトの時間(秒)です。

設定例を以下に示します。

ansible.cfg

 

変数

Ansibleでは変数を利用することができます。変数はPlaybook内で直接定義することも出来ますし、後述するインベントリファイル等に独立させて定義することも出来ます。
変数名で利用出来るのは半角アルファベット(大文字小文字)、数字、アンダースコア ( “_” )のみです。1文字目はアルファベットにする必要があります。 また、予約語については使用出来ません。詳細はこちらをご確認ください。

 

インベントリファイル

インベントリファイルにはホストをグループ単位で定義することが出来る設定ファイルです。これにより、Playbook内での処理の対象を絞り込むことができます。 また、そこで絞り込んだ対象について、個別に変数を定義することができます。インベントリーファイルにより、例えば開発環境のホスト群とステージング環境のホスト群と運用環境のホスト群で設定を変えて同じPlaybookで構築する、といったことができます。インベントリーファイルは通常 hostsという名前にすることが多いですが、任意のファイル名も指定可能です。

ansibleをインストールすると、サンプルとして /etc/ansible/hosts ファイルが用意されていますので参考にしてください。グループ分けをする場合、 [グループ名] のエントリーの次行以降でグループに所属するホストを記載します。ここで定義したグループ名を Playbook の hosts 属性に記載することで、グループに含まれるすべてのホストを対象にPlaybook記載のタスクを実行することができます。

設定例を以下に示します。

例の最後の行はワイルドカードの記述で、この例の場合はhost1~host9までの9つのホスト名として認識されます。また、*(アスタリスク)を使用すると任意の文字の扱いとなります。

hosts

また前述の通り、インベントリファイル内のホスト定義と同時に変数を設定することも出来ます。

設定例を以下に示します。

hosts

グループ全体で共通の変数を設定することも出来ます。

設定例を以下に示します。

hosts

なお、ここで説明した変数の設定は別の外部ファイルとして定義出来るのですが、それについてはディレクトリ構成についての説明の所で後述します。

 

冪等性

Ansibleは自動構成ツールとして、冪等性を担保出来るように設計されています。Ansibleを実行した際に、同じ環境と同じパラメータを使用した場合には、必ず同じ実行結果となることです。

例えば、あるソフトウェアをインストールする処理を実行する場合、初回実行時は新規インストールをします。再び同じ処理をそのまま実行しようとした場合、既にインストールされていますから、ここで二重インストールしないようにしたりします。

各モジュールは冪等性を前提に設計されていますので、Ansibleで標準で用意されたモジュールの処理の範囲では、冪等性は保障されます。しかしながら、独自でモジュールを開発する場合や、commandモジュール等からAnsible外のコマンドを実行する場合には、冪等性を考慮して実装するようにしてください。

 

ssh の公開鍵認証

Ansibleではsshによりリモートホストに接続して各種操作を行います。その際にあらかじめ対象ホストに対して公開鍵認証を設定しておくと、接続の際のパスワード入力を省略出来るため、Playbook実行時の自動化を実現できますので設定しておくことをお勧めします。

参考までに、以下に手順を解説しておきます。

1. キーペア作成

以下のコマンドによりキーペアが生成されます。既に作成済みの場合は流用できます。

2. 接続先に公開鍵を登録

以下のコマンドにより接続先に公開鍵が登録され、以降のsshにはパスワードが不要となります。

3. Ansible.cfgのask_passをFalseに設定

デフォルトでFalseになっていますが、もし明示的に設定をTrueに変更していた場合、パスワード入力が必要となってしまいますのでFalseに設定します。

 

Playbook 開発にあたって考慮すべき点

以降では、実際にPlaybookによる開発を行う上で注意する点を解説します。

 

1.ディレクトリ構成

Playbookの開発にあたって、特にファイル類についてディレクトリ構造の規定はないのですが、Ansibleのドキュメントにディレクトリ構成に関するベストプラクティスが記載されております。これをベースに、重要な部分に絞って説明していきます。

ポイントは2つあります。

ポイント1.  変数を環境別に分けて記載

インベントリファイルの説明のところでは、単一のインベントリファイル内で変数を定義していましたが、変数は外部ファイルに記載することが出来ます。変数を環境別に用意したり変更しやすくするため、外部ファイルに記載することお勧めします。

ベストプラクティスにおけるディレクトリ構造の group_vars ディレクトリ配下には、インベントリファイルで定義したグループ名のファイル名でファイルを作成し、変数定義を記述することで、該当グループの全ホストに対して変数を設定出来ます。group_vars ディレクトリ配下に all というファイル名でファイルを作成した場合、すべてのグループを対象に変数を設定出来ます。また、host_vars ディレクトリ配下のインベントリファイルで定義したホスト名をファイル名としてファイルを作成し、変数定義を記述することで、該当ホストに対して変数を設定出来ます。

同じ変数名を複数のファイルで定義した場合は、group_vars ディレクトリ配下のファイルより host_vars ディレクトリ配下のファイルの方が後から上書きされます。複数のグループに所属しているようなホストの場合は、インベントリファイルの上から順番に処理されるため、後に書かれている方で上書きされます。なお、これらの設定は、同一変数をPlaybook内で定義した場合、Playbookの設定が優先されるため、group_vars ディレクトリ配下等で変数を設定する場合は、Playbook側では変数は定義しないよう注意してください。

上記で説明した変数を定義の優先順位について以下にまとめます。リストの上にあるほど優先され、下にある箇所で定義された同一名の変数を上書きします。(ここで説明していない項目についてはリストから割愛しています。詳細はAnsibleのドキュメントを参照してください。)

 

  1. Playbook内で定義した host_vars グループ内の変数
  2. Playbook内で定義した group_vars グループ内の変数
  3. host_vars ディレクトリ配下の個別インベントリファイルで定義した変数
  4. group_vars ディレクトリ配下の個別インベントリファイルで定義した変数
  5. group_vars ディレクトリ配下の all ファイルで定義した変数
  6. インベントリファイル内で定義した変数
  7. roles/[ロール名]/defaults/ 配下のファイルで定義した変数

 

ポイント2.  Playbookをロールで分割

ロールによりPlaybookを処理単位のグループとして集約することが出来ます。また、ロール単位で変数やタスクやハンドラを定義出来ます。

Playbookから外部ファイルとしてPlaybookを読み込むinclude属性を解説していましたが、roles属性によりロール内のPlaybookや付随するvars、handlerなどが暗黙的に読み込むことが出来ます。

rolesでロール名を指定した場合、以下のルールでPlaybook実行時にファイルが読み込まれます。なお、以下の記述はrolesを指定したPlaybookからの相対PATHとなります。

  1. [ロール名]/defaults/main.yml が読み込まれます。ここではロール内で使用する変数を定義します。
  2. [ロール名]/vars/main.yml が読み込まれます。ここでもロール内で使用する変数を定義します。defaults配下より優先されるので、たとえば特定の条件で変数を上書きするなどに使用します。
  3. [ロール名]/handlers/main.yml が読み込まれます。ここではロール内で使用するハンドラを定義します。
  4. [ロール名]/tasks/main.yml が読み込まれます。ここでロール内で実行する処理を記述します。

これ以外にmeta、templates、filesがありますが本記事では説明は割愛します。

上記各ディレクトリおよびファイルは、必要なものだけ用意します。存在しないものに関しては単に無視されるので特に問題ありません。

ロールを使うことで、処理を再利用可能な単位でまとめることができます。また、条件分岐でそれぞれ異なる条件を付与したロールの実行したりできます。

2.インベントリファイルのグループ分けの基準

先の説明の通り、イベントリファイルでは作業対象のホストをグループ化出来るわけですが、どのように分類すべきかについて指針を説明します。

1.機能的な分類

例えば典型的なWebのシステムでは、Web層、App層、DB層という3層構造で構成されたりしますが、こういった機能単位でグループ分けをする方法があります。多くのシステムでは、各層HA構成のために複数のホストを並列で稼働させるため、同じ機能グループ内の設定は同じ場合が多いです。

2.物理的な場所による分類

最近では災害に備えたDR構成として遠隔地の拠点間のホストを合わせてシステム構成するような場合があります。片系が正常運用に使用し、もう方系を障害時のバックアップとして用意してスタンバイしておくなどです。この場合、設定を分けるケースが多いので拠点単位で設定した方が効率的です。

 

以上、今回の記事ではPlaybookを作成するために特に押さえておいて欲しい点について解説しました。

これをベースに、次回以降で具体的なPlaybook作成の方法や良く使われるモジュールの解説する予定です。

 

参考リンク

 

著者

古川雅弘:過去にはJavaの開発からミドルウェア製品やサーバ製品の製品技術主管を担当し、2015年4月からクラウドイノベーションセンターでOpenStackに関連する構築運用等の技術担当に。ゲーム好き。

Pocket

コメント

「DevOps」のイベント・セミナー

開催
DevOps時代のテクノロジー