Ansible 入門
社内勉強会で Ansible の初歩的な発表をしたのでその資料を公開します。
間違い等あるとおもいますが、指摘して頂ければ幸いです。
Ansible とは?
構成管理ツールです。Chef とか Puppet とかああいうののお仲間です。
Puppet は知りませんが、Chef は少し使って嫌気が差して止めました。
理由は
- 特殊なことをしようとすると Ruby の知識が必要になる
- 構成管理「される側」にも Chef が必要(エージェント)
が主です。あとなんだかんだ言って結構複雑です。
その点 Ansible は下記の特徴があります。
- 標準入出力さえできればプラグインの言語は何でも構わない
- 一つ Ansible が入っているサーバと sshd が動いている対象サーバがあればそれでOK(要するに準備が要らない。もちろん自分自身だけでもOK)
- 標準(組込みモジュール?)で結構なんでもできる(ただし、 Chef と比較して、ではない。Chef は詳しくないので)
構成管理ツールに必須の冪等性も確保されています。
Ansible の構成
Ansible は端的に言えば
- hosts ファイル(インベントリ)
- playbook
- モジュール
の3つの要素で成り立ちます。
hosts ファイル
作業対象となるホストを記述します。
一般的には下記のように記述されます。
[lbserver]
192.168.1.1:1022
192.168.1.2:1022
[apserver]
192.168.2.1:1022
192.168.2.2:1022
[dbserver]
192.168.3.1:1022
192.168.3.2:1022
見ての通り ini 形式です。[セクション]でグループ化出来ます。このグループは後述する playbook で指定する際に使用しますが別に無くても構いません。
このファイルを/etc/ansible/hosts
として保存すると ansible 実行時に対象ホストが定まり、各ホストで ssh 経由で色々やってくれるということです。
※ hosts の場所は/etc/ansible/hosts
じゃなくても構いません。環境変数や-i
オプションで指定できたりします。
1022 はポート番号ですが、標準の 22 であれば指定はいりません。また、ssh_config も見てくれるので、ポートや鍵ファイルの指定は本来そちらで行うべきでしょう。
playbook
簡単にいえば後述のモジュールを組み合わせて、「このホストたちにはこのモジュールをこういうオプションで実行してよ」という命令書です。
yaml 形式で記述されます。
- hosts: dbserver
remote_user: hoge
sudo: yes
gather_facts: no
vars:
port: 3306
socket: "/var/lib/mysql/mysql.sock"
datadir: "/var/lib/mysql"
handlers:
- name: restart mysqld
service: name=mysqld state=restarted
tasks:
- name: yum install mysql
yum: name="{{item.name}}" enablerepo="{{item.repo}}" state=present
with_items:
- {name: mysql, repo: remi}
- {name: mysql-server, repo: remi}
- {name: mysql-devel, repo: remi}
- name: template my.cnf
template: src=etc/my.j2 dest=/etc/my.cnf mode=0644
notify: restart mysqld
- name: permit bin files
file: path={{item}} mode=0744
with_fileglob:
- /root/bin/*
- name: register
shell: touch /tmp/hoge creates=/tmp/hoge
register: result
- name: print result
debug: msg="rc:{{result.rc}} stdout:{{result.stdout}} stdout:{{result.stderr}}"
when: result.stdout == ""
これは割といろいろ使ってる playbook です。
キー個別に説明します。
hosts
前述の hosts ファイルで指定したグループ名を指定します。
all で全サーバ対象になるようです。
remote_user
リモート側の実効ユーザを指定します。
sudo
sudo するなら yes を指定します。
上に記述はないですが sudo_user
で sudo のユーザを指定することもできるようです。
gather_facts
ホスト情報を掻き集めるかのフラグです。
ホスト情報とはCPUのコア数や搭載メモリなどです。
これらは変数に代入されるので後述の template モジュールなどで威力を発揮します。
使用しない場合、無駄なので no にした方が実行速度が早くなります。
vars
変数を使用する場合はここで宣言します。
上の例のように宣言しておくと {{port}}
、${socket}
、$datadir
などで参照することが出来ます。
handlers
例えば apache の設定ファイルをいじった場合に httpd を restart したい場合などがあると思います。
この handlers を指定すると、変更があった場合に指定タスクを実行してくれます。
通知は tasks の notify で行います。複数のタスクで notify され、かつそれら全てで変更があった場合でも handlers が実行されるのは1回限りです。
tasks
playbook のキモとなる項目です。実行するモジュールを列挙していきます。
name 指定すると実行時に出力が為されます。また、name は必須ではないようです。書かなかった場合、モジュール部分の文字列がそのまま出力されるようです。
with_items
タスク内で使用する変数を宣言します。
モジュールは共通で、オプションのみ異なる場合などに便利です。個人的に使用頻度は非常に高いです。
上の例で言うと mysql と mysql-server をともに remi リポジトリを使って yum install します。
with_fileglob
glob
した結果を変数に代入し、その数分モジュールを実行します。
上の例で言うと /root/bin
以下にあるファイル全てのパーミッションを0744にします。
notify
handlers へ通知を行います。値には handlers の name キーを指定します。
上の例で言えば /etc/my.cnf に変更があった場合に mysqld を再起動します。
register
現在のモジュールの諸々の情報を指定した変数名へ代入します。
「諸々の情報」はモジュールによって異なるようです。
上記のように shell モジュールであれば rc
, stdout
, stderr
が取れますし、まっとうな?モジュールであれば changed
や failed
が取得でき、下記 when と組み合わせることで「前回のタスク結果に依存した」処理が書けるようになります。
※ どんなモジュールがどんなキーを扱えるかはどこかにドキュメントがあるはず…
when
指定した条件が成り立つときのみタスクを実行します。
上記の例だと register タスクの標準出力が空のときのみ実行されるようになります。
自信ないですがおそらく初回実行時のみ実行されます。
changed_when
changed 結果を明示的に指定できます。
changed_when: False
などとすると ステータスが changed になることがなくなります。
failed_when
基本的に changed_when と同じです。
モジュール
ansible 自体の主な仕事は、前述の playbook の解釈やホストへの接続、変数の展開などのメタ的な仕事であって、「このファイルをコピーしてくれ」とか「このサービスを起動してくれ」とかそういう具体的な実務は一切行いません。
それら実務はすべてプラグインとして提供・実装され、「モジュール」と呼ばれています。
代表的な(今回簡単に解説する)モジュールを下記に挙げます。
モジュール名 | 役目 | 冪等性 |
---|---|---|
shell | シェル上でコマンドを実行 | creates |
file | ファイルやディレクトリの作成、パーミッション | 自動 |
lineinfile | 指定ファイルの行単位の書き換え | 半自動 |
copy | ファイルの丸コピー | 自動 |
template | テンプレートを利用したファイルのコピー | 自動 |
synchronize | 要するに rsync | 自動 |
get_url | 指定URLからダウンロード | 自動 |
yum | yum コマンド。enablerepo やdisablerepo はもちろん rpm から直接インストールも可能 | 自動 |
service | service コマンド。chkconfig も兼ねる | 自動 |
上記は全て標準です。
さらに前述のとおり、なにか凝ったことをしようと思ったときは自分であらゆる言語でモジュールを作成することが出来ます。
ただしモジュールはリモートに転送されて実行されます。
よって php で自前でモジュールを作成してもリモート側に php が入っていないと実行できません。
下記はよく使いそうなオプションのみ記載しています。
結構便利なオプションがあったりするので調べてみるといいです。
モジュールの詳細が知りたい場合はansible-doc モジュール名
で調べることが出来ます。
shell
シェル上でコマンドを実行します。似たようなものに command モジュールがありますが、パイプやリダイレクトなどが使えるので基本的には shell の方がいいです。
# composer のインストール
shell: >
curl -sS https://getcomposer.org/installer | php && mv composer.phar composer
chdir=/usr/local/bin
creates=/usr/local/bin/composer
※ 見やすいように改行いれてます(folded スタイル)。一番上が実行コマンドでその他がオプションになります。
chdir
オプションでカレントディレクトリを指定、
creates
オプションでそのファイルが既にあるなら実行しないようになります。
なんでもできるので便利ですが、playbook が shell ばっかりになると単に手順書を複雑に書いているだけな気分になり、やる気が削がれます。気をつけましょう。
また、ansible は各タスクごとに プロセスを生成するようなので cd
だけのタスクとかをして無駄です。chdir オプションを使います。
file
ファイルやディレクトリの作成・削除、パーミッションの設定などを行います。
# /var/log/php ディレクトリを作成して 0644 にする
file: path=/var/log/php mode=0644 state=directory owner=apache group=apache
# /tmp/hoge を削除
file: path=/tmp/hoge state=absent
path
で対象ファイルを指定します。
mode
でパーミッションを指定します。
state
で対象の種類を指定します。ファイルだったりディレクトリだったり作成だったり削除だったり。
owner
でオーナーを指定します。
group
でグループを指定します。
ファイルの作成は基本的にやらないほうがいいです。
state=touch
を指定すれば作成されますが、毎回「changed」になるので精神衛生上良くありません。
changed_when: False
で抑止できますが、これだと初回実行時も抑止されます。
そういうものだと割りきって shell モジュールで shell: touch /tmp/hoge creates=/tmp/hoge
しちゃうのが良いんじゃないでしょうか。
lineinfile
ファイル内の特定の行を書き換えます。個人的に一番良く使います。
# selinux を無効にする
lineinfile: dest=/etc/sysconfig/selinux regexp="^SELINUX=.*" line="SELINUX=disabled"
# ssh のパスワード認証を禁止する
lineinfile: >
dest=/etc/ssh/sshd_config
regexp="^PasswordAuthentication"
line="PasswordAuthentication no"
insertafter="#PasswordAuthentication"
# php.ini に include_path を追加する
lineinfile: >
dest=/etc/php.ini
backrefs=yes
regexp='^include_path = "((?!.*add_path.*)(?(1)|.*))"'
line='include_path "\1:add_path"'
dest
で対象ファイルを指定します。
regexp
で対象行を指定します(マッチした行が置換される)。
line
で置換する文字列自体を指定します。
insertafter
でマッチしなかった場合にここで指定した正規表現のにマッチする次の行へ挿入されます。
backrefs
でキャプチャ文字が使えるようになりますが、insertafter/before
が使用できなくなります。
backrefs
を使用して既存文字列に文字列を加えるような場合、上記のような小細工が必要です。
※ ただし、説明は省く
copy
ファイルをローカルからリモートへコピーします。
# php 設定ファイルを転送する
copy: src=etc/php.d/default.ini dest=/etc/php.d/default.ini mode=0644
src
でローカルの対象ファイルパスを指定します。絶対パス、あるいは yaml ファイルからの相対パスです。
dest
でリモートのファイルパスを指定します。
mode
でパーミッションを指定します。
template
テンプレートファイルを元にして、変数置換したファイルをローカルからリモートへコピーします。
# nginx 設定ファイルを転送する
template: src=etc/nginx/nginx.j2 dest=/etc/nginx/nginx.conf mode=0644
src
でローカルの対象ファイルパスを指定します。テンプレートエンジンは jinja という python のテンプレートです。
dest
でリモートのファイルパスを指定します。
mode
でパーミッションを指定します。
etc/nginx/nginx.j2
の冒頭は下記のようになっています。
user nginx;
worker_processes {{ ansible_processor_vcpus }};
・・・
こういう環境依存のファイルを設置するときは template が便利です。
nginx のプロセス数は CPU のコア数を指定するのが望ましいですが、copy モジュールだと丸コピーなので細かな設定ができません。
copy したあと lineinfile してもいいですが、たくさんあると面倒です。
前述のとおり、変数は自分で宣言できますし、上記のように ansible が用意した変数を使うことも出来ます。ただし、上記の変数は gather_fact:yes
していないと使用できません。
synchronize
rsync 的なことをします。
オプションが大量にある上、各オプションが rsync のオプションに対応しているので例は省きます。
1点注意として、src オプションに相対パスを記述すると実効ユーザのホームディレクトリからの相対パスになるようです。
なんかとても微妙…。
get_url
指定 URL からファイルをダウンロードします。
# fluentd インストールスクリプトをダウンロードする
get_url: url=http://toolbelt.treasuredata.com/sh/install-redhat.sh dest=/root/fluentd-install.sh
url
で URL を指定します。
dest
で保存場所を指定します。
dest が既に存在する場合は実行されません。
yum
yum コマンドに対応します。
# yum で remi リポジトリから php5.5 をインストールする
yum: name=php state=present enablerepo=remi-php55
# yum で mysql をインストールする
yum: name=http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm state=present
yum: name=mysql-community-server state=present
yum: name=mysql-devel state=present
name
でパッケージ名を指定します。
state
でどういう状態にするかを指定します。[present|latest|absent] = [install|update|erase]
enablerepo
で有効にするリポジトリを指定します。
disablerepo
で無効にするリポジトリを指定します。
service
service コマンドに対応します。
# httpd サービスを起動して、自動起動をオンにする
service: name=httpd state=started enabled=yes
# ip6tables サービスを停止して、自動起動をオフにする
service: name=ip6tables state=stopped enabled=no
name
でサービス名を指定します。
state
でどういう状態にするかを指定します。[started|stopped|restarted|reloaded] = [start|stop|restart|reload]
enabled
で自動起動の ON/OFF を指定します(=chkconfig)。
graceful がない!
make install
以下、ソースファイルを download してきて解凍して make して make install する playbook です。
※ そういうモジュールがあるかと思ったけどなかった
- name: download hoge source file
get_url: url=https://hostname/hoge_source.tar.gz dest=/usr/local/src/hoge_source.tar.gz
- name: extract hoge source file
unarchive: src=/usr/local/src/hoge_source.tar.gz dest=/usr/local/src/ creates=/usr/local/src/hoge_source
- name: install hoge
shell: ./configure && make && make install chdir=/usr/local/src/hoge_source creates=/usr/bin/hoge
冪等性がいい感じに効いてくれるので2回目以降はすべて skip されます。
※ ただし creates=/usr/bin/hoge
だけは注意。インストールした結果、何かが出来上がるならそれを指定する
role
依存関係とかいろいろ設定できる role ってのがあるらしいがまだ触ってません。