akishin999の日記

調べた事などを書いて行きます。

構成管理ツール Ansible を使ってみる

最近は話題のサーバ構成管理ツール Ansible を試したりしています。

Ansible 自体は Python 製ですが、使うに当たっては特に Python の知識は必要とされる事もなく、定義ファイル(Playbook)も YAML ファイルなので気軽に始める事ができました。

また、Capistrano などと同じく SSH で対象サーバに接続さえ出来ればいい、という仕様なので、サーバに余計なパッケージを入れずに済むのも嬉しいです。
その点も Chef や Puppet などより個人的には好みですね。

検証環境は CentOS 6.4 x86_64 になります。

インストール

インストールには Python 2.6 以上が必要です。
CentOS 6 系であれば yum で普通に入れれば 2.6 系が入るはずなので問題ないかと思います。

# python -V
Python 2.6.6
EPEL からインストール

まずはお手軽に EPEL からインストールする方法。
CentOS 6.4 x86_64 の場合は EPEL に必要なパッケージが全て揃っているので、以下を実行するだけです。

# yum install -y http://dl.fedoraproject.org/pub/epel/6/x86_64/libyaml-0.1.3-1.el6.x86_64.rpm \
                 http://dl.fedoraproject.org/pub/epel/6/x86_64/PyYAML-3.10-3.el6.x86_64.rpm \
                 http://dl.fedoraproject.org/pub/epel/6/x86_64/ansible-1.2.2-1.el6.noarch.rpm

バージョンを確認します。

# ansible --version
ansible 1.2.2

以下のコマンドがインストールされました。

/usr/bin/ansible
/usr/bin/ansible-doc
/usr/bin/ansible-playbook
/usr/bin/ansible-pull

設定ファイルは以下にあるようです。

/etc/ansible/ansible.cfg
/etc/ansible/hosts
Github からインストール

最新版が使いたい方は Github から持ってきてインストールします。

まずは必要なライブラリをインストール。

# yum install -y http://pkgs.repoforge.org/python-yaml/python-yaml-3.09-3.el6.rf.x86_64.rpm \
                 python-jinja2 \
                 python-paramiko \
                 git

Github から clone して env-setup を実行します。

# cd /usr/local/src/
# git clone git://github.com/ansible/ansible.git
# cd ansible/
# source ./hacking/env-setup

バージョンを確認します。

# ansible --version
ansible 1.3 (devel ceff3b6ba3) last updated 2013/08/10 16:59:38 (GMT +900)

ログイン時に毎回 env-setup を source するのは面倒なので、以下のように ~/.bash_profile に追加しておきます。

$ echo "source /usr/local/src/ansible/hacking/env-setup" >> ~/.bash_profile

使ってみる

いきなり Playbook を書いて複雑な構成管理を始める前に、最初は ansible コマンドを使ってどんな事が出来るのかいろいろと試してみるのがいいと思います。

というわけで ansible コマンドの使い方を見ていきます。

まずは対象ホストを記述したテキストファイルを用意します。
ファイル名は判り易いものであれば何でも構いません。
ここでは hosts という名前のファイルを作成し、localhost(127.0.0.1) を追加しました。

$ echo "127.0.0.1" > hosts

作成した hosts ファイルを指定して、以下のように ping モジュールを実行します。

$ ansible all -i hosts -m ping -k
SSH password:
127.0.0.1 | success >> {
    "changed": false,
    "ping": "pong"
}

SSH パスワードを求められるので入力すると、上記のように localhostping モジュールを実行した結果が表示されます。

ホストの指定方法について

前述のコマンド内での all という部分は、作成した hosts ファイル内に書いた対象ホストうち、コマンド実行対象とするホストを決定するためのパターンを指定している部分です。

ここではホストは一つしか記述していないので、全てのホストを対象にする「all」を指定しています。

hosts ファイルに複数のホストを記述している場合、この部分で処理を適用するホストのパターンを指定します。

また、ホストは役割によってグルーピング可能ですが、その場合は処理を適用するグループ名を指定することもできます。
グループは以下のように [グループ名] というようにブラケットで囲んで指定します。

  • hosts
[local]
127.0.0.1
[webserver]
192.0.2.2
[dbserver]
192.0.2.3]

上記のように記述されている場合に、[local] グループのみに処理を適用したい場合、以下のようにグループ名を指定します。

$ ansible local -i hosts -m ping -k

ホストファイルの書き方については以下のドキュメントにまとめられています。

Inventory and Patterns | AnsibleWorks
http://www.ansibleworks.com/docs/patterns.html

基本的なオプション

その他、先ほどの ping モジュール実行時に指定している ansible コマンドのオプションは以下の通りです。

オプション 意味
-i 対象ホストファイル, --inventory-file=対象ホストファイル 対象ホストを記載したテキストファイルを指定する
-m モジュール名, --module-name=モジュール名 対象ホストに対して実行するモジュールを指定する
-k, --ask-pass SSH のパスワード入力を求める。パスワード無しでログインできるようになっている場合には不要

「-i」オプションでは対象ホストファイルを指定します。
毎回同じファイルを使用するような場合、環境変数 ANSIBLE_HOSTS にファイルパスを設定しておく事で省略する事が可能です。

「-m」オプションでは Ansible の「モジュール」を指定します。
Ansible では実行したい処理に合わせたモジュールを使用する事で様々な処理を対象サーバに対して実行することができます。
標準で以下のようなモジュールが用意されています。

Ansible Modules | AnsibleWorks
http://www.ansibleworks.com/docs/modules.html

ちなみに上記ページのモジュールのヘルプはモジュール名さえ分かれば ansible-doc コマンドで調べる事も可能です。

# ansible-doc yum
> YUM

  Will install, upgrade, remove, and list packages with the `yum'
  package manager.

Options (= is mandatory):

- conf_file
        The remote yum configuration file to use for the transaction.

- disable_gpg_check
        Whether to disable the GPG checking of signatures of packages



「-k」オプションを指定すると実行時に対象サーバの SSH パスワードを求められます。
複数のホストを管理する場合、対象ホスト全てに対して同一ユーザを同一パスワードで作成しておく必要があるようです。
もしくは ssh-agent を設定しておくか、もしくはパスワード無し秘密鍵でのログインを設定しておき、「-k」オプション自体を省略する事も可能です。

それでは実際にいくつかモジュールの使い方を見て行きます。

直接コマンドを実行する

対象サーバで任意のコマンドを実行したい場合には、command モジュールを使用します。
ただ、「-m」オプションによるモジュールの指定を省略した場合には自動的に command モジュールが使用されるので、command モジュールを使いたい場合は「-m」オプション自体を省略できます。
command モジュールで実行したいコマンドは「-a」オプションに文字列で指定します。

$ ansible all -i hosts -a "cat /etc/redhat-release" -k
SSH password:
127.0.0.1 | success | rc=0 >>
CentOS release 6.4 (Final)

これだけだと直接実行する方が早いと思ってしまいそうですが、サーバ台数が多い場合などには簡単なコマンドでも複数台にまとめて実行できるので、かなり便利だと思います。

また、command モジュールは直接任意の Linux コマンドを実行できるので、他のモジュールで上手く行かないような操作があった場合にもこのモジュール(または shell や raw モジュール)でベタにコマンドを実行してしまえば何でも出来てしまいます。

まずはやりたい事をするための Ansible モジュールがあるか探してみて、ないようなら command モジュールを使う、といった感じで、非常によく使用するモジュールです。

yum でパッケージをインストールする

yum でパッケージをインストールするには yum モジュールを使います。
「-m」オプションに「yum」を指定し、「-a」オプションでは「name」に対象のパッケージ名、「state」にパッケージの状態を指定します。

$ ansible all -i hosts -m yum -a "name=httpd state=latest" -k

state にはパッケージをインストールする場合は「present」「latest」「installed」、パッケージを削除する場合には「remove」または「absent」を指定します。

但し、yum コマンドでパッケージをインストール出来るのは「root ユーザ」または「sudo による実行を許可された一般ユーザ」だけなのは Ansible を使用していても同じです。
一般ユーザで yum モジュールを実行すると以下のようなエラーになってしまいます。

$ ansible all -i hosts -m yum -a "name=httpd state=latest" -k
SSH password:
127.0.0.1 | FAILED >> {
    "changed": false,
    "failed": true,
    "msg": "You need to be root to perform this command.\n",
    "rc": 1,
    "results": [
        ""
    ]
}

その場合は、Ansible 実行ユーザで yum を実行できるように sudo の設定を変更して「-s」オプションを使うか、または以下のように「-u」オプションで root ユーザを使用するように指定します。

$ ansible all -i hosts -m yum -a "name=httpd state=latest" -u root -k

name に指定できるのはパッケージ名だけではありません。
CentOS 6 であれば RPM の URL を直接指定できるのは Ansible でも同じです。

以下は EPEL から paco の RPM ファイルを直接 yum でインストールしています。

$ ansible all -i hosts -m yum -a "name=http://dl.fedoraproject.org/pub/epel/6/x86_64/paco-2.0.9-6.el6.x86_64.rpm" -u root -k

自分で作成した RPM ファイルなども同様に yum モジュールでインストールできます。
以下は自作ではありませんが、MySQL-client の RPM が /usr/local/src 以下に置いてある場合にインストールする例です。

$ ansible all -i hosts -m yum -a "name=/usr/local/src/MySQL-client-5.6.12-2.el6.x86_64.rpm" -u root -k

このように普段 yum で行っているような事は大抵 yum モジュールで実行する事が可能です。

ファイルをコピーする

SCP で対象サーバにファイルをコピーしたい場合は、file モジュールを使います。

/home/ansible/test.conf というファイルを作成した状態で以下を実行すると対象サーバの同じ場所にファイルがコピーされ、パーミッションが 600 に設定されます。

$ ansible all -m file -a "dest=/home/ansible/test.conf mode=600" -i hosts -k

file モジュールでは dest に指定したファイルが対象サーバの同じ位置にコピーされます。
もしコピー元とコピー先でファイルパスが異なるような場合は、代わりに copy モジュールか template モジュールを使用して下さい。

あるファイルからのシンボリックリンクを張りたい場合にも file モジュールが使用できます。
state に「link」を指定し、src にリンク元ファイルのパスを指定します。

$ ansible all -m file -a "src=/etc/httpd/conf/httpd.conf dest=/home/ansible/httpd.conf state=link" -i hosts -u root -k

ディレクトリの作成も file モジュールで行えます。
その場合は state に「directory」を指定します。
mkdir -p と同じで深い階層のディレクトリも一発で作成できました。

$ ansible all -m file -a "dest=/home/ansible/foo/bar/baz state=directory" -i hosts -k

state に「absent」を指定することで、ファイルやディレクトリの削除もできます。
ディレクトリの場合、親ディレクトリを指定すればサブディレクトリも含め一括で消してくれます。

$ ansible all -m file -a "dest=/home/ansible/foo/ state=absent" -i hosts -k

デバッグ方法

Ansible が裏側でどのような処理を行っているかを確認したい場合、「-v」オプションを指定する事でより詳細なログを画面に出力する事が出来るようになっています。

$ ansible all -vvv -i hosts -m ping -k

SSH などと同じく、v の数を 1 〜 3 の間で増やすことで出力される情報の量を調整できます。
これにより、処理が上手くいかない場合などに原因を調査することが可能になっています。

また、Ansible で実行した処理は対象サーバの /var/log/messages に以下のような形で出力されます。

Aug  9 05:55:06 centos6 ansible-command: Invoked with executable=None shell=False args=cat /etc/redhat-release removes=None creates=None chdir=None
Aug  9 05:57:52 centos6 ansible-ping: Invoked with data=None

対象サーバで処理が失敗してしまうような場合、こちらも原因の調査に役立つでしょう。

まとめ

ここに書いたモジュールを組み合わせるだけでもかなり色々な事が出来るようになります。
特に command モジュールを多用すればそれこそ何でも出来てしまいます。

単純に運用時の複数ホストでのコマンド同時実行ツールとして使う場合にも、ansible コマンドをシェルスクリプトに並べて書いておけばいいだけなので Capistrano を使うより簡単かも知れません。

ただ、Ansible の本当に便利なところはやはり Playbook という再現可能な形でサーバの構築手順をまとめておけるところにあると思います。
が、長くなってしまったので Playbook についてはまた次回にでも。

※ 続き書きました。
Ansible の Playbook を使ってみる
http://d.hatena.ne.jp/akishin999/20130815/1376520672

ansible コマンドの例については以下のドキュメントに他にもいろいろな例が載っていて参考になると思います。

Command Line Examples | AnsibleWorks
http://www.ansibleworks.com/docs/examples.html

参考

構成管理ツール Ansible について - apatheia.info
http://apatheia.info/blog/2013/04/06/about-ansible/

今日からすぐに使えるデプロイ・システム管理ツール ansible 入門 ― そこはかとなく書くよん。
http://tdoc.info/blog/2013/05/10/ansible_for_beginners.html