fbpx

CL LAB

HOME > CL LAB > Ansibleを試す #ansible

Ansibleを試す #ansible

 ★ 15

Ansibleとは

Ansibleは、ソフトウェアのデプロイを簡単にして楽をしよう、という概念のツールです。About Ansibleでは次のように述べられています。

Ansible is a powerful automation engine that makes systems and applications simple to deploy. 
No custom scripting or custom code. No agents. All using an automation language that’s easy for anyone to understand and learn. Just get in, get it done, and make some time for other strategic projects.

[和訳]: Ansibleはシステムとアプリケーションを簡単にデプロイできるようにするための強力な自動化エンジンです。独自スクリプトや独自コードは不要。エージェントも不要。誰にとっても理解しやすく学びやすい自動化言語を用いています。さっと入れて、さっと片付けて、空いた時間を他の戦略的なプロジェクトに使いましょう。

このように、手間と時間をなるべく減らすことを理想としています。

なお、Ansibleとは、最近実写映画化もされたオースン・スコット・カードによるSF小説「エンダーのゲーム」(1985)に登場する恒星間超高速通信システムに由来し、さらに出自をたどると「ゲド戦記」などで著名なアーシュラ・K・ル=グウィンがSF小説「ロカノンの世界」(1966)で「answerable」から創り出した言葉です。

Ansibleのインストール

Installation | Ansible Documentationを参考に、Ubuntu 14.04 LTSにAnsibleをインストールします。

Ubuntu 14.04 LTSに含まれているAnsibleは2014/04当時最新の1.5.4なので、AnsibleのPPAから最新版をインストールすることにします。

ubuntu@ws:~$ sudo apt-get install software-properties-common
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
software-properties-common は既に最新バージョンです。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 0 個。
ubuntu@ws:~$
ubuntu@ws:~$ sudo apt-add-repository ppa:ansible/ansible
 Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy. Avoid writing scripts or custom code to deploy and update your applications— automate in a language that approaches plain English, using SSH, with no agents to install on remote systems.

http://ansible.com/
 詳しい情報: https://launchpad.net/~ansible/+archive/ubuntu/ansible
[ENTER] を押すと続行します。ctrl-c で追加をキャンセルできます

gpg: 鍵輪「/tmp/tmpsi6wdi4t/secring.gpg」ができました
gpg: 鍵輪「/tmp/tmpsi6wdi4t/pubring.gpg」ができました
gpg: 鍵7BB9C367をhkpからサーバーkeyserver.ubuntu.comに要求
gpg: /tmp/tmpsi6wdi4t/trustdb.gpg: 信用データベースができました
gpg: 鍵7BB9C367: 公開鍵“Launchpad PPA for Ansible, Inc.”を読み込みました
gpg: 処理数の合計: 1
gpg:               読込み: 1  (RSA: 1)
OK
ubuntu@ws:~$
ubuntu@ws:~$ sudo apt-get update
    :
ubuntu@ws:~$
ubuntu@ws:~$ sudo apt-get install ansible
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下の特別パッケージがインストールされます:
  libgmp10 libyaml-0-2 python-crypto python-httplib2 python-jinja2
  python-markupsafe python-paramiko python-support python-yaml sshpass
提案パッケージ:
  python-crypto-dbg python-crypto-doc python-jinja2-doc
以下のパッケージが新たにインストールされます:
  ansible libgmp10 libyaml-0-2 python-crypto python-httplib2 python-jinja2
  python-markupsafe python-paramiko python-support python-yaml sshpass
アップグレード: 0 個、新規インストール: 11 個、削除: 0 個、保留: 0 個。
1,480 kB 中 661 kB のアーカイブを取得する必要があります。
この操作後に追加で 8,041 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
    :
    :
    :
python-support (1.0.15) を設定しています ...
python-markupsafe (0.18-1build2) を設定しています ...
python-jinja2 (2.7.2-2) を設定しています ...
python-yaml (3.10-4build4) を設定しています ...
python-crypto (2.6.1-4build1) を設定しています ...
python-paramiko (1.10.1-1git1build1) を設定しています ...
python-httplib2 (0.8-2build1) を設定しています ...
sshpass (1.05-1) を設定しています ...
ansible (1.7.2-1ppa~trusty) を設定しています ...
Processing triggers for libc-bin (2.19-0ubuntu6.3) ...
Processing triggers for python-support (1.0.15) ...
ubuntu@ws:~$

AnsibleはSSHを利用して対象のリモートノードの操作を行うので、SSH秘密鍵・公開鍵のペアを作成しておきます。ここではパスフレーズなしの鍵ペアを作成しています。

ubuntu@ws:~$ ssh-keygen -N ''
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa):
Created directory '/home/ubuntu/.ssh'.
Your identification has been saved in /home/ubuntu/.ssh/id_rsa.
Your public key has been saved in /home/ubuntu/.ssh/id_rsa.pub.
The key fingerprint is:
23:91:e6:d5:03:e3:cd:4f:b2:26:38:3b:10:2c:b7:32 ubuntu@ws.example.jp
The key's randomart image is:
+--[ RSA 2048]----+
|        o        |
|   .   o *       |
|  . + + o * .    |
|   o = +   *     |
|  E o = S o .    |
|   o . + +       |
|      o          |
|       .         |
|                 |
+-----------------+
ubuntu@ws:~$

当然ながら、対象のリモートノードはSSHデーモンが動作している必要があるので起動しておきます。また、先に作成した公開鍵をリモートノードにあらかじめ配置します。

ubuntu@node:~$ mkdir .ssh
ubuntu@node:~$ cat > .ssh/authorized_keys
ssh-rsa (省略) ubuntu@ws.example.jp
ubuntu@node:~$

加えて簡便のために、パスワードなしでsudoを実行してroot権限を得られるように、ログインアカウントに設定しておきましょう。

作業環境を作る

Ansibleを実行する環境とするディレクトリを作り、gitの管理下に置いておきます。このディレクトリ構造についてはBest Practicesがありますが、ここでは深く追従しません。

ubuntu@ws:~$ mkdir ansible-repo
ubuntu@ws:~$ cd ansible-repo
ubuntu@ws:~/ansible-repo$ git init
Initialized empty Git repository in /home/ubuntu/ansible-repo/.git/
ubuntu@ws:~/ansible-repo$

Ansibleではインベントリという設定ファイルに対象のノードを列挙します。インベントリファイルはINIファイル形式です。

ここではwsグループに192.168.122.209nodeグループに192.168.122.210を所属させるインベントリファイルをhostsという名前で作成しています。

ubuntu@ws:~/ansible-repo$ vi hosts
[ws]
192.168.122.209

[node]
192.168.122.210
ubuntu@ws:~/ansible-repo$

モジュールを使ってみる

Ansibleは多数のモジュールをあらかじめ組み込んでおり、後述するPlaybookを作らずともコマンドラインから作業させることが可能です。

pingモジュール

まずpingモジュールで対象のノードが応答するかを確認してみます。ansibleコマンドにてall -i hostsで対象のイベントリファイル記載のホストすべてに-m pingでpingモジュールを実行します。

ubuntu@ws:~/ansible-repo$ ansible all -i hosts -m ping
192.168.122.210 | success >> {
    "changed": false,
    "ping": "pong"
}

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

ubuntu@ws:~/ansible-repo$

successでモジュールの実行が成功したことを示しています。

デフォルトではインベントリファイルは/etc/ansible/hostsを読んでいるので-iオプションで指定してますが、環境変数ANSIBLE_HOSTSで指定することもできます。なお、デフォルトのインベントリファイル指定は/etc/ansible/ansible.cfgで行われています。

環境変数ANSIBLE_HOSTSを設定して、以降の入力を簡略化しましょう。

ubuntu@ws:~/ansible-repo$ export ANSIBLE_HOSTS=~/ansible-repo/hosts
ubuntu@ws:~/ansible-repo$

allですべてのノードではなく、インベントリのグループ名を指定することで、そのグループに所属するノードに対してのみ実行することもできます。

ubuntu@ws:~/ansible-repo$ ansible ws -m ping
192.168.122.209 | success >> {
    "changed": false,
    "ping": "pong"
}

ubuntu@ws:~/ansible-repo$ ansible node -m ping
192.168.122.210 | success >> {
    "changed": false,
    "ping": "pong"
}

ubuntu@ws:~/ansible-repo$

commandモジュール

commandモジュールは、ノードでコマンドを実行します。ここではuname -aコマンドを実行してみましょう。

ubuntu@ws:~/ansible-repo$ ansible all -m command -a 'uname -a'
192.168.122.209 | success | rc=0 >>
Linux ws.example.jp 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:30:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

192.168.122.210 | success | rc=0 >>
Linux node.example.jp 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:30:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

ubuntu@ws:~/ansible-repo$

実はデフォルトのモジュールはcommandなので、-m commandは省略できます。

ubuntu@ws:~/ansible-repo$ ansible all -a 'uname -a'
192.168.122.209 | success | rc=0 >>
Linux ws.example.jp 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:30:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

192.168.122.210 | success | rc=0 >>
Linux node.example.jp 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:30:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

ubuntu@ws:~/ansible-repo$

setupモジュール

setupモジュールは、ノードのfactsを収集します。factsとは、ノードに関するさまざまな情報です。

例えば、次のような情報が収集できます。

ubuntu@ws:~/ansible-repo$ ansible node -m setup
192.168.122.210 | success >> {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.122.210"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::5054:ff:fe8a:1832"
        ],
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "04/01/2014",
        "ansible_bios_version": "1.7.5-20140531_083030-gandalf",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/boot/vmlinuz-3.13.0-39-generic",
            "ro": true,
            "root": "UUID=b93f22cb-54e4-4332-bf41-b05b33cf2374"
        },
        "ansible_date_time": {
            "date": "2014-11-14",
            "day": "14",
            "epoch": "1415937170",
            "hour": "12",
            "iso8601": "2014-11-14T03:52:50Z",
            "iso8601_micro": "2014-11-14T03:52:50.004783Z",
            "minute": "52",
            "month": "11",
            "second": "50",
            "time": "12:52:50",
            "tz": "JST",
            "tz_offset": "+0900",
            "weekday": "\u91d1\u66dc\u65e5",
            "year": "2014"
        },
        "ansible_default_ipv4": {
            "address": "192.168.122.210",
            "alias": "eth0",
            "gateway": "192.168.122.1",
            "interface": "eth0",
            "macaddress": "52:54:00:8a:18:32",
            "mtu": 1500,
            "netmask": "255.255.255.0",
            "network": "192.168.122.0",
            "type": "ether"
        },
        "ansible_default_ipv6": {},
        "ansible_devices": {
            "vda": {
                "holders": [],
                "host": "SCSI storage controller: Red Hat, Inc Virtio block device",
                "model": null,
                "partitions": {
                    "vda1": {
                        "sectors": "20967424",
                        "sectorsize": 512,
                        "size": "10.00 GB",
                        "start": "2048"
                    }
                },
                "removable": "0",
                "rotational": "1",
                "scheduler_mode": "",
                "sectors": "20971520",
                "sectorsize": "512",
                "size": "10.00 GB",
                "support_discard": "0",
                "vendor": "0x1af4"
            }
        },
        "ansible_distribution": "Ubuntu",
        "ansible_distribution_major_version": "14",
        "ansible_distribution_release": "trusty",
        "ansible_distribution_version": "14.04",
        "ansible_domain": "example.jp",
        "ansible_env": {
            "HOME": "/home/ubuntu",
            "LANG": "C",
            "LC_ALL": "ja_JP.UTF-8",
            "LC_CTYPE": "C",
            "LOGNAME": "ubuntu",
            "MAIL": "/var/mail/ubuntu",
            "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games",
            "PWD": "/home/ubuntu",
            "SHELL": "/bin/bash",
            "SHLVL": "1",
            "SSH_CLIENT": "192.168.122.209 49909 22",
            "SSH_CONNECTION": "192.168.122.209 49909 192.168.122.210 22",
            "SSH_TTY": "/dev/pts/2",
            "TERM": "xterm-color",
            "USER": "ubuntu",
            "XDG_RUNTIME_DIR": "/run/user/1000",
            "XDG_SESSION_ID": "5",
            "_": "/bin/sh"
        },
        "ansible_eth0": {
            "active": true,
            "device": "eth0",
            "ipv4": {
                "address": "192.168.122.210",
                "netmask": "255.255.255.0",
                "network": "192.168.122.0"
            },
            "ipv6": [
                {
                    "address": "fe80::5054:ff:fe8a:1832",
                    "prefix": "64",
                    "scope": "link"
                }
            ],
            "macaddress": "52:54:00:8a:18:32",
            "mtu": 1500,
            "promisc": false,
            "type": "ether"
        },
        "ansible_form_factor": "Other",
        "ansible_fqdn": "node.example.jp",
        "ansible_hostname": "node",
        "ansible_interfaces": [
            "lo",
            "eth0"
        ],
        "ansible_kernel": "3.13.0-39-generic",
        "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": 65536,
            "promisc": false,
            "type": "loopback"
        },
        "ansible_lsb": {
            "codename": "trusty",
            "description": "Ubuntu 14.04.1 LTS",
            "id": "Ubuntu",
            "major_release": "14",
            "release": "14.04"
        },
        "ansible_machine": "x86_64",
        "ansible_memfree_mb": 7660,
        "ansible_memtotal_mb": 7985,
        "ansible_mounts": [
            {
                "device": "/dev/vda1",
                "fstype": "ext4",
                "mount": "/",
                "options": "rw,errors=remount-ro",
                "size_available": 9119244288,
                "size_total": 10432602112
            }
        ],
        "ansible_nodename": "node.example.jp",
        "ansible_os_family": "Debian",
        "ansible_pkg_mgr": "apt",
        "ansible_processor": [
            "Intel Xeon E312xx (Sandy Bridge)"
        ],
        "ansible_processor_cores": 1,
        "ansible_processor_count": 1,
        "ansible_processor_threads_per_core": 1,
        "ansible_processor_vcpus": 1,
        "ansible_product_name": "Standard PC (i440FX + PIIX, 1996)",
        "ansible_product_serial": "NA",
        "ansible_product_uuid": "NA",
        "ansible_product_version": "pc-i440fx-2.1",
        "ansible_python_version": "2.7.6",
        "ansible_selinux": false,
        "ansible_ssh_host_key_dsa_public": "(省略)",
        "ansible_ssh_host_key_ecdsa_public": "(省略)",
        "ansible_ssh_host_key_rsa_public": "(省略)",
        "ansible_swapfree_mb": 0,
        "ansible_swaptotal_mb": 0,
        "ansible_system": "Linux",
        "ansible_system_vendor": "QEMU",
        "ansible_user_id": "ubuntu",
        "ansible_userspace_architecture": "x86_64",
        "ansible_userspace_bits": "64",
        "ansible_virtualization_role": "NA",
        "ansible_virtualization_type": "NA",
        "module_setup": true
    },
    "changed": false
}

ubuntu@ws:~/ansible-repo$

Playbookを作る

Ansibleの手続きを記載したファイルをPlaybookと呼びます。PlaybookはYAML形式で、Ansible独自の手続き言語を記述します。

パッケージを1つインストールする

次はインベントリファイルのすべてのノードに対して、sudoコマンドでroot権限を得て、最新のntpパッケージをaptでインストールするというPlaybookです。

ubuntu@ws:~/ansible-repo$ vi ntp.yml
---
- hosts
: all
  sudo
: yes

  tasks
:
  - name
: install latest ntp package
    apt
: pkg=ntp state=latest
ubuntu@ws:~/ansible-repo$

Playbookの適用にはansible-playbookコマンドを用います。適用前に-Cオプションでdry-runしてみます。

ubuntu@ws:~/ansible-repo$ ansible-playbook -C ntp.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

TASK: [install latest ntp package] ********************************************
changed: [192.168.122.209]
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=1    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

すべてのノードで問題なさそうなことがわかったので、-Cオプションを除いて実際に適用してみます。

ubuntu@ws:~/ansible-repo$ ansible-playbook ntp.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

TASK: [install latest ntp package] ********************************************
changed: [192.168.122.209]
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=1    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

changedはPlaybookの適用が成功して変更があったことを示しています。べき等性の確認のためもう1回適用してみます。

ubuntu@ws:~/ansible-repo$ ansible-playbook ntp.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

TASK: [install latest ntp package] ********************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=0    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=0    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

変更がなかったためchangedが増えていません。

さらにべき等性の確認のため、アンインストールしてもう1回実行してみます。
アンインストールはcommandモジュールを用いて行います。--sudoはsudoコマンドでroot権限を得てコマンドを実行するというオプションです。

ubuntu@ws:~/ansible-repo$ ansible all -a 'apt-get purge -y ntp' --sudo
192.168.122.210 | success | rc=0 >>
    :
    :
    :
Removing ntp (1:4.2.6.p5+dfsg-3ubuntu2) ...
 * Stopping NTP server ntpd
   ...done.
Purging configuration files for ntp (1:4.2.6.p5+dfsg-3ubuntu2) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...

192.168.122.209 | success | rc=0 >>
    :
    :
    :
Removing ntp (1:4.2.6.p5+dfsg-3ubuntu2) ...
 * Stopping NTP server ntpd
   ...done.
Purging configuration files for ntp (1:4.2.6.p5+dfsg-3ubuntu2) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...

ubuntu@ws:~/ansible-repo$
ubuntu@ws:~/ansible-repo$ ansible-playbook ntp.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

TASK: [install latest ntp package] ********************************************
changed: [192.168.122.209]
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=1    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

再びchangedがカウントされてPlaybookの適用が成功しました。

パッケージを複数インストールする

最新のnginxパッケージとredis-serverパッケージをそれぞれaptでインストールするPlaybookです。

ubuntu@ws:~/ansible-repo$ vi multi_pkgs.yml
---
- hosts
: node
  sudo
: yes

  tasks
:
  - name
: install latest nginx package
    apt
: pkg=nginx state=latest
  - name
: install latest redis-server package
    apt
: pkg=redis-server state=latest
ubuntu@ws:~/ansible-repo$
ubuntu@ws:~/ansible-repo$ ansible-playbook multi_pkgs.yml

PLAY [node] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]

TASK: [install latest nginx package] ******************************************
changed: [192.168.122.210]

TASK: [install latest redis-server package] ***********************************
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.210            : ok=3    changed=2    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

インストールできました。ここで、一旦アンインストールしておきます。

ubuntu@ws:~/ansible-repo$ ansible node -a 'apt-get purge -y nginx redis-server' --sudo
    :

ループを用いて書き直してみます。

ubuntu@ws:~/ansible-repo$ vi multi_pkgs.yml
---
- hosts: node

  sudo: yes
 
  tasks:
    apt: pkg={{ item }} state=latest
    with_items:
    - nginx
    - redis-server
ubuntu@ws:~/ansible-repo$
ubuntu@ws:~/ansible-repo$ ansible-playbook multi_pkgs.yml

PLAY [node] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]

TASK: [install latest packages] ***********************************************
changed: [192.168.122.210] => (item=nginx,redis-server)

PLAY RECAP ********************************************************************
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

インストールできました。ループを用いなかった場合でのchangedの数の違いに注目してください。

テンプレートを用いる

AnsibleはエンジンにJinja2を用いたテンプレートが利用できます。Jinjaとはそのまま「神社」のことで、templateとtempleの発音が似ていることに由来しているそうです。「神社」は本当はtempleではなくshrineなのですがここでは目をつぶります。

変数から得た値(Hello, World!)をテンプレート(tmpl.hello.j2)中に埋め込み、ファイル(/tmp/hello.txt)として出力するPlaybookです。

ubuntu@ws:~/ansible-repo$ vi tmpl.yml
---
- hosts
: all
  sudo
: yes
  vars
:
    message
: Hello, World!

  tasks
:
  - name
: put hello file
    template
: src=tmpl.hello.j2 dest=/tmp/hello.txt
ubuntu@ws:~/ansible-repo$
ubuntu@ws:~/ansible-repo$ vi tmpl.hello.j2
"{{ message }}"
ubuntu@ws:~/ansible-repo$

ノードに適用します。

ubuntu@ws:~/ansible-repo$ ansible-playbook tmpl.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]
ok: [192.168.122.209]

TASK: [put hello file] ********************************************************
changed: [192.168.122.209]
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=1    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

ファイルが作成できたことを確認します。

ubuntu@ws:~/ansible-repo$ ansible all -a 'cat /tmp/hello.txt'
192.168.122.210 | success | rc=0 >>
"Hello, World!"

192.168.122.209 | success | rc=0 >>
"Hello, World!"

ubuntu@ws:~/ansible-repo$

テンプレートにはfactsで収集した値を埋め込むこともできます。ここではansible_fqdnを埋め込みます。

ubuntu@ws:~/ansible-repo$ git diff
diff --git a/tmpl.hello.j2 b/tmpl.hello.j2
index 763a6c7..c27197f 100644
--- a/tmpl.hello.j2
+++ b/tmpl.hello.j2
@@ -1 +1 @@
-"{{ message }}"
+{{ ansible_fqdn }} says "{{ message }}"
ubuntu@ws:~/ansible-repo$

ノードに適用します。

ubuntu@ws:~/ansible-repo$ ansible-playbook tmpl.yml

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.209]
ok: [192.168.122.210]

TASK: [put hello file] ********************************************************
changed: [192.168.122.209]
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.209            : ok=2    changed=1    unreachable=0    failed=0  
192.168.122.210            : ok=2    changed=1    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

ファイルが作成できたことを確認します。

ubuntu@ws:~/ansible-repo$ ansible all -a 'cat /tmp/hello.txt'
192.168.122.209 | success | rc=0 >>
ws.example.jp says "Hello, World!"

192.168.122.210 | success | rc=0 >>
node.example.jp says "Hello, World!"

ubuntu@ws:~/ansible-repo$

サービス間の通信

notifyhandlersを用いることで、設定ファイルに変更があったらサービスを再起動するといった手続きを実現できます。

nginxの最新パッケージをaptでインストールし、待ち受けポート番号(listen_portのみが変更できる設定ファイル(/etc/nginx/sites-available/default)を設置するPlaybookです。

ubuntu@ws:~/ansible-repo$ vi nginx.yml
---
- hosts
: node
  sudo
: yes
  vars
:
    listen_port
: 80

  tasks
:
  - name
: install nginx latest packages
    apt
: pkg=nginx state=latest
  - name
: write default site file
    template
: src=nginx.default.j2 dest=/etc/nginx/sites-available/default
    notify
:
   - restart nginx
  - name
: ensure nginx is running
    service
: name=nginx state=started

  handlers
:
  - name
: restart nginx
    service
: name=nginx state=restarted
ubuntu@ws:~/ansible-repo$

設定ファイルのテンプレートです。

ubuntu@ws:~/ansible-repo$ vi nginx.default.j2
#
# Generated by Ansible for {{ ansible_fqdn }}
#

server {
    listen {{ listen_port }} default_server;
    listen [::]:{{ listen_port }} default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    server_name localhost;

    location / {
        try_files $uri $uri/ =404;
    }
}
ubuntu@ws:~/ansible-repo$

ノードに適用します。

ubuntu@ws:~/ansible-repo$ ansible-playbook nginx.yml

PLAY [node] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]

TASK: [install nginx latest packages] *****************************************
ok: [192.168.122.210]

TASK: [write default site file] ***********************************************
changed: [192.168.122.210]

TASK: [ensure nginx is running] ***********************************************
ok: [192.168.122.210]

NOTIFIED: [restart nginx] *****************************************************
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.210            : ok=5    changed=2    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

パッケージインストール、設定ファイルの変更、再起動が行われました。設定通りの80番ポートにアクセスできることを確認します。

ubuntu@ws:~/ansible-repo$ curl http://node 2> /dev/null | head -5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
ubuntu@ws:~/ansible-repo$

Playbookのポート番号を変更します。

ubuntu@ws:~/ansible-repo$ git diff
diff --git a/nginx.yml b/nginx.yml
index 16cc803..f8474d4 100644
--- a/nginx.yml
+++ b/nginx.yml
@@ -2,7 +2,7 @@
 - hosts: node
   sudo: yes
   vars:
-    listen_port: 80
+    listen_port: 8080
 
   tasks:
   - name: install nginx latest packages
ubuntu@ws:~/ansible-repo$

変更したPlaybookをノードに適用します。

ubuntu@ws:~/ansible-repo$ ansible-playbook nginx.yml

PLAY [node] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]

TASK: [install nginx latest packages] *****************************************
ok: [192.168.122.210]

TASK: [write default site file] ***********************************************
changed: [192.168.122.210]

TASK: [ensure nginx is running] ***********************************************
ok: [192.168.122.210]

NOTIFIED: [restart nginx] *****************************************************
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.210            : ok=5    changed=2    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

設定ファイルの変更と再起動のみが行われました。設定通りの8080番ポートにアクセスできることを確認します。

ubuntu@ws:~/ansible-repo$ curl http://node
curl: (7) Failed to connect to node port 80: 接続を拒否されました
ubuntu@ws:~/ansible-repo$

ubuntu@ws:~/ansible-repo$ curl http://node:8080 2> /dev/null | head -5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
ubuntu@ws:~/ansible-repo$

また、Playbookでよく変更するような部分は別ファイルに切り出すことができます。ここではlisten_port.ymlとして待ち受けポート設定部分を別ファイルに切り出します。

ubuntu@ws:~/ansible-repo$ git diff
diff --git a/nginx.yml b/nginx.yml
index f8474d4..c3b11fd 100644
--- a/nginx.yml
+++ b/nginx.yml
@@ -1,8 +1,8 @@
 ---
 - hosts: node
   sudo: yes
-  vars:
-    listen_port: 8080
+  vars_files:
+  - listen_port.yml
 
   tasks:
   - name: install nginx latest packages
ubuntu@ws:~/ansible-repo$
ubuntu@ws:~/ansible-repo$ cat listen_port.yml
listen_port
: 8888
ubuntu@ws:~/ansible-repo$

この状態でノードに適用してみます。

ubuntu@ws:~/ansible-repo$ ansible-playbook nginx.yml

PLAY [node] *******************************************************************

GATHERING FACTS ***************************************************************
ok: [192.168.122.210]

TASK: [install nginx latest packages] *****************************************
ok: [192.168.122.210]

TASK: [write default site file] ***********************************************
changed: [192.168.122.210]

TASK: [ensure nginx is running] ***********************************************
ok: [192.168.122.210]

NOTIFIED: [restart nginx] *****************************************************
changed: [192.168.122.210]

PLAY RECAP ********************************************************************
192.168.122.210            : ok=5    changed=2    unreachable=0    failed=0  

ubuntu@ws:~/ansible-repo$

設定ファイルの変更と再起動のみが行われました。設定通りの8888番ポートにアクセスできることを確認します。

ubuntu@ws:~/ansible-repo$ curl http://node:8888 2> /dev/null | head -5
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
ubuntu@ws:~/ansible-repo$

まとめ

Ansibleはその思想・理想通り、導入コスト・学習コストが低いことが特徴と言えるでしょう。Playbookを書かなくとも同梱のモジュールによって素早くちょっと使えることも利点と言えそうです。


CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post