Ansible blockinfile モジュール

Ansible Logo

このごろは Python で書かれた構成管理ツールの Ansible を使ってみています。

試行錯誤の末にようやく運用構成がかたまり、 また自作のモジュールを書くなどしてみたので、紹介します。

Why Ansible?

そもそも Ruby 好きを自認するのであれば構成管理ツールには ChefPuppet を使うのが普通の流れでしょうが、 これらはエージェント実行のために必要なリソースが大きいのが難点で、 これまで試す気が起きなかったのでした。 例えば 普通に Chef クライアントをインストール すると /opt/chef に Ruby の環境一式が放り込まれて 150MB 近くのストレージを消費します。 また基本的にエージェントプロセスが動きっぱなしになるため、 OpenVZ や LXC を使って大量の軽量コンテナを稼働させたときの 総リソース消費量がばかになりません。

それに対して Ansible はエージェントレスな構成が特徴で、 管理対象ホストには Python がインストールされていればよいため、 システム全体を単純・軽量に済ませられます。 加えて github.com 上での開発 が非常に活発であること、 Ansible Galaxy というロールの公開と利用を簡単に行う仕組みがあることが気に入りました。

Ansible の運用を始めるには、通常は Best Practices に従ったファイル階層を作って Git などでバージョン管理していくのですが、 実際にやってみると、ホストのグループ構成であるとか、 ホストのアクセス・認証・権限付与手段 (通常は一般ユーザで SSH でログインした後 sudo することになります)、 平文でリポジトリに格納したくない認証情報の管理手段 (ansible-vault という暗号化機能が使えますが、その暗号鍵をどう共有するかという問題は残ります) など、自分で考えなければならない事項が数多くあることがわかります。 単純なだけに、納得のいく運用構成にたどりつくまでに結構時間をとられました。

運用構成の確立後は、これまでほぼ手作業だった様々なホスト設定を Ansible のプレイブックで記述するのをぼちぼちと進めています。 やはり単純なシェルスクリプトとは違って独特の癖や注意点があり、 動作検証なども含めると結構手間がかかるのですが、 まあでも楽しみながらやっています。

blockinfile モジュール

Unix ホストの構成管理では /etc の設定ファイルを頻繁に編集する必要があり、この目的のために Ansible モジュールの Files カテゴリ には様々なファイル編集モジュールが用意されています。 しかしながら、一行だけの編集ならよいのですが複数行にわたる編集については 標準のモジュールだけでは簡単にできないことがわかってきたので、 blockinfile という名前のモジュールおよびロールを自作してみました。

blockinfile ロールは Ansible Galaxy でも yaegashi.blockinfile として公開していますので、次のコマンドでインストールできます。

$ ansible-galaxy install yaegashi.blockinfile

blockinfile ロールは blockinfile モジュールを追加するだけのロールです。 ロールを呼び出した後にタスクやプレイブックでモジュールを使うことができます。

たとえば SSH サーバの設定ファイル /etc/ssh/sshd_config を対象に次のようなプレイブックを記述すると、

---
- hosts: all
  remote_user: ansible-agent
  sudo: yes
  roles:
    - yaegashi.blockinfile
  tasks:
    - name: Prohibit SSH password authentication for $SUDO_USER
      blockinfile: |
        dest=/etc/ssh/sshd_config backup=yes
        content='Match User {{ansible_env.SUDO_USER}}\nPasswordAuthentication no'
      notify: Restart sshd
  handlers:
    - name: Restart sshd
      service: name=ssh state=restarted

設定ファイル内で次のようなテキストブロックを追加・更新・削除し、 設定ファイルの内容に変更があった場合のみ SSH サーバを再起動します。

# BEGIN ANSIBLE MANAGED BLOCK
Match User ansible-agent
PasswordAuthentication no
# END ANSIBLE MANAGED BLOCK

テキストブロックを # BEGIN/END ANSIBLE MANAGED BLOCK という明確なマーカーコメント行で囲むことで Ansible で管理したい設定行の更新や削除を正確に行い、 冪等性を維持して無駄なデーモンの再起動を抑えることができます。

単純なことのように思えますが、標準モジュールの replacelineinfile だけでこれを実現するのは非常に面倒で、 これまで多くの質問がメーリングリストや Stack Overflow に出ていました (replace モジュールだけで頑張った例 – blockinfile モジュールはちょうどこれを簡単にやるためのものです)。 あきらめて sed などを使う人も多いようです。

ということで Ansible をお使いの方は blockinfile モジュールを是非使ってみてください。 すでに改良のネタがいくつか出ているので、今後も継続して更新する予定です。 最終的には Ansible の標準モジュールにできればといいなあとも思っています。

2014/08/24 18:07:39 JST