Learning Ansible


# 概要
システムの大規模化や複雑化、サーバの構築や破棄が容易に行えるようになったことを受け、近年、サーバ構成(プロビジョニング)手順を自動化するための手段が注目を集めている。プロビジョニング手順を自動化するツールを総称して構成管理ツールと言い、代表的なものに[Puppet](http://puppetlabs.com/)や[Chef](https://www.chef.io/)、[Ansible](http://www.ansible.com/home)などがある。

本記事はAnsibleを初めて学ぶ人を対象に、Ansibleの基本的な使い方を解説する。

# 導入
## Ansibleとは
公式サイトより引用。

>アプリケーションのデプロイを容易にする構成管理自動化ツールである。
アプリケーションをデプロイするために専用のスクリプト／コードを書く必要は無く、平易な英語とSSHを使ってデプロイ作業を自動化できる。

## Ansibleの特徴

 * Ansibleの実行ファイル( **Playbook** と言う )は[YAML](http://magazine.rubyist.net/?0009-YAML)をベースとした構文であり、読み書きが容易である。

 * 必要なものはSSHとPython(2.5以上)のみで、クライアント側にAnsibleをインストールする必要はない。

 * 自分の好きな時にPlaybookを実行できる( Push-based )。

 * 冪等性(ある操作を何度行っても同じ結果が得られること)が保証されている。

# Ansibleを使ってみる
Jenkinsサーバの構築を例に、Ansibleの使用法を説明する。

## 動作環境
今回使用した環境は下記の通り。

 * OS X Yosemite 10.10.1

 * Vagrant 1.3.5

 * VirtualBox 4.3.6

VagrantとVirtualBoxのインストール方法がわからない方は、[Vagrant入門](http://qiita.com/MasayaMizuhara/items/791c2b713ac7d8c98123)を参考にインストールする。

## 仮想マシンの作成
本記事ではUbuntu14.10を使用する。

```
$ vagrant init ubuntu1410 https://cloud-images.ubuntu.com/vagrant/utopic/current/utopic-server-cloudimg-amd64-vagrant-disk1.box
```

続いてVagrantfileを下記のように編集する。

```Vagrantfile
  .
  .
  config.vm.define :vagrant1 do |node|
    node.vm.box = "Ubuntu1410"
    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 :vagrant2 do |node|
    node.vm.box = "Ubuntu1410"
    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
  .
  .

```

Vagrantfileの編集が終わったら仮想マシンを起動する。

```
$ vagrant up
```

仮想マシンの起動後、vagrant1からvagrant2へsshできるよう下記コマンドを実行する。

```
$ vagrant ssh-config vagrant1 >> ssh_config
$ vagrant ssh-config vagrant2 >> ssh_config
$ scp -F ssh_config ~/.vagrant.d/insecure_private_key vagrant1:.ssh/id_rsa
```

## Ansibleのインストール
作成した仮想マシンにAnsibleをインストールする。

```
$ vagrant ssh vagrant1
[vagrant@vagrant-ubuntu-utopic-64:~]$ sudo apt-get install -y python-pip
[vagrant@vagrant-ubuntu-utopic-64:~]$ sudo pip install ansible
```

## インベントリファイルの作成
インベントリファイルとは、対象サーバを登録するファイルのこと。
最も単純なインベントリファイルは、対象ホストを記載した下記のような形式になる。

```hosts
192.168.33.12
```

インベントリファイル(hosts)を作成したら上記ホスト(vagrant2)と疎通確認を行ってみる。

```
[vagrant@vagrant-ubuntu-utopic-64:~]$ ansible -i hosts 192.168.33.12 -m ping
```

下記のような応答が返ってくればOK。

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

また、下記のように対象ホストにグループ名をつけることもできる。

```hosts
[test]
192.168.33.12
```

グループ名をつけると下記のようにグループ名を指定してコマンドを実行することができる。

```
[vagrant@vagrant-ubuntu-utopic-64:~]$ ansible -i hosts test -m ping
```

グループ名は、下記のように、対象ホストが複数ある場合は便利だと思う。

```hosts
[test1]
host1.example.com
host2.example.com
host3.example.com

[test2]
host4.example.com
host5.example.com
```

### 疎通確認コマンドの補足
vagrant2との疎通確認に使用した下記コマンドの ```-i``` と ```-m``` について説明をする。

```
[vagrant@vagrant-ubuntu-utopic-64:~]$ ansible -i hosts test -m ping
```

```-i``` はhostsファイルを指定するオプションである。hostsファイルに記載したホスト以外に ```ansible``` コマンドを実行することはできない。

```-m``` は **モジュール** を指定するコマンドであり、今回はpingモジュールを指定している。モジュールとは **処理の最小単位** のこと。 ```ansible``` コマンドまたはPlaybookのタスク(後述)で指定したモジュールが処理対象のサーバに転送され、実行される。モジュールは自作することも可能。

## Playbookの作成と実行
**Playbook** とはモジュールの処理をまとめたもので、Chefでのレシピに相当する。

[Jenkins Debian packages](http://pkg.jenkins-ci.org/debian/)に記載のインストール手順を参考に、Ubuntu14.10にJenkinsをインストールするPlaybookを作成した(下記)。

```jenkins.yml
---
- hosts: test
  sudo: true
  user: vagrant
  tasks:
    - name: Add jenkins-key to my system.
      action: apt_key url=http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key state=present

    - name: Add entry in my /etc/apt/sources.list.
      action: apt_repository repo='deb http://pkg.jenkins-ci.org/debian binary/' state=present

    - name: Update my local package index and install jenkins.
      apt: name=jenkins state=latest update_cache=yes

    - name: Start jenkins service.
      service: name=jenkins state=started
```

Playbookを実行する前に下記コマンドで構文チェックを行う。

```
[vagrant@vagrant-ubuntu-utopic-64:~]$ ansible-playbook -i hosts jenkins.yml --syntax-check
```

構文エラーが無ければ下記出力が得られる。

```
playbook: jenkins.yml
```

Playbookに構文エラーが無ければ下記コマンドでPlaybookを実行する。

```
vagrant@vagrant-ubuntu-utopic-64:~$ ansible-playbook -i hosts jenkins.yml
```

下記出力が得られればJenkinsのインストールは完了。

```
PLAY [test] ******************************************************************* 

GATHERING FACTS *************************************************************** 
ok: [192.168.33.12]

TASK: [Add jenkins-key to my system.] ***************************************** 
changed: [192.168.33.12]

TASK: [Add entry in my /etc/apt/sources.list.] ******************************** 
changed: [192.168.33.12]

TASK: [Update my local package index and install jenkins.] ******************** 
changed: [192.168.33.12]

TASK: [Start jenkins service.] ************************************************ 
changed: [192.168.33.12]

PLAY RECAP ******************************************************************** 
192.168.33.12              : ok=5    changed=4    unreachable=0    failed=0
```

http://192.168.33.12:8080/ にアクセスするとJenkinsおじさんに会えるはず。

### jenkins.ymlの解説

#### hosts: test
対象のホストまたはグループを指定する。
今回はhostsファイルで指定した ```test``` というグループ名を指定している。

#### sudo: true
Playbookに記載したタスクをsudoを使って実行する。
デフォルトはrootユーザであるため、rootユーザとしてSSHできないUbuntuサーバを管理する場合はtrueを指定する必要がある。

#### tasks
実行したい処理の一覧。
本記事で紹介したPlaybookのタスクは[Jenkins Debian packages](http://pkg.jenkins-ci.org/debian/)に記載の4つの処理と、Jenkinsサービスを起動する処理の計5つのタスクから構成される。

各タスクはモジュール名とモジュールに渡す引数とで構成される。

```
- name: Update my local package index and install jenkins.
  apt: name=jenkins state=latest update_cache=yes
```

例えば上記タスクの場合、モジュール名と引数は下記のようになる。

 * モジュール ```name``` と引数 ```Update my local package index and install jenkins.``` 。
```name``` はオプションであるため、記載しなくても良い。記載するとコンソールに記載した文字が出力されるため、進捗を知ることができる。

 * モジュール ```apt``` と引数 ```name=jenkins state=latest update_cache=yes``` 。
これは、 **パッケージを更新( ```update_cache=yes``` )して最新版( ``state=latest``` )のjenkinsパッケージ( ```name=jenkins``` )をインストールすること** を表している。

また ```action``` は古いシンタックスで、モジュール名( ```apt_key``` )と引数( ```url=...``` )を指定する。これは下記と同じである。

```
- name: Add jenkins-key to my system.
  apt_key: url=http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key state=present
```

その他モジュールについては[公式ドキュメント](http://docs.ansible.com/modules.html)を参照。


#最後に
Jenkinsサーバを構築する例を題材に、Ansibleを使う際に必要となる最低限の知識を説明した。
本記事で紹介した内容はAnsibleが提供する機能のほんの一部であり、知っておくと便利な機能などがまだまだあると思うので、興味のある方は勉強してみると良いと思う。

#参考

 * [構成管理ツール Ansibleを使ってみる](http://dev.classmethod.jp/tool/ansible/)
 * [AnsibleをUbuntuのローカルで使う](http://qiita.com/itiut@github/items/e8b95ac9b9ea2a6ea701)