導入しやすく軽量な構成管理ツール「Itamae」を使ってみよう

サーバーの管理や設定を自動化する構成管理ツールが広く普及しつつあるが、その代表ともいえる「Chef」は高機能である一方、その設定や管理方法を学ぶハードルが高いという問題があった。その欠点を解決すべく開発されたツールが「Itamae」だ。今回はこのItamaeの導入手順と基本的な利用法を紹介する。

設定コストをなるべくかけずに利用できる構成管理ツール

サービスの運用において、1つもしくは少数の高性能なサーバーではなく、コストパフォーマンスの良いサーバーを多数用意して組み合わせるという手法がここ10年来のトレンドだ。しかしこういった構成を取る場合、OSやアプリケーションをサーバーにインストールし、適切に設定するコストが増えるというデメリットがある。そのため、近年ではサーバーの構成管理を自動化するツールが注目されている。

このようなツールの代表が「Chef」や「Ansible」だ。これらは『サーバー設定ツール「Chef」の概要と基礎的な使い方』や『エージェントレスでシンプルな構成管理ツール「Ansible」入門』といった記事で以前紹介しているが、Chefは非常に多機能である一方で設定ファイルの記述や管理が複雑になりやすい。また、Ansibleはシンプルだが複雑な処理を行わせようとすると面倒など、それぞれ一長一短がある。

今回紹介する「Itamae」は、こういった背景から生まれた構成管理ツールだ。Itamaeはクックパッド社員の荒井良太氏が開発し、クックパッドの運用環境で実際に使われているという。

図1 ItamaeのWebサイト

Itamaeの特徴

Itamaeの特徴についてはクックパッド開発者ブログで開発者本人が紹介しているが、機能がシンプルで学習コストが低い点やサイズがコンパクトで導入しやすい点、管理対象サーバーに専用のソフトウェアをインストールする必要が無い点などが特徴だ。

表1 構成管理ツール比較
ツール名 Itamae Chef Puppet Ansible
実装言語 Ruby Ruby、Erlang Ruby Python
設定ファイルの形式 独自(Rubyを使ったDSL) 独自(Rubyを使ったDSL) 独自(Rubyを使ったDSL) YAML
主なインストール手法 gem rpm/deb(専用パッケージを提供) yum/apt-get(専用リポジトリを提供) pip
モジュール等による機能拡張
モジュール等を提供する独自リポジトリ なし(gemを利用) あり あり なし
ローカル環境の構成管理
リモート環境の構成管理方法 SSH経由およびリモートにインストールされたItamae経由 エージェントを利用 エージェントを利用 SSH経由
専用サーバーによる管理支援機能 なし あり あり 商用サービス(Ansible Tower)として提供

ItamaeはChefとほぼ同じフォーマットのDSL(ドメイン固有言語)を採用して設定を記述できるのが特徴で、Chefの知識があれば容易に導入できる。このDSLはRubyコードとして実行されるため、Rubyの知識があれば拡張も容易である。ただし、標準でサポートされる管理対象リソースはChefと比べて少なく、一部パラメータ等も異なるため、Chef向けに作成した記述をそのままItamaeで利用することはできない。

管理対象サーバーに専用のソフトウェアをインストールする必要が無い点も特徴だ。SSHでのリモートログインおよびsudoによる管理者権限の取得が可能であれば、それだけでサーバーの設定処理を実行できる。また、管理対象サーバーにもItamaeをインストールすることで、処理の際のレイテンシを少なくすることも可能だ。

Itamaeでは専用サーバーを用いた複数サーバーの集中管理機能は省かれている。ただし、サーバーによって柔軟に処理内容を変更することは可能なので、別のツールと組み合わせることで多数のサーバーがある環境でも十分に対応できる。また、設定ファイルやプラグインを提供する独自リポジトリはないが、その代わりそれらをRubyのパッケージ管理システムであるRubyGemsを使って管理できるようになっている。Itamae自体もRubyGems経由でインストールが可能だ。提供される機能が絞られているためパッケージのファイルサイズも小さく、インストールが簡単に行える点もメリットだ。

後発のツールということでドキュメントが少なかったり、やデフォルトで利用できるリソース機能が限られているという短所はあるが、元々機能がシンプルであり、また構成管理に必要な処理のほとんどは現時点でも十分カバーされている。そのため、実用上で大きな問題になることはないだろう。

Itamaeを利用する基本的な流れ

それでは、実際にItamaeを利用する流れを説明していこう。なお、Itamaeはrubyで実装されているため、事前にRubyおよびRubyGemsをインストールしておく必要がある。

Itamaeのインストール

RubyGemsが利用できる環境であれば、次のようにgemコマンドでitamaeをインストールできる。

# gem install itamae

このようにルート権限でインストールを行った場合、/use/local/bin/ディレクトリ以下にitamaeコマンドがインストールされる。/usr/local/binディレクトリにPATH環境変数にこのディレクトリが設定されているかどうかを確認しておこう。

なお、gemコマンドでは一般権限でのインストールも可能だが、その場合実行したユーザーの~/bin/ディレクトリ以下にitamaeコマンドがインストールされる。

itamaeコマンドを引数無しで実行すると、次のように利用できるサブコマンド一覧が表示される。

$ itamae
Commands:
  itamae destroy [cookbook|role] [NAME]   # Undo role or cookbook (short-cut alias: "d")
  itamae docker RECIPE [RECIPE...]        # Create Docker image
  itamae generate [cookbook|role] [NAME]  # Initialize role or cookbook (short-cut alias: "g")
  itamae help [COMMAND]                   # Describe available commands or one specific command
  itamae init NAME                        # Create a new project
  itamae local RECIPE [RECIPE...]         # Run Itamae locally
  itamae ssh RECIPE [RECIPE...]           # Run Itamae via ssh
  itamae version                          # Print version

Options:
  -l, [--log-level=LOG_LEVEL]
                               # Default: info
      [--color], [--no-color]
                               # Default: true
  -c, [--config=CONFIG]

また、「itamae help <サブコマンド>」のように実行することで、サブコマンド毎のヘルプを確認できる。

「レシピ」を作成する

ItamaeはChefと同様、レシピ(recipe)と呼ばれるファイルに設定内容を記述していく。このファイルはRubyコードとして実行され、拡張子は「.rb」だ。Chefと同様、レシピでは基本的に以下のようなルールに従って設定内容を記述していく。

<リソースタイプ> <リソース名> do
  <属性> <その値>
 :
 :
  action <リソースに対し実行するアクション>
end

ただし、ItamaeではChefで利用できるリソースのうち主要なものしか実装されていない。利用できるリソース一覧はItamaeのWikiページにまとめられているが、現状デフォルトで扱えるリソースは表2のものだけだ。また、各リソースに対し指定できる属性(Attribute)も一部異なっている。

表2 Itamaeがデフォルトで扱えるリソース
リソース名 実行できる操作
directory ディレクトリの作成/削除
execute 指定したコマンドの実行
file ファイルの作成/削除/編集
gem_package gemパッケージのインストール/アップグレード
git gitリポジトリの作成/同期
group グループの作成
http_request 指定したURLにHTTPリクエストを送信する
link シンボリックリンクの作成
local_ruby_block 指定したRubyコードを実行する
package パッケージのインストール/削除
remote_directory ディレクトリのコピー
remote_file ファイルのコピー
service サービスの開始/停止/再起動/リロード/無効化
template テンプレートを使ったファイルの作成/削除/編集
user ユーザーの作成

たとえば次のレシピは、「taro」というユーザーおよびグループを作成するものだ。

group "taro" do
  gid 1000
  action :create
end

user "taro" do
  home "/home/taro"
  password '$6$OmC3KootOURrqOaP$63rwQ2bSE8op8wXa.ZWzgxm/iGvePTzEL5lOntmkPyYh5Qwh4lWs2DtyoEHcvsbYV5Q6a2ezzrZueb2ydrkhz0'
  shell "/bin/bash"
  uid 1000
  gid "taro"
  create_home true
  action :create
end

これは、サーバー設定ツール「Chef」の概要と基礎的な使い方記事内の「ユーザーの管理を行うRecipeを作成する」で紹介したレシピファイルとほぼ同じものになっている。Chefの場合と唯一異なるのが、chef用のレシピでは「supports :manage_home => true」となっていた部分が「create_home true」に変更されている点だ。

また、「password」属性にはSHA512でハッシュされたパスワードを指定する。Chefの記事ではgrub-cryptコマンドを利用していたが、CentOS 7などではこのコマンドが利用できないので、代わりに以下のような簡単なPerlワンライナーを利用すれば良いだろう。

# perl -e 'print crypt("<指定したいパスワード>", "\$6\$<適当なソルト文字列>"), "\n";'
$6$<適当なソルト文字列>$gGNbMWB0id6Xmu25gu/0y25Lr1jJnkynHSj8wGa2M8dSVF5OXLTaq36jQxr7PkbINubSLWscre48D6EV0Gp9L0
↑ハッシュ処理されたパスワードが表示される

ここで「適当なソルト文字列」には、適当に選んだ8文字のランダムな文字列を指定する。

このレシピファイルをrecipe.rbというファイルに保存し、次のように「local」サブコマンドを使って実行するとローカルのマシンにこの設定が反映され、「taro」というユーザーおよびグループが作成される。

# itamae local recipe.rb
 INFO : Starting Itamae...
 INFO : Recipe: /home/hylom/recipe.rb
 INFO :   user[taro] exist will change from 'false' to 'true'

なお、以下のように「--dry-run」オプションを指定すると、実際に処理を行うことなしに実行される処理が確認できる。テストの際などに利用すると良いだろう。

# itamae local --dry-run recipe.rb

リモートサーバーに対し実行する

Itamaeでは対象のサーバーにSSHでリモートログインし、設定管理を行う機能が標準で用意されている。この機能は「ssh」サブコマンドで実行できる。このとき、対象とするホストは「-h」オプションで指定する。たとえば「example.com」というホストに対して設定管理を実行する場合、次のようになる。

$ itamae ssh -h example.com recipe.rb
 INFO : Starting Itamae...
Enter passphrase for /home/hylom/.ssh/id_rsa: 
sudo password:
  
  処理が実行される
  

なお、Itamaeではroot権限が必要な処理を実行するためにsudoコマンドを使ってroot権限を得る仕組みになっており、SSHでのログイン後にユーザーのパスワードの入力が要求される。もちろん、sudoが利用できないユーザーの場合は処理の実行に失敗する。

対象のサーバーごとに異なる設定を行う

Chefでは「Data Bag」などの機能を利用することで、対象とするホストやその設定に応じて異なるパラメータをレシピに与えることができた。Itamaeの場合、Data Bagのようにデータを一元管理する機能は用意されていないが、代わりに実行時にJSONファイルもしくはYAMLファイルでレシピにパラメータを与えることが可能だ。これは、itamaeコマンドの「-j」(「--node-json」)もしくは「y」(「--node-yaml」)オプションで実現できる。

itamaeコマンドでは、「-j」オプションに続けてJSONファイル、もしくは「-y」オプションに続けてYAMLファイルを指定すると、指定したファイル内で定義された値をレシピ内から「node」変数経由で参照できるようになる。

次の例は、作成するユーザーおよびグループをYAMLファイルに記述し、それに応じてユーザーやグループを作成するものだ。まず、YAMLファイルは次のようになる。

groups:
  - name: taro
    gid: 1000
users:
  - name: taro
    uid: 1000
    gid: taro
    home: /home/taro
    password: $6$OmC3KootOURrqOaP$63rwQ2bSE8op8wXa.ZWzgxm/iGvePTzEL5lOntmkPyYh5Qwh4lWs2DtyoEHcvsbYV5Q6a2ezzrZueb2ydrkhz0
    shell: /bin/bash

この設定を利用するレシピファイルは次のようになる。ここで、「node['groups']」部分はYAMLファイル内の「groups」配列に、「node['users']」部分はYAMLファイル内の「users」配列を参照するものになる。

node['groups'].each do |g|
  group g['name'] do
    gid g['gid']
    action :create
  end
end

node['users'].each do |u|
  user u['name'] do
    home u['home']
    password u['password']
    shell u['shell']
    uid u['uid']
    gid u['gid']
    create_home true
    action :create
  end
end

これを実行すると、次のようになる。

$ itamae ssh  -h example.com -y node.yaml test2.rb
 INFO : Starting Itamae...
 INFO : Loading node data from /home/hylom/tmp/node.yaml...
Enter passphrase for /home/hylom/.ssh/id_rsa:
sudo password:
 INFO : Recipe: /home/hylom/tmp/test2.rb
 INFO :   user[taro] exist will change from 'false' to 'true'

このようにレシピに与えるパラメータを別ファイルに分離することで、サーバーによって異なる処理を行わせることが可能になる。たとえば「taro」ではなく「john」というユーザーを作成するには、node.yaml内の「taro」という部分を「john」に置き換えれば良い。さらに、groups配列やusers配列にアイテムを追加することで、複数のグループやユーザーを作成することも可能になる。

ホストの情報を取得する

レシピ内では、node変数を使ってホストの情報を取得することも可能だ。これは「Host Inventory」を利用して実装されている。たとえば、ホスト名は次のように参照できる。

node['hostname']

取得できる情報はHost Inventoryのページにまとめられているが、プラットフォームやそのバージョン、FQDNといった情報も取得可能だ。

プラグインの利用

Itamaeではプラグインやレシピを管理する独自手法は用意されていないが、その代わりRubyのパッケージマネージャであるRubyGemsを利用してプラグインやレシピのインストールを行えるようになっている。RubyGemsではパッケージの依存関係を定義したり、それに応じて自動的に必要なパッケージをインストールする機能があり、これらを利用することでレシピやプラグインの管理が容易になる。

レシピプラグインの利用

Itamaeのレシピは、gem上では「itamae-plugin-recipe-<レシピ名>」という名前で登録するルールになっている。「itamae-plugin-recipe-」というキーワードで検索を行うと、公開されているレシピプラグイン一覧を得ることができる。

$ gem search itamae-plugin-recipe-

*** REMOTE GEMS ***

itamae-plugin-recipe-anyenv (0.3.0)
itamae-plugin-recipe-atom (0.0.1)
itamae-plugin-recipe-docker (0.2.0)
itamae-plugin-recipe-etcd (0.1.0)
itamae-plugin-recipe-git_now (0.1.0)
itamae-plugin-recipe-homebrew (0.0.3)
itamae-plugin-recipe-idcf-backup_to_object_storage (0.1.6)
itamae-plugin-recipe-kzyty_mysql (0.1.0)
itamae-plugin-recipe-kzyty_redis (0.1.1)
itamae-plugin-recipe-minecraft (0.0.5)
itamae-plugin-recipe-nginx_build (0.1.2)
itamae-plugin-recipe-nm_chruby (0.1.0)
itamae-plugin-recipe-nodebrew (0.1.1)
itamae-plugin-recipe-openresty (0.0.1)
itamae-plugin-recipe-openssh (0.1.0)
itamae-plugin-recipe-oracle_jdk (0.0.2)
itamae-plugin-recipe-phantomjs (0.0.1)
itamae-plugin-recipe-plenv (0.1.0)
itamae-plugin-recipe-pyenv (0.1.0)
itamae-plugin-recipe-raspberry_pi (0.1.1)
itamae-plugin-recipe-rbenv (0.6.1)
itamae-plugin-recipe-ros (0.2.2)
itamae-plugin-recipe-rtn_git (0.1.4)
itamae-plugin-recipe-rtn_php_nabe (0.0.1)
itamae-plugin-recipe-rtn_rbenv (0.1.4)
itamae-plugin-recipe-rvm (1.0.1)
itamae-plugin-recipe-selinux (0.0.5)
itamae-plugin-recipe-tig (0.1.0)
itamae-plugin-recipe-unicorn (0.1.0)
itamae-plugin-recipe-zabbix (0.1.1)

たとえばOpenSSHに関する設定を行える「openssh」レシピを利用したい場合、次のようにして対応するgemをインストールすれば良い。

$ gem install itamae-plugin-recipe-openssh

インストールしたレシピは、ほかのレシピから「include_recipe」コマンドで読み込むことが可能だ。たとえば先のopensshレシピを利用するには、レシピ内に次のように記述すれば良い。

include_recipe 'openssh'

なお、このレシピは「node['openssh']」というプロパティで動作を制御するようになっている。指定可能な値はgemに含まれている「attribute.rb」に記載されているが、「node['openssh']['server'][<プロパティ名>]」というプロパティに設定された値がsshdの設定ファイルである/etc/ssh/sshd_configファイルに、「node['openssh']['client'][<プロパティ名>]」というプロパティに設定された値がsshクライアントの設定ファイルである/etc/ssh/ssh_configファイルに出力される仕組みになっている。

たとえば/etc/ssh/sshd_configの「permit_root_login」設定値を「no」に設定するには、次のようなレシピを用意すれば良い。

node['openssh'] ||= {}
node['openssh']['server'] ||= {}
node['openssh']['server']['permit_root_login'] = 'no'

include_recipe 'openssh'

このレシピを実行すると、/etc/ssh/sshd_configファイルが以下のように書き換えられ、sshdが再起動される。

# This file was generated by Itamae for itamae-test

PermitRootLogin no
Port 22
ChallengeResponseAuthentication no
UsePAM yes

なお、記事執筆時点ではこのレシピにはsshdのサービス名が「ssh」にハードコードされているという不具合があり、そのままではRed Hat Enterprise Linuxやその互換環境では実行できなかった。

リソースプラグインの導入

リソースプラグインは、Itamaeで扱えるリソースを拡張するためのプラグインだ。こちらは「itamae-plugin-resource-<リソース名>」というgem名が付与されており、次のようにして検索できる。

$ gem search itamae-plugin-resource-

*** REMOTE GEMS ***

itamae-plugin-resource-authorized_keys (0.1.0)
itamae-plugin-resource-aws (0.0.1)
itamae-plugin-resource-brew_tap (0.1.0)
itamae-plugin-resource-cask (0.2.2)
itamae-plugin-resource-daemontools_service (0.0.2)
itamae-plugin-resource-encrypted_remote_file (0.0.2)
itamae-plugin-resource-firewalld (0.1.1)
itamae-plugin-resource-ghq (0.0.1)
itamae-plugin-resource-iptables (0.0.2)
itamae-plugin-resource-mail_alias (0.0.4)
itamae-plugin-resource-mysql_query (0.0.1)
itamae-plugin-resource-pip (0.1.0)
itamae-plugin-resource-ros (0.1.0)
itamae-plugin-resource-security_context (0.1.0)

たとえばSSH公開鍵を設定するためのauthorized_keysを提供するプラグインである「authorized_keys」プラグインを導入する場合、次のようになる。

$ gem install itamae-plugin-resource-authorized_keys

インストールされたリソースプラグインは、特に設定しなくても自動的にレシピで利用が可能になる。このauthorized_keysリソースを使って、「taro」というユーザーのauthorized_keysファイルを設定するレシピは次のようになる。

user "taro"
authorized_keys "taro" do
  content "<登録するSSH公開鍵をここに記述する>"
end

このレシピを実行すると、「content」で指定した値が指定したユーザーの.ssh/authorized_keysファイルに書き込まれる。

用途や構成に併せた選択を

本記事では割愛しているが、ItamaeではChefと同様にRuby標準のテンプレートライブラリであるERB形式のテンプレートファイルを使って設定ファイル等を生成したり、任意のコマンドを実行する機能なども用意されている。また、Chefと同様の書式で新たなリソースを定義することも可能だ。ItamaeはChefと完全に互換性があるわけではないが、Chefに慣れていれば簡単にItamaeへの移行は行えるだろう。

ただ、Chefと同様、ItamaeのレシピやプラグインはRuby言語の仕様に依存しているため、使いこなすにはRubyについての知識が必要な点はややハードルが高いかもしれない。それらも踏まえて、ChefやAnsible、Puppetなど、ほかの構成管理ツールと比較してどれを利用するかを検討することをおすすめする。