とにかく簡単にAnsible2を使い始めるためのチュートリアル

Ansibleを使い始めようと思ったのだが、Web上のチュートリアルは、やや古かったり、やたらとたくさんのディレクトリやファイルを作らせたりと、Ansibleの特徴とされているシンプルさが感じられず、うんざりしたのでこの記事をまとめています。触り始めたばかりのため、もし誤りがあればご指摘いただけると幸いです。

# 1. はじめに

## Ansibleとは？

この辺の情報はWebにいくらでもあるので、簡単に。。。

- Python製の構成管理ツールです。(「IT自動化ツール」というように、より汎用性を強調した説明もちらほら見かける)
- 似たようなツールとしては、ChefやPuppet、Itamaeなどがあります。
- スクリプトはyamlで書くので、Pythonの知識は必要ありません。
- シンプルで習得が容易であることがその特徴の一つとされています。（多分ChefやShellと比べて言ってるんだと思う）

## 用語の解説

まずはこの４つだけ頭に入れておきましょう

### ①対象ホスト

Ansibleで操作される対象となるマシン
Ansibleがインストールされている必要はありませんが、Python2.5以上がインストールされている必要はあります。
ここではVagrantで対象ホストを構築し、`ssh 192.168.33.10`でログインできるものとします。

### ②実行ホスト

対象ホストをAnsibleで操作するマシン
Ansibleがインストールされている必要があります。
ここではMacで動作確認しています。

### ③インベントリ

対象ホストの一覧を管理するファイルです。

### ④Playbook

対象ホストを操作するためのスクリプトです。
ChefやItamaeで言うところのレシピですね。

## 準備/前提条件

この辺の情報もWeb上にたくさんあるので、具体的な手順は省略させていただきます。

- Ansibleはインストールされているものとします
- Ansibleで操作される対象となるマシン(対象ホスト)がVagrantで構築されており、`ssh 192.168.33.10`でログインできること。(IPアドレスは適宜読み替えて下さい)
- 作業ディレクトリはVagrantfileが置いてあるディレクトリとします。

    ```
    $ python --version
    Python 2.7.10 --  64-bit 

    $ ansible --version
    ansible 2.0.2.0
      config file = 
      configured module search path = Default w/o overrides

    $ tree
    .
    ├── Vagrantfile
    ├── inventory.txt  # 後から作るファイルです
    └── playbook.yml   # 後から作るファイルです

	$ cat Vagrantfile 
	Vagrant.configure(2) do |config|
	  config.vm.box = "ubuntu/trusty64"
	  config.vm.network "private_network", ip: "192.168.33.10"
	  config.vm.network :forwarded_port, guest: 80, host: 8080
	end
    ```

# 1. ansibleコマンド

まずは、Playbookは使わずに、ansibleコマンドと呼ばれる一行コマンドで動作を見ていきます。

## 1.1. Hello world!

まずはお馴染みのHello worldで動作確認をしてみます。

```
# インベントリファイルを作成
$ echo 192.168.33.10 > ./inventory.txt

# ansibleコマンドを実行
$ ansible 192.168.33.10 -i ./inventory.txt -m shell -a "echo Hello world\!"
192.168.33.10 | SUCCESS | rc=0 >>
Hello world!
```

### 解説

#### -iオプション

インベントリファイルを指定します。

#### -mオプション

実行するモジュールを指定します。モジュールとはAnsibleで実行する処理のことで、ここでは`shell`を実行しています。文字通り、対象ホストで`shell`を実行します。`shell`以外にも`yum`や`service`、`file`などがあります。
[こちら](http://docs.ansible.com/ansible/modules_by_category.html)に一覧があるので必要に応じて調べてみてください。

#### -aオプション

実行モジュールの引数です。


## 1.2. Nginxをインストールする

最初の１行目が実行コマンドで、その後にズラズラっと出ているのが実行結果です。

```
$ ansible 192.168.33.10 -b -i ./inventory.txt -m apt -a "name=nginx state=latest"
192.168.33.10 | SUCCESS => {
    "cache_update_time": 0, 
    "cache_updated": false, 
    "changed": true, 
    "stderr": "", 
    "stdout": (stdout_linesと同じなので略), 
    "stdout_lines": [
        "Reading package lists...", 
        "Building dependency tree...", 
        "Reading state information...", 
        "The following extra packages will be installed:", 
        "  libxslt1.1 nginx-common nginx-core", 
        "Suggested packages:", 
        "  fcgiwrap nginx-doc", 
        "The following NEW packages will be installed:", 
        "  libxslt1.1 nginx nginx-common nginx-core", 
        "0 upgraded, 4 newly installed, 0 to remove and 3 not upgraded.", 
        "Need to get 494 kB of archives.", 
        "After this operation, 1795 kB of additional disk space will be used.", 
        "Get:1 http://archive.ubuntu.com/ubuntu/ trusty/main libxslt1.1 amd64 1.1.28-2build1 [145 kB]", 
        "Get:2 http://archive.ubuntu.com/ubuntu/ trusty-updates/main nginx-common all 1.4.6-1ubuntu3.4 [18.3 kB]", 
        "Get:3 http://archive.ubuntu.com/ubuntu/ trusty-updates/main nginx-core amd64 1.4.6-1ubuntu3.4 [325 kB]", 
        "Get:4 http://archive.ubuntu.com/ubuntu/ trusty-updates/main nginx all 1.4.6-1ubuntu3.4 [5616 B]", 
        "Fetched 494 kB in 4s (116 kB/s)", 
        "Selecting previously unselected package libxslt1.1:amd64.", 
        "(Reading database ... 65082 files and directories currently installed.)", 
        "Preparing to unpack .../libxslt1.1_1.1.28-2build1_amd64.deb ...", 
        "Unpacking libxslt1.1:amd64 (1.1.28-2build1) ...", 
        "Selecting previously unselected package nginx-common.", 
        "Preparing to unpack .../nginx-common_1.4.6-1ubuntu3.4_all.deb ...", 
        "Unpacking nginx-common (1.4.6-1ubuntu3.4) ...", 
        "Selecting previously unselected package nginx-core.", 
        "Preparing to unpack .../nginx-core_1.4.6-1ubuntu3.4_amd64.deb ...", 
        "Unpacking nginx-core (1.4.6-1ubuntu3.4) ...", 
        "Selecting previously unselected package nginx.", 
        "Preparing to unpack .../nginx_1.4.6-1ubuntu3.4_all.deb ...", 
        "Unpacking nginx (1.4.6-1ubuntu3.4) ...", 
        "Processing triggers for ureadahead (0.100.0-16) ...", 
        "Processing triggers for ufw (0.34~rc-0ubuntu2) ...", 
        "Processing triggers for man-db (2.6.7.1-1ubuntu1) ...", 
        "Setting up libxslt1.1:amd64 (1.1.28-2build1) ...", 
        "Setting up nginx-common (1.4.6-1ubuntu3.4) ...", 
        "Processing triggers for ureadahead (0.100.0-16) ...", 
        "Processing triggers for ufw (0.34~rc-0ubuntu2) ...", 
        "Setting up nginx-core (1.4.6-1ubuntu3.4) ...", 
        "Setting up nginx (1.4.6-1ubuntu3.4) ...", 
        "Processing triggers for libc-bin (2.19-0ubuntu6.7) ..."
    ]
}
```

### 解説

#### -bオプション

becomeの略で、対象ホストでどのユーザーとして操作をするかを指定します。デフォルトはsudoです。

#### aptモジュール

対象ホストにてaptコマンドを使ってパッケージをインストールします。
私は対象ホストがUbuntuなのにyumで入れようとしてハマってしまいました。OSに応じて、yum, apt, brewなどが用意されているので、適宜使い分けてください。

# 2. Playbook

複数のモジュールをまとめて実行するためにPlaybookを使って処理を書いていきましょう。

## 2.1. Hello world!

まずは動作確認。

```
$ cat << EOS > ./playbook.yml
- hosts: 192.168.33.10
  tasks:
    - name: PlaybookでHello world!
      shell: echo Hello world! > hello.txt
EOS

$ ansible-playbook -i ./inventory.txt ./playbook.yml
```

`ssh 192.168.33.10`で対象ホストにログインすると、ログイン直後のディレクトリに`hello.txt`ができていることを確認できるはずです。

### 解説
- yaml形式です。ファイル名はなんでも構いません。yamlの書き方については[こちら](http://magazine.rubyist.net/?0009-YAML)。
- tasksの中に、処理を記述していきます。
- nameに記載する文字列は人間向けなのでなんでも構いません。
- shellがモジュールで、その後がモジュール引数ですね。

## 2.2. Nginxをインストールする

では、複数の処理を書いていきましょう。ここではNginxをインストールした後、起動しています。

```
$ cat << EOS > ./playbook.yml
- hosts: 192.168.33.10
  become: sudo
  tasks:
    - name: NGINX | Installing NGINX
      apt: name=nginx state=present
    - name: NGINX | Starting NGINX
      service: name=nginx state=started
EOS

$ ansible-playbook -i ./inventory.txt ./playbook.yml
```

### 解説
- `become: sudo`はansibleコマンドの説明で出てきた`-b`オプションと同じく、対象ホストでの実行ユーザーを指定しています。
- `service`というモジュールでNginx等のサービスを、起動/停止/再起動することができます。

Vagrantファイルで下記のように、ポートフォワードしている場合、実行ホスト側のブラウザで http://192.168.33.10/ を叩くと「Welcome to nginx!」と言ってくれるはずです。

```
$ cat Vagrantfile 
Vagrant.configure(2) do |config|
  config.vm.box = "ubuntu/trusty64"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.network :forwarded_port, guest: 80, host: 8080
end
```

<img width="961" alt="Screen Shot 2016-05-04 at 19.08.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/36429/c101e4cd-594c-5c16-5be3-259d731dcdc6.png">



# 3. Next Steps

ここまででなんとなくAnsibleの概要はつかめました。この後は、今開発中のサービスに実戦投入しつつ、下記を進めていこうと思います。

- [Ansible Galaxy](https://galaxy.ansible.com/)に上がっているRoleを眺めてみる。
- [Githubに上がっているPlaybook](https://github.com/search?utf8=%E2%9C%93&q=flask+playbook&type=Repositories&ref=searchresults)を眺めてみる。
- Flaskでの開発環境構築処理を記述する。
- Templateとやらの調査。
- ディレクトリ構成やファイル名などに関するお作法（[ベストプラクティス](http://knowledge.sakura.ad.jp/tech/3084/)）を学ぶ。

# 参考文献

- [Ansible 公式サイト](http://docs.ansible.com/ansible/index.html)
- [サーバ／インフラエンジニア養成読本 DevOps編](http://www.amazon.co.jp/DevOps-Infrastructure-Code-ebook/dp/B01C6RPY82/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=&sr=)