エージェントレスでシンプルな構成管理ツール「Ansible」入門

近年、ChefやPuppetなどの構成管理ツールが人気だが、新たに注目されつつある構成管理ツールとして「Ansible」がある。Ansibleは設定ファイルがシンプルで、管理対象サーバーに特別なソフトウェアをインストールすることなく利用できるなど、最小限の手間で各種設定を自動化できるのが特徴だ。今回はこのAnsibleについてその基本的な使い方を紹介する。

小規模な環境でも手軽に使えるAnsible

あらかじめ用意しておいた設定ファイルに従って、ソフトウェアのインストールや設定ファイルの修正、サービスの起動/停止、ネットワーク設定といったサーバーの各種設定を自動的に実行するソフトウェアを構成管理ツールと呼ぶ。代表的なものとしては、さくらのナレッジでも過去に取り上げているChefやPuppetがある。

関連記事:

今回取り上げるAnsibleもChefやPuppetと同様、設定ファイルを元にサーバーの各種設定を自動実行するツールだ。

図1 AnsibleのWebサイト
図1 AnsibleのWebサイト

AnsibleもChefもPuppetも基本的な機能については大きな違いはないが、Ansibleの特徴としては以下のようなものが挙げられる。

・管理対象のサーバーに特別なソフトウェア(エージェント)をインストールすることなしに利用できる

ChefやPuppetは、管理対象のサーバーに「エージェント」などと呼ばれる専用のソフトウェアをインストールしておく必要がある。いっぽうAnsibleでは、SSHによるリモートログインを行って各種操作を実行する。このとき管理対象マシンに必要なソフトウェアはPython 2.4以上のみだ。SSHサーバーやPythonは多くのLinuxディストリビューションで標準で含まれているため、特に追加の設定をせずにすぐに用意したサーバーの設定を行える。

・YAML形式の設定ファイルを利用する

ChefやPuppetでは、実行する処理を記述した設定ファイルはそれぞれ独自のフォーマットとなっていた。これら設定ファイルの文法はRubyの構文に従っているため、Rubyに慣れていれば分かりやすいが、Rubyの知識のないユーザーにとっては困惑する点もある。Ansibleでは、YAML形式というシンプルなフォーマットで設定ファイルを記述できる。

・設定ファイルを用意せずとも、コマンドラインで対話的に処理を実行できる

Ansibleのコマンドラインツール(ansibleコマンド)では、あらかじめ用意した設定ファイルに従って処理を実行するだけでなく、コマンドラインの引数で処理を指定して実行できる。設定ファイルを用意せずとも、簡単に指定した複数のサーバーで特定の処理を実行させることが可能だ。

・コンパクトでインストールが容易

AnsibleではRed Hat Enterprise LinuxおよびCentOSなどのその互換環境、Debian、Ubuntu、FreeBSD、Mac OS Xといった環境向けのパッケージが提供されており、容易にインストールが可能だ。パッケージのサイズも比較的コンパクトである。また、AnsibleはPythonで実装されているため、Python向けのパッケージマネージャであるpip経由でもインストールできる。もちろん、ソースコードもGitHubで公開されている。

なお、Ansibleの管理コマンドの実行にはPython 2.6以降が必要だ。最近のLinuxディストリビューションの多くでPython 2.6が標準で含まれているが、もし古めのLinuxディストリビューションで利用する場合は注意したい。

そのほか、モジュール構造になっている点はChefやPuppetと同様だ。一般的に使われる「コアモジュール」はAnsibleにデフォルトで含まれており、さらに特定の用途に特化したモジュールが「Extra」モジュールとしてAnsibleによって管理されている。もちろん、サードパーティ製のモジュールを利用したり、独自にモジュールを作成することもできる。利用できるモジュール一覧はAnsibleのModule Indexページで確認可能だ。

さらに、Webベースでの管理ツールである「Ansible Tower」というツールも提供されている。こちらはAnsibleを開発しているAnsible社が提供している有償サービスとなる。Ansible社はほかにもAnsibleに関する有償サポートサービスなども提供している。

Ansibleのインストール

それでは、実際にAnsibleを使って構成管理を行う流れを紹介しよう。なお、AnsibleはWindowsホストの管理にも利用できるが、今回はLinuxのみを管理対象として使用することにする。

まずAnsibleのインストールだが、前述したとおり各種管理作業に使用するマシンに公開されているパッケージをインストールするだけで完了する。ただし、このマシンからは管理対象のサーバーに対し直接SSHなどでリモートログインできる必要がある。

Red Hat Enterprise Linuxおよびその互換環境でのインストール

Red Hat Enterprise Linux(RHEL)やCentOSなどその互換環境では、Fedoraプロジェクトが提供しているEPEL(Extra Packages for Enterprise Linux)リポジトリからAnsibleのRPMパッケージをインストールできる。EPELを利用するには、FedoraプロジェクトのEPELページから利用しているRHELもしくはCentOSなどのバージョンに対応した「epel-release」パッケージをダウンロードしてインストールすれば良い。

たとえばCentOS 7の場合、次のようにしてepel-release-7-5.noarchパッケージをインストールできる。

# rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/7/x86_64/e/epel-release-7-5.noarch.rpm

epel-releaseパッケージをインストールすると、EPELのリポジトリが利用可能になり、次のようにyumコマンドでansibleをインストールできるようになる。

# yum install ansible

Debianでのインストール

Debian 7.0(wheezy)では、Debian BackportsにてAnsibleのパッケージが提供されている。apt-getで利用するリポジトリ情報を格納する「/etc/apt/sources.list」に下記の内容を追加することでwheezy向けのBackportsリポジトリが利用可能になる。

deb http://ftp.jp.debian.org/debian wheezy-backports main contrib non-free

Ansibleをインストールするには、Backportsリポジトリが利用可能な状態で次のように実行すれば良い。

# apt-get update
# apt-get install ansible

そのほかの環境でのインストール

Ansibleドキュメントの「Installation」ページでは、そのほかUbuntuやFreeBSD、Mac OS Xでのインストールやpip経由でのインストール方法などが解説されている。これら環境での利用についてはこちらのページを参照して欲しい。

管理対象マシンの登録

Ansibleでは、「/etc/ansible」ディレクトリ以下に設定ファイルが格納されている。このディレクトリ内でまず編集する必要があるのが、管理対象とするサーバーを記述する「hosts」ファイルだ。Ansibleのインストール時には設定サンプルが記述されたhostsファイルが自動的に作成されるので、ざっと中身を確認しておくと良い。

サンプルを見ると概要は掴めると思うが、このファイルでは管理対象ホストをそのIPアドレスやホスト名を記述することで指定する。また、「[<グループ名>]」という形でグループを宣言することもできる。

たとえば、「192.168.2.1」および「192.168.2.10」、「192.168.2.11」という3つのホストがあり、「192.168.2.10」、「192.168.2.11」についてはWebサーバーとして使われている環境を考えよう(図2)。

図2 管理対象ホストの例
図2 管理対象ホストの例

この場合、/etc/ansible/hostsファイルには次のように記述すれば良い。この場合、192.168.2.1というホストはグループに所属せず、「192.168.0.10」と「192.168.0.11」というホストは「webservers」というグループに所属することになる。

192.168.2.1

[webservers]
192.168.2.10
192.168.2.11

そのほか、「<数字>:<数字>」という形でIPアドレスやホスト名の範囲を指定することも可能だ。たとえば次のように記述することで、「test00.example.com」から「test09.example.com」まで10個のホストを指定できる。

test[00:09].example.com

また、「#」から行末まではコメントとなる。必要に応じてデフォルトの設定サンプル内容を削除し、管理するサーバーに応じた内容のものに書き換えておこう。

なお、このhostsファイルで登録した管理対象のホストは「Inventory」(インベントリ)と呼ばれる。

ansibleコマンドを使う

Ansibleでは、「ansible」コマンドで各種処理を実行できる。与えられるオプション引数などは「-h」もしくは「--help」オプション付きでansibleコマンドを実行することで確認できる。

$ ansible --help

なお、前述の通りAnsibleはSSH経由で管理対象ホストにリモートログインして各種処理を実行する。そのため、以下のようにssh-agentコマンドを使用してあらかじめリモートログインに使用する公開鍵およびそのパスフレーズを登録し、パスフレーズを入力すること無しにリモートログインを行えるようにしておく必要がある。

$ ssh-agent bash
$ ssh-add
Enter passphrase for /home/hylom/.ssh/id_rsa: ←使用する鍵に対応するパスフレーズを入力する
Identity added: /home/hylom/.ssh/id_rsa (/home/hylom/.ssh/id_rsa)

管理対象のホストに対し正しく通信が行えるかを検証するには、次のように「<対象ホスト/グループ> -m ping」引数を付けてansibleコマンドを実行する。このとき、対象ホストとして「all」を指定すると、/etc/ansible/hostsファイルに記述されているすべてのホストが対象となる。

$ ansible all -m ping
192.0.2.1 | success >> {
    "changed": false, 
    "ping": "pong"
}

192.0.2.10 | success >> {
    "changed": false, 
    "ping": "pong"
}

192.0.2.11 | success >> {
    "changed": false, 
    "ping": "pong"
}

ここで指定されている「-m」オプションは、続けて指定したモジュールを実行するというという意味のオプションだ。ここではテスト用のモジュールである「ping」モジュールを実行する、という意味になる。

また、「-a」オプションでモジュールに与えるパラメータを指定することもできる。もしモジュールを指定せずに-aオプションのみを指定した場合、指定したコマンドが対象のホスト上で実行され、その結果が返される。たとえば次の例は「webservers」グループに含まれるホスト上で時刻を表示する「/bin/date」コマンドを実行したものだ。

$ ansible webservers -a "/bin/date"

192.168.2.10 | success | rc=0 >>
Wed Jan 28 21:00:08 JST 2015

192.168.2.11 | success | rc=0 >>
Wed Jan 28 21:00:08 JST 2015

ansibleコマンドのデフォルトではコマンドを実行したユーザーで管理対象のホストにリモートログインを試みる。もし別のユーザー名を使用したい場合は、「-u」オプションでログインに使用するユーザー名を指定できる。

なお、rootユーザーでのリモートログインはセキュリティ上の理由で禁止している場合が多いだろう。その場合、root権限が必要な処理を実行させるにはsudoを利用できるユーザーでリモートログインし、かつ「-s」もしくは「--sudo」オプションを指定すれば良い。sudoコマンドの実行時にパスワードが必要な場合は、「-K」もしくは「--ask-sudo-pass」オプションを指定すると実行時にそのパスワードを入力できるようになる。

ファイルを転送する

Ansibleにはさまざまなモジュールが用意されており、それらはansibleコマンドからも呼び出せる。たとえば「copy」モジュールでは、ローカルにあるファイルを指定したホストにコピーできる。次の例は、「/etc/hosts」ファイルを指定したホストに「/tmp/hosts」としてコピーする、というものだ。

$ ansible webservers -m copy -a "src=/etc/hosts dest=/tmp/hosts"
192.168.2.10 | success >> {
    "changed": true, 
    "checksum": "441dc406f2d6dff7195b0b2b071c5bccc2fabc8b", 
    "dest": "/tmp/hosts", 
    "gid": 1000, 
    "group": "hylom", 
    "md5sum": "c5b8333f7d281b531d334151300c91b5", 
    "mode": "0664", 
    "owner": "hylom", 
    "size": 235, 
    "src": "/home/hylom/.ansible/tmp/ansible-tmp-1421922668.59-7442260507284/source", 
    "state": "file", 
    "uid": 1000
}

192.168.2.11 | success >> {
    "changed": true, 
    "checksum": "441dc406f2d6dff7195b0b2b071c5bccc2fabc8b", 
    "dest": "/tmp/hosts", 
    "gid": 1001, 
    "group": "hylom", 
    "md5sum": "c5b8333f7d281b531d334151300c91b5", 
    "mode": "0664", 
    "owner": "hylom", 
    "size": 235, 
    "src": "/home/hylom/.ansible/tmp/ansible-tmp-1421922668.63-53693479417628/source", 
    "state": "file", 
    "uid": 1001
}

また、ディレクトリの作成やパーミッションの変更などは「file」モジュールで実行できる。次の例は、「/tmp/hosts」ファイルのオーナーおよびグループを「root」に設定し、そのパーミッションを「600」に変更するものだ。この処理はroot権限が必要な処理なので、「-s」オプションを付けてsudo経由で実行させる。

$ ansible webservers -m file -a "dest=/tmp/hosts mode=600 owner=root group=root" -s -K

sudo password: ←sudoコマンドの実行に必要なパスワードを入力する
133.242.6.157 | success >> {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0600", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "size": 235, 
    "state": "file", 
    "uid": 0
}

133.242.6.231 | success >> {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0600", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "size": 235, 
    "state": "file", 
    "uid": 0
}

このとき、もし「-s」オプションなしで実行すると次のように「FAILED」というステータスが返される。

$ ansible webservers -m file -a "dest=/tmp/hosts mode=600 owner=root group=root"

133.242.6.157 | FAILED >> {
    "failed": true, 
    "gid": 1000, 
    "group": "hylom", 
    "mode": "0664", 
    "msg": "chown failed", 
    "owner": "hylom", 
    "path": "/tmp/hosts", 
    "size": 235, 
    "state": "file", 
    "uid": 1000
}

133.242.6.231 | FAILED >> {
    "failed": true, 
    "gid": 1001, 
    "group": "hylom", 
    "mode": "0664", 
    "msg": "chown failed", 
    "owner": "hylom", 
    "path": "/tmp/hosts", 
    "size": 235, 
    "state": "file", 
    "uid": 1001
}

fileモジュールでは「state=directory」オプションを指定することでディレクトリを作成できる。次の例は、「/tmp/hoge」というディレクトリを作成するものだ。

$ ansible webservers -m file -a "dest=/tmp/hoge mode=755 owner=root group=root state=directory" -s -K

sudo password: ←sudoコマンドの実行に必要なパスワードを入力する
192.168.2.11 | success >> {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/tmp/hoge", 
    "size": 4096, 
    "state": "directory", 
    "uid": 0
}

192.168.2.10 | success >> {
    "changed": true, 
    "gid": 0, 
    "group": "root", 
    "mode": "0755", 
    "owner": "root", 
    "path": "/tmp/hoge", 
    "size": 6, 
    "state": "directory", 
    "uid": 0
}

逆にファイルやディレクトリを削除するには、パラメータに「state=absent」を指定する。

$ ansible webservers -m file -a "dest=/tmp/hoge state=absent" -s -K 

sudo password: ←sudoコマンドの実行に必要なパスワードを入力する
192.168.2.10 | success >> {
    "changed": true, 
    "path": "/tmp/hoge", 
    "state": "absent"
}

192.168.2.11 | success >> {
    "changed": true, 
    "path": "/tmp/hoge", 
    "state": "absent"
}

そのほかのモジュールとして、パッケージ管理を行う「yum」や「apt」、ユーザーの管理を行う「user」、サービスの管理を行う「service」、Gitリポジトリの操作を行う「git」などがある。利用できるモジュール一覧は「ansible-doc -l」コマンドで確認できる。また、個々のモジュールに関するドキュメントは「ansible-doc <モジュール名>」コマンドで閲覧できる。

Ansibleの設定ファイル

Ansibleでは、「/etc/ansible/ansible.cfg」というファイルにその各種設定が記述されている。このファイルではさまざまなAnsibleのデフォルト設定やSSH接続に関する設定などが指定できるので、確認しておくと良いだろう。

「Playbook」を利用する

Ansibleでは実行する作業をまとめて1つのファイルに記述したものを「Playbook」と呼ぶ。Playbookは前述のとおりYAML形式で記述する。Playbookの基本的なフォーマットは以下のようになる。

- hosts: <対象とするホスト/グループ>
  var:
    <変数名1>: <値>
    <変数名2>: <値>
      :
      :
  remote_user: <処理を実行するユーザー名>
  sudo: yes
  tasks:
    <タスク1>
    <タスク2>
      :
      :
  handlers:
    <ハンドラ1>
    <ハンドラ2>
      :
      :

Playbookではまず「hosts:」で対象とするホストもしくはグループを指定し、そのホストに対して実行する「タスク」や「ハンドラ」を続けて記述していく。

Ansibleの「タスク」

Ansibleでは、そのホストに対する処理を「タスク」という単位で管理する。通常、1つのタスクには以下のように1つのモジュールを指定する。

  - name: <タスクの説明>
    <モジュール名>: <実行時に与えるパラメータ>

例えば、「yum」モジュールを使って「httpd」パッケージをインストールするタスクは以下のようになる。

  - name: install httpd
    yum: name=httpd state=present

また、「command」モジュールを使えば任意のコマンドを実行させることが可能だ。

  - name: disable selinux
    command: /sbin/setenforce 0

なお、タスクを複数記述した場合、それらは記述された順番に実行される。

特定のタスクの実行後に実行される「ハンドラ」

「ハンドラ」は特定のタスクの実行後、あらかじめ指定しておいた処理を実行するための仕組みだ。該当のタスクで「notify」項目を設定することで、そのタスクの実行後にnotify項目で指定したハンドラが実行される。タスクと同様、1つのハンドラには1つのモジュールを指定する。

  - name: <ハンドラの説明>
    <モジュール名>: <実行時に与えるパラメータ>

たとえば、「template」モジュールを使ってApache HTTP Server(httpd)の設定ファイルを作成するタスクと、その設定の変更後にhttpdを再起動するハンドラは次のようになる。

tasks:
  - name: install WordPress configuration file
    template: src=wordpress.conf dest=/etc/httpd/conf.d/wordpress.conf
    notify:
      - restart httpd
handlers:
  - name: restart httpd
    service: name=httpd state=restarted

この場合、「install WordPress configuration file」というタスクが実行されると、続いて「notify」で指定された「restart httpd」というハンドラが実行される。

Playbookの実行

Playbookを実行するには、「ansible-playbook」コマンドを使用する。

$ ansible-playbook <実行したいPlaybookファイル>

そのほか、Playbookでは変数を使用したり、別のPlaybookを呼び出す「include」や「roles」機能、さらに条件分岐やループといった機能も用意されている。これらの詳細な仕様や応用的な利用方法についてはAnsibleのPlaybooksドキュメントを参照してほしい。

小規模・シンプルな環境でおすすめしたいAnsible

さて、ここまでではAnsibleの基本的な機能や使い方を説明した。AnsibleはChefやPuppetと比較してシンプルであり、ここまで説明した機能だけでも、多くの場合十分にサーバーの構成管理を行えるだろう。

特にAnsibleの利用をおすすめしたいのは、数台~十数台程度の小規模なサーバー管理だ。Ansibleは管理対象ホストにSSHおよびPythonさえあれば利用できるので、利用のためのイニシャルコストが低く、また最低限利用するために習得する知識の量も少ない。そのため、手軽に導入できるのがAnsibleの最大の利点だろう。