UUUM攻殻機動隊(エンジニアブログ)

UUUMのエンジニアによる技術ブログです

Ansibleことはじめ

こんにちは、エンジニアのナカハシです。

UUUMのインフラ構築はAnsibleで構築することが恒例になっており、絶賛開発中のRailsアプリも当然Ansibleでインフラを記述しています。

つまり、AnsibleのPlayBookを読めないと既存のインフラもさっぱり理解できなくなるわけで、Webアプリの実装ばかりやっている私としてもさすがにヤバいのではないかと思い、改めてAnsibleに入門してみることにしました。

そもそもAnsibleって何?

Ansibleは構成管理ツールです。

ここでいう「構成管理ツール」とは、コードでインフラ/ミドルウェア構成を記述し、対象のホストに構成を展開(プロビジョニング)することができるツールのことです。

いちいち管理対象のホストにコマンドを打ってログインし、各種ミドルウェアのインストールとかやっていると、間違えるし俗人的だし効率も良くありません。構成管理ツールを使えば、そのあたりの効率性を爆発的に向上できます。

また、サービス/ツール間の連携も可能となり、アプリのコードコミット時にCI⇒プロビジョニングを行ったりすることもできます。

なぜAnsible?

構成管理ツールの競合プロダクトとしては、Chefなどが挙げられます。あえてAnsibleを利用するメリットとはなんでしょうか。

Ansibleの最も大きな特徴は、「エージェントレス型」の構成管理ツールである、つまり、管理対象ホストにプロビジョニングのためのエージェントツールをインストールすることなく、利用できるということです。

Chefなどのエージェント型ツールの場合、プロビジョニングを行うためにエージョエントを配布するという手順が必要になるツラみがあるのです。

Ansibleでどうやって構成書くの?

Ansibleでプロビジョニングを行うのに最低限記述しなければならないのは、InventoryとPlayBookです。

Inventoryはプロビジョニング対象となるホストを記述するファイル、PlayBookはプロビジョニング内容を記述するファイルです。

これらを用意した上で、

$ ansible-playbook -i inventory_file playbook_file

と実行することで、プロビジョニングを開始できます。

超シンプルなInventoryとPlayBookを書いてみましょう。

まずはInventoryを書いてみます。Inventoryはiniファイル形式で記述します。

; グループ
[vagrant]
127.0.0.1

; グループごとの変数
[vagrant:vars]
ansible_port=2222
ansible_user=vagrant
ansible_ssh_private_key_file=.vagrant/machines/default/virtualbox/private_key

プロビジョニング対象のホストとそれが所属するグループ、グループごとにパラメータとなる変数を記述できます。今回の例では、 vagrant というグループと、それに所属する 127.0.0.1 というホスト、SSH接続のためのパラメータを記述しました。

PlayBookはYAML形式で記述します。

---
# Play
- name: simplest play
  hosts: all

  # Task
  tasks:
    # サーバー内情報(Facts)をダンプしてみる
    - name: fact dump
      debug:
        var: ansible_env

PlayBookには、主にPlayとTaskを記述します。

Playでは、所属するTaskへの共通的な設定を行います。 hosts: all は、Inventory内に記述してある全ホストを対象にする、という意味です。

Taskは「モジュール」を使って何かしらの処理を実行します。ここでは debug モジュールを使い、デプロイ先の情報をダンプさせています。

Ansibleには多数のモジュールがデフォルト状態で使えますので、基本的にはモジュールにパラメータを組み合わせてタスクを記述していくことになります。例えば apt-get を使用してNginxをインストールしたい場合、以下のように書きます。

- name: Nginxインストール
  apt:
    name: nginx

超絶簡単ですね。

Role

さて、Taskをどんどん追加していって複雑な構成のインフラを記述しよう! となると、PlayBookがどんどん巨大化していき、新たな神が誕生することになります。そうならないよう、PlayBookをモジュール化する仕組みがRoleです。

Roleは、TaskやTaskから使う変数/テンプレートファイルをなどをひとまとまりにしたもので、以下のようなディレクトリ構成で作成します。

├── playbook.yml
└── roles
    └── nginx
        ├── defaults
        │   └── main.yml
        ├── files
        │   └── web.ini
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        ├── templates
        │   └── index.html
        └── vars
             └── main.yml

ここでは、nginxというRoleをplaybook.ymlから利用しようとしています。(Roleは、1ミドルウェアあたり1Roleといった粒度で作成するといいでしょう)

この場合、playbook.ymlで

roles:
  - role: nginx

と書くだけで、nginx Roleを読み込めます。

変数

さて、Roleの下のいくつかのディレクトリは、それぞれTaskから読み込んで利用できるAnsibleの機能です。この中で超重要なのは変数です。以下のように vars/main.yml で変数を定義することで、 tasks/main.yml から利用できます。

vars/main.yml

---
nginx_service_name: nginx

tasks/main.yml

---
- name: 起動/自動起動設定
  service:
    name: "{{ nginx_service_name }}"
    state: started
    enables: true

変数はInventory内のホスト/グループ単位で指定することもできます。これらの変数は、Roleとは別に以下のようなパスに格納することになっています。

├── playbook.yml
├── group_vars
│  ├── all.yml
│  ├── web.yml
│  └── db.yml
└── host_vars
    ├── web1.host.yml
    ├── web2.host.yml
    └── db.host.yml

その他

変数の他、ファイル内の特定の箇所を変数で上書きするテンプレートや、特定の条件で発火するタスクを作るハンドラーなどの機能があります。また、タスク内にループや例外処理を記述することができます。