概要
July Tech Festa にて開催されたハンズオンの資料が公開されていたことに刺激され、Chef の代わりに Ansible を使う資料を作りました始めました。
Ansible を使って WordPress サーバーのセットアップを行います。
まだ Ansible を試し始めたばかりで自分の勉強がてら書いています。
Puppet にも Chef にも乗り遅れたので Ansible に飛び乗ってみようかと。
※鋭意作成中です。
そのため Github にある playbook を実行した結果と必ずしも同じでは無いことがあります。
https://github.com/yteraoka/ansible-tutorial/ コメントなどお待ちしております。@yteraoka
少しずつ更新してます、また来てね。
Ansible とは
Ansible のサイト (AnsibleWorks | Radically simple IT orchestration) には次のように書いてあります。
Ansible は非常にシンプルなIT構成エンジンです。これはあなたのアプリケーションやシステムのデプロイを容易にします。スクリプトや専用のコードを書くことなくアプリケーションをデプロイし、更新することができます。エージェントをインストールすることなく、SSH を使い、自然な英語に近い感覚で自動化します。以下のサイトも参考になります
Ansible は最もシンプルな構成管理、自動化ツールです。
- 構成管理ツール Ansible について - apatheia.info
- ansibleを使ってみる — そこはかとなく書くよん。
- Deploying with Vagrant and Ansible by yeukhon [speakerdeck]
(これ、とても良いスライドです。この Tutorial の後にどうぞ..)
目次
- Vagrant を使ってサーバーを準備する
- Ansible のインストール
- Ansible を使うための準備
- Ansible の疎通確認
- 簡単な Playbook を書いて試す
- 対象ホストの情報を取得 (GATHERING FACTS)
- Best Plactices に沿った構成を真似る
- serverspec でテストする
- もっと知る
1. Vagrant を使ってサーバーを準備する
何度でも綺麗な環境でやり直せるように VirtualBox + Vagrant を使ってこの Tutorial 用環境を構築します。
あたりを参考に最新版の VirtualBox と Vagrant をインストールしてください。 Sahara plugin なんかを使うとやり直しも簡単ですが、再構築してもそんなに時間かからないのでお好みで。$ mkdir ansible-tutorial
$ cd ansible-tutorial
$ vagrant init centos6 http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130427.box
Ansible サーバーと、Ansible に制御される側の2台のサーバーを立てることにするので Vagrantfile を編集します。
$ vi Vagrantfile
config.vm.box = "centos6" の行を次のように書き換えます。2台じゃなくて3台でも4台でもOK
config.vm.define :node1 do |node|
node.vm.box = "centos6"
node.vm.network :forwarded_port, guest: 22, host: 2001, id: "ssh"
node.vm.network :private_network, ip: "192.168.33.11"
end
config.vm.define :node2 do |node|
node.vm.box = "centos6"
node.vm.network :forwarded_port, guest: 22, host: 2002, id: "ssh"
node.vm.network :forwarded_port, guest: 80, host: 8000, id: "http"
node.vm.network :private_network, ip: "192.168.33.12"
end
編集が終わったら起動させます。
$ vagrant up
起動後、Ansible で node1 から node2 へ ssh するため、Vagrant 用の秘密鍵をコピーする。
$ vagrant ssh-config node1 > ssh_config
$ vagrant ssh-config node2 >> ssh_config
$ scp -F ssh_config ~/.vagrant.d/insecure_private_key node1:.ssh/id_rsa
vagrant ssh コマンドでログインできます
$ vagrant ssh node1
$ vagrant ssh node2
やり直したくなったら destroy して up すれば元の状態に戻ります
$ vagrant destroy node2
$ vagrant up node2
2. Ansible をインストールする
node1 に Ansible をインストールします。CentOS 6 なので EPEL リポジトリから yum でインストールします。
$ sudo rpm -ivh http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
$ sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6
$ sudo yum -y install ansible
楽ちんですね。
3. Ansible を使うための準備
vagrant ssh を使うと vagrant ユーザーでログインし、パスワードなしで sudo で root としてコマンドが実行可能なので、Ansible の実行も vagrant ユーザーで行う。
4. Ansible の疎通確認
$ ansible 192.168.33.12 -m ping
192.168.33.12 | success >> {
"changed": false,
"ping": "pong"
}
ansible-doc コマンドでモジュールのドキュメントを読むことができます。
$ ansible-doc ping
> PING
A trivial test module, this module always returns `pong' on
successful contact. It does not make sense in playbooks, but it is
useful from `/usr/bin/ansible'
Example:
ansible webservers -m ping
$ ansible 192.168.33.12 -a 'uname -r'
192.168.33.12 | success | rc=0 >>
2.6.32-358.el6.x86_64
5. 簡単な Playbook を書いて試す
まずはインベントリファイルを作成する。yum でインストールした Ansible の場合、デフォルトのインベントリファイルは /etc/ansible/hosts となっている。これは /etc/ansible/ansible.cfg で定義されている。別のファイルを使う場合は -i オプションで指定する。
$ cat <<_EOD_ > hosts
[test-servers]
192.168.33.12
_EOD_
$ cat <<_EOD_ > simple-playbook.yml
- hosts: test-servers
user: vagrant
sudo: yes
tasks:
- name: be sure httpd is installed
action: yum pkg=httpd state=installed
- name: be sure httpd is running and enabled
service: name=httpd state=running enabled=yes
_EOD_
この playbook の内容は
hosts: test- 対象のホストまたはグループを指定する
user: vagrant- リモートホストへ vagrant ユーザとして ssh でログインする
sudo: yes- リモートホストで sudo を使って処理を実行する
tasks:- 実行する処理をリストで定義する
tasks の内容
name:- 処理の名称。実行時や task の一覧で表示されます
action:- これは省略可能で
yum:とも書ける service:- サービスの状態を制御するモジュール
--syntax-check オプションを使います。
$ ansible-playbook -i hosts simple-playbook.yml --syntax-check
Playbook Syntax is fine
次に task の一覧を確認してみましょう。--list-tasks オプションを使います。(その他のオプション一覧はこちら)。
$ ansible-playbook -i hosts simple-playbook.yml --list-tasks
playbook: simple-playbook.yml
play #1 (test-servers): task count=5
be sure httpd is installed
be sure httpd is running and enabled
次は dry-run です、--check オプションを指定することで変更は行わないが、実際に実行するとこうなるという出力がされます。
$ ansible-playbook -i hosts simple-playbook.yml --check
PLAY [test-servers] ***********************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.33.12]
TASK: [be sure httpd is installed] ********************************************
changed: [192.168.33.12]
TASK: [be sure httpd is running and enabled] **********************************
failed: [192.168.33.12] => {"failed": true}
msg: cannot find 'service' binary or init script for service, possible typo in service name?, aborting
FATAL: all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit @/var/tmp/ansible/simple-playbook.retry
192.168.33.12 : ok=2 changed=1 unreachable=0 failed=1
あららら?なんか failed って出てますね。まぁ、順番に見てみましょう。一つ目のインストールする task は changed となっています。これは、まだ httpd がインストールされていないので、実際に実行するとインストールされて changed となるということを意味しています。次の自動起動と起動している状態にする task は失敗してしまっています。これはまだ httpd がインストールされていないために、chkconfig httpd などに失敗するからです。ではいよいよ実行してみましょう。
$ ansible-playbook -i hosts simple-playbook.yml
PLAY [test-servers] ***********************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.33.12]
TASK: [be sure httpd is installed] ********************************************
changed: [192.168.33.12]
TASK: [be sure httpd is running and enabled] **********************************
changed: [192.168.33.12]
PLAY RECAP ********************************************************************
192.168.33.12 : ok=3 changed=2 unreachable=0 failed=0
うまくいきましたね。node2 で確認
$ sudo chkconfig --list httpd
httpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
$ sudo service httpd status
httpd (pid 2424) is running...
冪等性があるため再度実行しても対象サーバーの状態は変わらない。
ただし、既に package がインストールされていたり、サービスの設定がされていたりするのでコマンドの出力は変わる。(changed が ok だったり skipping だったりする)
2度目の実行の出力
$ ansible-playbook -i hosts simple-playbook.yml
PLAY [test-servers] ***********************************************************
GATHERING FACTS ***************************************************************
ok: [192.168.33.12]
TASK: [be sure httpd is installed] ********************************************
ok: [192.168.33.12]
TASK: [be sure httpd is running and enabled] **********************************
ok: [192.168.33.12]
PLAY RECAP ********************************************************************
192.168.33.12 : ok=3 changed=0 unreachable=0 failed=0
6. 対象ホストの情報を取得する
実行結果に「GATHERING FACTS」と出力されています。このような task は playbook に書いていません。これは何でしょう?結構時間かかってます(非力な virtual server だから?)。
名前のとおりですが、これは対象サーバーから情報を収集する処理です。次のようにして内容を確認すことができます。
$ ansible -m setup -i hosts 192.168.33.12
192.168.33.12 | success >> {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.0.2.15",
"192.168.33.12"
],
"ansible_all_ipv6_addresses": [
"fe80::a00:27ff:fec9:399e",
"fe80::a00:27ff:fed5:dab6"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "12/01/2006",
"ansible_bios_version": "VirtualBox",
"ansible_cmdline": {
"KEYBOARDTYPE": "pc",
"KEYTABLE": "us",
"LANG": "en_US.UTF-8",
"SYSFONT": "latarcyrheb-sun16",
"quiet": true,
"rd_LVM_LV": "VolGroup/lv_root",
"rd_NO_DM": true,
"rd_NO_LUKS": true,
"rd_NO_MD": true,
"rhgb": true,
"ro": true,
"root": "/dev/mapper/VolGroup-lv_root"
},
"ansible_date_time": {
"date": "2013-08-08",
"day": "08",
"epoch": "1375968652",
"hour": "13",
"iso8601": "2013-08-08T13:30:52Z",
"iso8601_micro": "2013-08-08T13:30:52.873665Z",
"minute": "30",
"month": "08",
"second": "52",
"time": "13:30:52",
"tz": "UTC",
"year": "2013"
},
"ansible_default_ipv4": {
"address": "10.0.2.15",
"alias": "eth0",
"gateway": "10.0.2.2",
"interface": "eth0",
"macaddress": "08:00:27:c9:39:9e",
"mtu": 1500,
"netmask": "255.255.255.0",
"network": "10.0.2.0",
"type": "ether"
},
"ansible_default_ipv6": {},
"ansible_devices": {
"sda": {
"holders": [],
"host": "SATA controller: Intel Corporation 82801HM/HEM (ICH8M/ICH8M-E) SATA Controller [AHCI mode] (rev 02)",
"model": "VBOX HARDDISK",
"partitions": {
"sda1": {
"sectors": "1024000",
"sectorsize": 512,
"size": "500.00 MB",
"start": "2048"
},
"sda2": {
"sectors": "1047549952",
"sectorsize": 512,
"size": "499.51 GB",
"start": "1026048"
}
},
"removable": "0",
"rotational": "1",
"scheduler_mode": "cfq",
"sectors": "1048576000",
"sectorsize": "512",
"size": "500.00 GB",
"support_discard": "0",
"vendor": "ATA"
},
"sr0": {
"holders": [],
"host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)",
"model": "CD-ROM",
"partitions": {},
"removable": "1",
"rotational": "1",
"scheduler_mode": "cfq",
"sectors": "2097151",
"sectorsize": "512",
"size": "1024.00 MB",
"support_discard": "0",
"vendor": "VBOX"
},
"sr1": {
"holders": [],
"host": "IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)",
"model": "CD-ROM",
"partitions": {},
"removable": "1",
"rotational": "1",
"scheduler_mode": "cfq",
"sectors": "2097151",
"sectorsize": "512",
"size": "1024.00 MB",
"support_discard": "0",
"vendor": "VBOX"
}
},
"ansible_distribution": "CentOS",
"ansible_distribution_release": "Final",
"ansible_distribution_version": "6.4",
"ansible_domain": "localdomain",
"ansible_eth0": {
"active": true,
"device": "eth0",
"ipv4": {
"address": "10.0.2.15",
"netmask": "255.255.255.0",
"network": "10.0.2.0"
},
"ipv6": [
{
"address": "fe80::a00:27ff:fec9:399e",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "08:00:27:c9:39:9e",
"module": "e1000",
"mtu": 1500,
"type": "ether"
},
"ansible_eth1": {
"active": true,
"device": "eth1",
"ipv4": {
"address": "192.168.33.12",
"netmask": "255.255.255.0",
"network": "192.168.33.0"
},
"ipv6": [
{
"address": "fe80::a00:27ff:fed5:dab6",
"prefix": "64",
"scope": "link"
}
],
"macaddress": "08:00:27:d5:da:b6",
"module": "e1000",
"mtu": 1500,
"type": "ether"
},
"ansible_form_factor": "Other",
"ansible_fqdn": "localhost.localdomain",
"ansible_hostname": "localhost",
"ansible_interfaces": [
"lo",
"eth1",
"eth0"
],
"ansible_kernel": "2.6.32-358.el6.x86_64",
"ansible_lo": {
"active": true,
"device": "lo",
"ipv4": {
"address": "127.0.0.1",
"netmask": "255.0.0.0",
"network": "127.0.0.0"
},
"ipv6": [
{
"address": "::1",
"prefix": "128",
"scope": "host"
}
],
"mtu": 16436,
"type": "loopback"
},
"ansible_machine": "x86_64",
"ansible_memfree_mb": 323,
"ansible_memtotal_mb": 458,
"ansible_mounts": [
{
"device": "/dev/mapper/VolGroup-lv_root",
"fstype": "ext4",
"mount": "/",
"options": "rw",
"size_available": 497491697664,
"size_total": 525282689024
},
{
"device": "/dev/sda1",
"fstype": "ext4",
"mount": "/boot",
"options": "rw",
"size_available": 448802816,
"size_total": 507744256
},
{
"device": "/vagrant",
"fstype": "vboxsf",
"mount": "/vagrant",
"options": "uid=501,gid=501,rw",
"size_available": 72607436800,
"size_total": 117461032960
}
],
"ansible_os_family": "RedHat",
"ansible_pkg_mgr": "yum",
"ansible_processor": [
"Intel(R) Core(TM) i3-3217U CPU @ 1.80GHz"
],
"ansible_processor_cores": "NA",
"ansible_processor_count": 1,
"ansible_product_name": "VirtualBox",
"ansible_product_serial": "NA",
"ansible_product_uuid": "NA",
"ansible_product_version": "1.2",
"ansible_python_version": "2.6.6",
"ansible_selinux": false,
"ansible_ssh_host_key_dsa_public": "...",
"ansible_ssh_host_key_rsa_public": "...",
"ansible_swapfree_mb": 2559,
"ansible_swaptotal_mb": 2559,
"ansible_system": "Linux",
"ansible_system_vendor": "innotek GmbH",
"ansible_user_id": "vagrant",
"ansible_userspace_architecture": "x86_64",
"ansible_userspace_bits": "64",
"ansible_virtualization_role": "guest",
"ansible_virtualization_type": "virtualbox",
"facter_architecture": "x86_64",
"facter_augeasversion": "0.9.0",
"facter_blockdevice_sda_model": "VBOX HARDDISK",
"facter_blockdevice_sda_size": 536870912000,
"facter_blockdevice_sda_vendor": "ATA",
"facter_blockdevice_sr0_model": "CD-ROM",
"facter_blockdevice_sr0_size": 1073741312,
"facter_blockdevice_sr0_vendor": "VBOX",
"facter_blockdevice_sr1_model": "CD-ROM",
"facter_blockdevice_sr1_size": 1073741312,
"facter_blockdevice_sr1_vendor": "VBOX",
"facter_blockdevices": "sda,sr0,sr1",
"facter_facterversion": "1.7.0",
"facter_filesystems": "ext4,iso9660",
"facter_hardwareisa": "x86_64",
"facter_hardwaremodel": "x86_64",
"facter_hostname": "localhost",
"facter_id": "vagrant",
"facter_interfaces": "eth0,eth1,lo",
"facter_ipaddress": "10.0.2.15",
"facter_ipaddress_eth0": "10.0.2.15",
"facter_ipaddress_eth1": "192.168.33.12",
"facter_ipaddress_lo": "127.0.0.1",
"facter_is_virtual": "true",
"facter_kernel": "Linux",
"facter_kernelmajversion": "2.6",
"facter_kernelrelease": "2.6.32-358.el6.x86_64",
"facter_kernelversion": "2.6.32",
"facter_macaddress": "08:00:27:C9:39:9E",
"facter_macaddress_eth0": "08:00:27:C9:39:9E",
"facter_macaddress_eth1": "08:00:27:D5:DA:B6",
"facter_memoryfree": "366.08 MB",
"facter_memoryfree_mb": "366.08",
"facter_memorysize": "458.64 MB",
"facter_memorysize_mb": "458.64",
"facter_memorytotal": "458.64 MB",
"facter_mtu_eth0": "1500",
"facter_mtu_eth1": "1500",
"facter_mtu_lo": "16436",
"facter_netmask": "255.255.255.0",
"facter_netmask_eth0": "255.255.255.0",
"facter_netmask_eth1": "255.255.255.0",
"facter_netmask_lo": "255.0.0.0",
"facter_network_eth0": "10.0.2.0",
"facter_network_eth1": "192.168.33.0",
"facter_network_lo": "127.0.0.0",
"facter_operatingsystem": "CentOS",
"facter_operatingsystemmajrelease": "6",
"facter_operatingsystemrelease": "6.4",
"facter_osfamily": "RedHat",
"facter_path": "/usr/local/bin:/bin:/usr/bin",
"facter_physicalprocessorcount": 1,
"facter_processor0": "Intel(R) Core(TM) i3-3217U CPU @ 1.80GHz",
"facter_processorcount": "1",
"facter_ps": "ps -ef",
"facter_puppetversion": "3.1.1",
"facter_rubysitedir": "/usr/lib/ruby/site_ruby/1.8",
"facter_rubyversion": "1.8.7",
"facter_selinux": "false",
"facter_sshdsakey": "...",
"facter_sshfp_dsa": "SSHFP 2 1 ...\nSSHFP 2 2 ...",
"facter_sshfp_rsa": "SSHFP 1 1 ...\nSSHFP 1 2 ...",
"facter_sshrsakey": "...",
"facter_swapfree": "2.50 GB",
"facter_swapfree_mb": "2559.99",
"facter_swapsize": "2.50 GB",
"facter_swapsize_mb": "2559.99",
"facter_timezone": "UTC",
"facter_uniqueid": "007f0100",
"facter_uptime": "1:09 hours",
"facter_uptime_days": 0,
"facter_uptime_hours": 1,
"facter_uptime_seconds": 4195,
"facter_virtual": "virtualbox"
},
"changed": false
}
このようにして収集したデータを task のオプションやテンプレートの変数に使うことができます。
- IP Address は
{{ansible_eth0.ipv4.address}}のようにして使えますtasks: - name: gathering data task example command: echo {{ansible_eth0.ipv4.address}} {{ansible_processor_count * 5}}と計算結果を使うこともできます。CPUのコア数を元にプロセス数を設定したりする場合に使えます。- 次のようにして task 実行の条件判定にも使えます
tasks: - name: "shutdown Debian flavored systems" command: /sbin/shutdown -t now when: ansible_os_family == "Debian"
gather_facts: no とすることで収集しないことで playbook の実行時間を短縮できます。
- hosts: all
sudo: yes
gather_facts: no
roles:
- common
7. Best Plactices に沿った構成を真似る
Best Practices のディレクトリ構成にならって WordPress サーバーを構築する Playbook を作成します。
ここは長くなりそうだから詳細は別ページにしよう。
こんなディレクトリ構成で進めます。playbook branch のファイルで一応動作すると思います。随時改善していきます。
このファイルは https://github.com/yteraoka/ansible-tutorial/archive/playbook.zip からダウンロードできます。
$ tree
.
├── common.yml
├── group_vars
├── host_vars
├── roles
│ ├── common
│ │ ├── files
│ │ ├── handlers
│ │ │ └── main.yml
│ │ ├── tasks
│ │ │ ├── common-packages.yml
│ │ │ ├── epel.yml
│ │ │ ├── main.yml
│ │ │ ├── ntp.yml
│ │ │ └── sshd.yml
│ │ ├── templates
│ │ └── vars
│ └── wordpress
│ ├── files
│ │ └── wordpress-3.5.2-ja.zip
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ ├── httpd.yml
│ │ ├── main.yml
│ │ ├── mysql.yml
│ │ ├── php.yml
│ │ └── wordpress.yml
│ ├── templates
│ │ ├── httpd.conf.j2
│ │ └── wp-config.php.j2
│ └── vars
│ └── main.yml
├── site.yml
├── test-servers
└── wordpress.yml
15 directories, 20 files
タスクの一覧を確認するには次のように --list-tasks オプションをつけて ansible-playboook コマンドを実行します。
$ ansible-playbook --list-tasks site.yml
playbook: site.yml
play #1 (all): task count=7
be sure epel repository is installed
be sure common packages are installed
configure sshd_config
be sure ntpd is running and enabled
Please enter MySQL wordpress user password:
play #2 (wordpress): task count=19
be sure httpd is installed
create document root
be sure httpd is configured
remove httpd welcome.conf
be sure httpd is running and enabled
be sure mysql-server is installed
be sure mysqldb is installed
be sure mysqld is running and enabled
Create database
Create database user
be sure php is installed
be sure php-mysql is installed
disable password authentication
copy wordpress zip file
unzip wordpress zip file
configure wp-config.php
(随時更新しているため↑この内容は現在の repository のものとはずれてる場合があります)
実際の実行は次のコマンドになります。
$ ansible-playbook -i test-servers site.yml
7.1. 各ディレクトリ、ファイルの役割・意味
数種類のサービスが Web - App - DB 構成(それぞれは Role)で構築されており、それぞれに2ヶ所のロケーションにあるとする(Multi-AZみたいな)
- group_vars/
- グループ毎の変数を定義するのに使います、role ではありません、role 毎の変数は roles/{role_name}/vars/ を使います。例えばロケーション毎に異なる変数など。ファイル名はインベントリファイルで設定するグループ名です。インベントリファイルにグループ変数を書くことも可能です。
- host_vars/
- ホスト毎の変数を定義するのに使います。group_vars と同じくファイル名はインベントリファイルに設定したホスト名です。インベントリファイルの中でホスト名の右に並べて書くこともできます。
- roles/
- このディレクトリの下に role (役割) 毎のディレクトリを作成し、それぞれの role にさらに
files/,handlers/,tasks/,templates/,vars/というサブディレクトリを作成します。 - roles/*/files/
- 当該 role の task で使うファイル関連モジュール (file, copy) が src として使うファイルの置き場所。任意のファイル名で置きます。
- roles/*/handlers/
- 設定変更後にサービスの再起動をさせたりする場合に、notify という定義で処理を呼び出しますが、その呼び出されるハンドラをここで定義します。main.yml というファイルで作成しますが、
includeという定義で複数ファイルをそこから読み込ませることが可能です。 - roles/*/tasks/
- 何かをインストールしたり、ユーザーを作成したりする task 定義のファイルをここに置きます。handlers と同じように mail.yml というファイルが起点となります。
- roles/*/templates/
- template モジュールで利用するテンプレートファイルを置きます。このモジュールでは Jinja2 (神社) というテンプレートエンジンが使われていて
.j2とうい拡張子を使います。 - roles/*/vars/
- role 毎に設定する変数を定義するファイルを置きます。handlers や tasks と同じく main.yml ファイルが起点となります。
- sites.yml
ansible-playbookコマンドに渡す大元 (root) の playbook ファイルです。- test-servers
- 今回のインベントリファイルです。実際の運用では development, stage, production などというそれぞれの環境毎のファイルにするのが Best Practice っぽいです。
- wordpress.yml
- role 毎の対象グループ、対象ホストなどを定義します。今回は wordpress サーバーをセットアップする wordpress role とするため、このファイル名としてあります。site.yml で include されています。
7.2. リスト変数を使った処理
roles/common/tasks/common-packages.yml を見てみましょう。
- name: be sure common packages are installed
yum: name={{item}} state=installed
with_items:
- ntp
- bind-utils
- unzip
tags: common-packages
with_items にインストールされているべきパッケージ名を並べ、それぞれを yum モジュールで処理します。
tags を指定しておくと ansible-playbook の --tags オプションを使うことで指定の tag のついた task だけを実行可能。複数の task に同じ tag を付けられます。roles/common/tasks/sshd.yml でも sshd_config の複数行の編集をまとめるために with_items を使っています。
- name: configure sshd_config
lineinfile: dest=/etc/ssh/sshd_config owner=root group=root mode=0600 backup=yes {{item}}
with_items:
- regexp='^PasswordAuthentication' line='PasswordAuthentication no' insertafter='PasswordAuthentication no'
- regexp='^PermitRootLogin' line='PermitRootLogin no' insertafter='#PermitRootLogin'
- regexp='^GSSAPIAuthentication' line='GSSAPIAuthentication no' insertafter='#GSSAPIAuthentication'
notify: restart sshd
tags: sshd
それぞれ別の task にしてしまうと notify によて3度も sshd の restart が必要になってしまう...と思ったら、別々にしても notify は一度しか処理されませんでした。よって、こういう場合はわかりやすい書き方を選ぶのが良いでしょう。lineinfile モジュールは設定ファイルの置換に便利です。insertafter や backref オプションは要チェックです。
7.3. MySQL 関連
パッケージのインストールだけでなく、DBの作成、ユーザーの作成も行えます。
# yum で mysql-server パッケージをインストール
- name: be sure mysql-server is installed
yum: pkg=mysql-server state=installed
tags: mysqld
# mysql_user で必要な python モジュールをインストールする
- name: be sure mysqldb is installed
yum: pkg=MySQL-python state=installed
tags: mysqld
# mysqld の起動、自動起動設定
- name: be sure mysqld is running and enabled
service: name=mysqld state=running enabled=yes
tags: mysqld
# wordpress 用 DB の作成
- name: Create database
action: mysql_db db={{dbname}} state=present
tags: mysqld
# wordpress 用 DB ユーザーの作成
- name: Create database user
action: mysql_user name=${dbuser} password=${dbpassword} priv=${dbname}.*:ALL state=present
tags: mysqld
dbname, dbuser 変数は roles/wordpress/vars/main.yml に書いてあり、dbpassword は wordpress.yml にて次のように vas_prompt 設定し、ansible-playbook 実行時に入力させている。
- hosts: wordpress
sudo: yes
roles:
- wordpress
vars_prompt:
- name: "dbpassword"
prompt: "Please enter MySQL wordpress user password"
default: "wordpress"
8. serverspec でテストする
8.1. Ruby のインストール
CentOS 6 はいまだに 1.8.7 だから最新のバージョンを /opt/ruby-2.0.0 にインストール
まずは Ruby のコンパイルに必要なものをインストール
$ sudo yum -y install git gcc gcc-c++ make patch readline-devel zlib-devel libyaml-devel
ruby-build を git clone する
$ git clone -q git://github.com/sstephenson/ruby-build.git
2.0.0-p247 をインストール
$ cd ruby-build
$ sudo bin/ruby-build 2.0.0-p247 /opt/ruby-2.0.0
Tea Time...Ruby や Perl のコンパイルには結構時間がかかりますねぇ。
8.2. ServerSpec のインストール
$ sudo /opt/ruby-2.0.0/bin/gem install serverspec
あ、bundler 使ったほうが良かったかな?
8.3. ServerSpec を実行してみる
まずはserverspec-init コマンドで土台を作ります。
$ /opt/ruby-2.0.0/bin/serverspec-init
Select a backend type:
1) SSH
2) Exec (local)
Select number: 1
Vagrant instance y/n: n
Input target host name: 192.168.33.12
+ spec/
+ spec/192.168.33.12/
+ spec/192.168.33.12/httpd_spec.rb
+ spec/spec_helper.rb
+ Rakefile
Vagrant 使ってるけど、Vagrant の Guest 同士での SSH だから Vagrant じゃないよと。今回の設定では httpd.conf の ServerName は localhost となっているのでテストをちょっといじる
$ sed -i 's/192.168.33.12/localhost/' spec/192.168.33.12/httpd_spec.rb
それでは rake コマンドでテストを実行してみましょう
$ /opt/ruby-2.0.0/bin/rake spec
/opt/ruby-2.0.0/bin/ruby -S rspec spec/192.168.33.12/httpd_spec.rb
/opt/ruby-2.0.0/bin/ruby: No such file or directory -- rspec (LoadError)
rake aborted!
/opt/ruby-2.0.0/bin/ruby -S rspec spec/192.168.33.12/httpd_spec.rb failed
Tasks: TOP => spec
(See full trace by running task with --trace)
あらら、失敗。PATH の問題っぽい。
$ PATH=/opt/ruby-2.0.0/bin:$PATH
$ /opt/ruby-2.0.0/bin/rake spec
/opt/ruby-2.0.0/bin/ruby -S rspec spec/192.168.33.12/httpd_spec.rb
......
Finished in 0.62573 seconds
6 examples, 0 failures
成功しました。spec/192.168.33.12/httpd_spec.rb に書いてあるテストが実行されました。内容は次の通り
- httpd パッケージがインストールされていること
- httpd サービスが有効になっていること (
chkconfig httpd on状態) - httpd が起動していること
- ポート 80 が LISTEN 状態となっていること
/etc/httpd/conf/httpd.confファイルが存在すること- httpd.conf に "ServerName localhost" が含まれること
8.4. mysqld のテストを作成
httpd_spec.rb を参考に mysqld のテストを作成しましょう。
これは JTF のパクリですね とまったく同じ課題ですね。
- mysql-server パッケージがインストールされていること
- mysqld デーモンが有効化されていること (chkconfig mysqld on されていること)
- mysqld デーモンが起動していること
- 3306 ポートが LISTEN していること
$ vi spec/192.168.33.12/mysqld_spec.rb
(例はこちら: https://gist.github.com/yteraoka/6156753)
8.5. WordPress のテストを作成
Chef 版との違いが出ましたよ。WordPress が日本語版だったので出力されるHTMLが日本語です。
http://localhost/wp-admin/install.php にアクセスすると出力されるメッセージ(HTML)に「5分でできる WordPress の有名なインストールプロセスへようこそ」が含まれることをチェックしましょう。
あぁぁ、ServerSpec の command 出力を日本語でマッチさせる方法がわからん...ただ、日本語文字列のコピペをミスっていただけでした...
誰か教えてくださいまし。
$ vi spec/192.168.33.12/wordpress_spec.rb
(例はこちら: https://gist.github.com/yteraoka/6186278)
9. もっと知る
ansible-in-detail.html にモジュールの説明や細かいことを書いています。