Ansibleのドキュメントを読んでみたメモ

少しくらいAnsibleを使ってみようと思ってブログや公式ドキュメントを読んでみたのでメモ。
参考にした主なものは以下のリンク。
Ansibleとは？みたいないのはリンクを読むとよくわかった。

- Ansibleの公式ドキュメント
  - http://docs.ansible.com/index.html
- Playbookのサンプル
  - https://github.com/ansible/ansible-examples
- Ansibleの概要を知るのにとてもよかった。
  - http://apatheia.info/blog/2013/04/06/about-ansible/

# 構成
ChefとかPuppetとは違ってこちらはAnsibleから対象のサーバに接続していく感じ。
対象のサーバにはとくにエージェントとかはいらない。

# インストール
ほとんどパッケージ管理とかでいけるのでとても簡単。
## Via Pip

    $ sudo easy_install pip
    $ sudo pip install ansible

## Via Yum

    $ sudo rpm -ivh http://ftp.riken.jp/Linux/fedora/epel/6/i386/epel-release-6-8.noarch.rpm
    $ sudo yum install ansible

## Via Apt

    $ sudo apt-add-repository ppa:rquillo/ansible
    $ sudo apt-get update
    $ sudo apt-get install ansible

## Via Homebrew

    $ brew update
    $ brew install ansible

## インストールされた対象バージョン

    $ ansible --version
    ansible 1.6.2

# 基本的な書式
ansibleコマンドの後に-mオプションでモジュールを指定しても良いし-aオプションで直接コマンドを指定してもOK。

    $ ansible 対象 -m モジュール
    $ ansible 対象 -a 'コマンド'

# 実行基本例
pingモジュールは対象へのチェックとかに使える。

    $ ansible all -m ping                                                                                                                            
    target01.okochang.com | success >> {
        "changed": false, 
        "ping": "pong"
    }
     
    $ ansible all -a "uname -r" 
    target01.okochang.com | success | rc=0 >>
    3.10.35-43.137.amzn1.x86_64

# 対象ホストの指定方法
## 設定ファイル
以下のいずれかで良い。

- /etc/ansible/hosts
- export ANSIBLE_HOSTS="your config path"

## 設定ファイル内の書き方
基本的にはホスト名を書くだけでOKだけど、色々な書き方が出来る。

    # グループ化
    [webservers]
    www01.okochang.com
    www02.okochang.com
    # 接続先のポートをデフォルトから変える
    db01.okochang.com:22222
    # IPアドレスを指定する
    local.okochang.com ansible_ssh_port=22 ansible_ssh_host=192.168.0.10
    # 範囲指定とかも出来る
    app-[01:10].okochang.com
    app-[a:d].okochang.com
    # 対象毎にコネクションのタイプも指定出来る
    localhost ansible_connection=local
    other1.okochang.com ansible_connection=ssh ansible_ssh_user=ec2-user
    # 変数を指定したりも出来る（ホスト毎）
    host1 http_port=80 maxRequestPerChild=101
    host2 http_port=8080 maxRequestPerChild=102
    # グループ毎に変数を指定する
    [foo-group]
    host1
    host2
    [foo-group:vars]
    ntp_server=ntp.okochang.com
    proxy_servers=proxy.okochang.com

## コマンド実行時

ワイルドカードが使える

    $ ansible webserver* -m ping

複数を指定することが出来る

    $ ansible webservers:dbservers -m ping

グループのうち特定ホストを除外する事も出来る

    $ ansible webservers:\!webserver01 -m ping

# ansibleコマンド実行時の便利オプション
やんごとなき理由ででSSHのパスワード認証を使いたい

    $ ansible all -m ping --ask-pass

SSHの秘密鍵を指定したい

    $ ansible all -m ping --private-key="~/.ssh/yourkey.pem"

接続先のSSHユーザーを指定したい（デフォルトはカレント）

    $ ansible all -m ping -u ec2-user

sudoで実行したい

    $ ansible all -m ping -u ec2-user --sudo

sudoするユーザーを指定したい

    $ ansible all -m ping -u ec2-user --sudo --sudo-user okochang

sudoするときにはパスワードが必要なんですけどって場合

    $ ansible all -m ping -u ec2-user --sudo --ask-sudo-pass

時間がかかる処理の場合はタイムアウトを指定

    $ ansible webserver01 -B 180 -a "sleep 120"

# 設定ファイル
- /etc/ansible/ansible.cfg
- ~/.ansible.cfg

上記のいずれかで設定でき、デフォルトの動作を指定するものが多かった印象。

    # 接続するときにホスト公開鍵の検証をするかしないか
    $ host_key_checking = False
    # リモード接続するときに平行して生成するプロセス数
    forks=5
    # ホストを指定する方法
    hostfile=/etc/ansible/hosts
    # ログファイルのパス
    log_path=/var/log/ansible.log
    # 色の設定
    nocolor=0
    # デフォルトで使用する接続先のポート
    remote_port=22

# AWSへの対応
AWSを使ってたりすると接続先のIPが変わったり台数が変わったり頻繁にあるのでその対応。

## 導入編

Githubにpythonのスクリプトとiniファイルが配布されている。
使うためにはbotoのインストールが必要だが、実行権限を付与するといい感じに使える。

    $ sudo pip install boto
    $ cd .ansible
    $ curl -LO https://raw.github.com/ansible/ansible/devel/plugins/inventory/ec2.py
    $ curl -LO https://raw.github.com/ansible/ansible/devel/plugins/inventory/ec2.ini
    $ vi .bash_profile
        export AWS_ACCESS_KEY_ID='YOURACCESSKEYID'
        export AWS_SECRET_ACCESS_KEY='YOURSECRETACCESSKEY'
        export EC2_INI_PATH=~/.ansible/ec2.ini
     
    $ chmod +x .ansible/ec2.py
    $ .ansible/ec2.py --list

## 使い方
全リージョンのEC2インスタンスに実行

    $ ansible ec2 -i ~/.ansible/ec2.py -u ec2-user -m ping

リージョンを限定して実行

    $ ansible ap-northeast-1 -i .ansible/ec2.py -u ec2-user -m ping

AZを限定して実行

    $ ansible ap-northeast-1a -i .ansible/ec2.py -u ec2-user -m ping

セキュリティグループを限定して実行

    $ ansible security_group_okochang-group -i .ansible/ec2.py -u ec2-user -m ping

タグを限定して実行（Nameタグにweb01の場合）

    $ ansible tag_Name_web01 -i .ansible/ec2.py -u ec2-user -m ping

# モジュール
Ansibleでの処理される小さい実行の単位。ChefでいうところのResources。
使い方のメモ

## shell

    $ ansible webservers -m shell -a 'ping -c 3 google.co.jp'

## copy

    $ ansible webservers -m copy -a "src=~/test.txt dest=/tmp/test.txt"

## file

    $ ansible webservers -m file -a "dest=/tmp/test.txt mode=600 owner=foo group=var"

## yum

    $ ansible webservers -m yum -a "name=httpd state=installed" -u ec2-user --sudo
    $ ansible webservers -m yum -a "name=postfix state=removed" -u ec2-user --sudo

## service

    $ ansible webservers -m service -a "name=httpd state=started" -u ec2-user --sudo
    $ ansible webservers -m service -a "name=httpd state=restarted" -u ec2-user --sudo
    $ ansible webservers -m service -a "name=httpd state=stopped" -u ec2-user --sudo
    $ ansible webservers -m git -a "repo=git://github.com/serverworks/aws-spec.git dest=/opt/aws-spec version=HEAD"

## gitモジュール
    $ ansible webservers -m git -a "repo=git://github.com/serverworks/aws-spec.git dest=/opt/aws-spec version=HEAD"

# Playbooks
moduleを組み合わせて対象サーバに実行する処理をまとめて書いたもの。
Chefのレシピに近くて、書き方はyml形式。

pingモジュールを使ったplaybook

    # test.con.yml
    - hosts: all
      remote_user: ec2-user
      tasks:
        - name: test connection
          ping:

実行

    $ ansible-playbook .ansible/playbooks/test_con.yml 


shellモジュールを使ったplaybook

    # shell_result.yml
    - hosts: ec2
      remote_user: ec2-user
      tasks:
        - name: run command and ignore the result
          shell: /bin/echo foo
          ignore_errors: True

先ほどのAWSに対応したスクリプトと合わせて使うことも出来る

    $ ansible-playbook -i .ansible/ec2.py -u ec2-user .ansible/playbooks/shell_result.yml

Webサーバ用のPlaybookはこんな感じになる

    # webserver.yml
    - hosts: tag_Name_target01
      vars:
        http_port: 80
        max_clients: 200
      remote_user: ec2-user
      sudo: yes
      sudo_user: root
      tasks:
        - name: ensure apache is installed
          yum: pkg=httpd state=installed
        - name: write the apache config file
          template: src=~/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
          notify:
          - restart apache
        - name: create virtual host file for {{ vhost }}
          template: src=~/vhost.conf.j2 dest=/etc/httpd/conf.d/{{ vhost }}.conf
        - name: ensure apache is running
          service: name=httpd state=started
      handlers:
        - name: restart apache
          service: name=httpd state=restarted

オプションで変数を指定したりが出来る

    $ ansible-playbook -i .ansible/ec2.py -u ec2-user .ansible/playbooks/webserver.yml -e vhost=foo

ファイルをincludeする事も出来る

    # foo_var.yml
    - name: echo foo
      command: /bin/echo foo
    - name: echo var
      command: /bin/echo var
     
    # hoge.yml
    - hosts: ec2
      remote_user: ec2-user
      tasks:
        - include: foo_var.yml

実行

    $ ansible-playbook -i .ansible/ec2.py -u ec2-user .ansible/playbooks/hoge.yml

# Playbook Roles
Playbookを簡単に再利用出来るようにした仕組み。
決められた構成で配置すると自動的に再利用が出来る。
以下はcommonとwebserversのRoleの場合のディレクトリ構成。
https://github.com/okochang/ansible-sample-project

    $ tree
    .
    ├── roles
    │   ├── common
    │   │   ├── files
    │   │   ├── handlers
    │   │   │   └── main.yml
    │   │   ├── meta
    │   │   ├── tasks
    │   │   │   └── main.yml
    │   │   ├── templates
    │   │   │   └── clock.j2
    │   │   └── vars
    │   └── webservers
    │       ├── files
    │       ├── handlers
    │       │   └── main.yml
    │       ├── meta
    │       ├── tasks
    │       │   ├── install_httpd.yml
    │       │   └── main.yml
    │       ├── templates
    │       │   └── vhosts.conf.j2
    │       └── vars
    └── site.yml

実行する場合はこんな感じ。

    $ ansible-playbook -i ~/.ansible/ec2.py -u ec2-user ./site.yml