ChefからAnsibleに乗り換えてみる

もう…Chefは沢山だ!

Chef-SoloChef-Serverの使い分けどうしたらいいんだ!!」とか、「そうこうしているうちに、Chef-Zeroってなんだ!!」とか、「そもそも立ち上がってないサーバー宛に、OpenSSLでのアクセス要求するとか、もうわけわからん(← これは単に俺がわけわかってないだけ)」とか、イライライライラしてきたので、サーバー構成管理ツールについてはよりシンプルと噂のAnsibleを使ってみることにする。以下メモ!


初期設定

Ansible自体のインストールは、ここにあるように、色んな方法があるので割愛。俺はpipで入れました。

こことかを参考にして進めるのですが、わざわざVagrantで仮想サーバーを二つ構築するのではなく、立ち上げた仮想サーバーに対して、Macから設定を行ってみようと思います。(その方がニーズあるんじゃないか…)

Vagrantで仮想サーバーを立ち上げる

Provisionは走らないようにして、$ vagrant upを実行(IPアドレスには192.168.33.45を指定してあります)

仮想サーバーへの疎通を確認します

サーバーの疎通を確認するために、pingを打ってみる。-mはModuleの「m」。Ansibleで利用できるModuleにはかなりの数があり、これだけでChefよりリッチな気がする。Moduleの詳細はここで確認できます

$ ansible 192.168.33.45 -m ping
ERROR: Unable to find an inventory file, specify one with -i ?

こんな感じで、「サーバーの構成リストの中にこのIP含まれてないよ」と優しく諭されます。「-i忘れてない?」って(「?」が優しさ)。

そこでIPアドレスを単に列挙したサーバーの構成リスト(Inventoryと呼ぶ)を-iオプションで指定してやりましょう。

僕の場合は、Ansibleのファイルは一箇所にまとめたいので、/ansibleというディレクトリを作っています。$ cd ansibleしてからコマンド叩いてやる方法もあるんですけど、プロジェクトルートから色々やりたいので、以下の様な書き方にしますね。

$ echo 192.168.33.45 > ansible/hosts
$ ansible -i ansible/hosts 192.168.33.45 -m ping

次は、こんなエラーを吐きます。

192.168.33.45 | FAILED => SSH Error: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
    while connecting to 192.168.33.45:22
It is sometimes useful to re-run the command using -vvvv, which prints SSH debug output to help diagnose the issue.

要するに、SSHでの接続権限が無い、と。なので、仮想サーバーの方に公開鍵を追記してやって、SSHでの疎通を確認します。$ vi ~/.ssh/id_rsa.pubとかで、公開鍵の中身を把握しておきます(Github使ってるなら、既にあるでしょ公開鍵 ← 雑)

$ vagrant ssh
$ vi ~/.ssh/authorized_keys

ここに、さっきの公開鍵の中身を追記しておきます。その上で、もう一回下記コマンド実行。

$ ansible -i ansible/hosts 192.168.33.45 -m ping
192.168.33.45 | success >> {
    "changed": false,
    "ping": "pong"
}

疎通確認!

だが待って欲しい。俺たちの冒険はここから始まります。そう、ここからは、「AnsibleでLAMP環境を構築するPlaybookを書き、VagrantのProvisionで走らせるまで…」に挑戦してみることにします。


Playbookを書く!

Ansibleでは、タスクをまとめたものを「Playbook」と呼びます。

Inventoryを設定

ローカルの開発グループとして、ホストグループdevelopmentを定義。ansible/developmentというInventory Fileを用意してやりましょう。そこで、lampというグループを作ります。

development

[lamp]
192.168.33.45

これによって、「開発環境(development)では仮想マシン一台構成だが、本番環境(production)ではWEBサーバーとDBサーバーを分けたい」なんて時、ansible/productionにはwebdbのグループを用意して、それぞれ別のPlaybookを走らせる…なんてことが可能になります。

Playbookを記述

こんな感じでテスト用Playbookを書いてみます。これは単に、「Apacheが動いているか確認する」というPlaybookですね。becomeという項目は、このタスクをsudoで行うという意味です。

- hosts: development
  become: yes
  tasks:
    - name: be sure httpd is installed
      yum: name=httpd state=installed
    - name: be sure httpd is running and enabled
      service: name=httpd state=started enabled=yes

Playbookを実行!

まずはシンタックスチェックが出来ます。

$ ansible-playbook -i ansible/development ansible/development.yml --syntax-check

ドライランで、「実際には実行しないけど、実行したらこんな感じになるよ…」っていうのを試してみることが出来ます。

$ ansible-playbook -i ansible/development ansible/development.yml --check

で、実行!

$ ansible-playbook -i ansible/development ansible/development.yml

凄く直感的ですね。こうシンプルだとわくわくしますね。


構成

Bast Practiceを確認

Ansibleの公式ドキュメントには「Best Practices」という形で、構成案が記してあります。これに併せて、LAMP構成のサーバーを構築してみることにする!

ディレクトリ構造

  • development : 当記事のInventory File。ここは各環境に合わせてください。例えば、productionstagingなんていうInventoryはよく使うことになるでしょう
  • development.yml : site.ymlから読み込むPlaybookファイル。それぞれの環境に応じたタスクをここに記述します
  • group_vars/ : グループ毎の設定ファイル
    • all : 全てのグループで読まれる設定ファイル
  • host_vars/ : hostsにあるホストごとの設定ファイル
    • development.yml : こんな感じで設定ファイルを置いておく
  • roles/ : 各タスクを格納するディレクトリ
    • xxxx/ : 例えばroles/httpd/みたいな感じで置いたものを、設定ファイルからhttpdタスクとして実行することが可能になります
    • handlers/ : 再起動や終了など、何かのタスクをフックにアクションを起こしたいときは、ここにハンドラーとして登録します
    • tasks/ : タスクファイル(yml)を格納。基本、task httpdとやると、roles/httpd/tasks/main.ymlが読み込まれる
    • templates/ : タスクで利用する設定ファイルなどの雛形を格納します。httpd.confなどをここに置いています
  • site.yml : マスターのPlaybookファイル

site.ymlを設定

site.ymlは全ての大元のPlaybookになります。$ ansible-playbook -i ansible/development ansible/site.ymlこんな形で実行しますので、勿論site.ymlという名前じゃなくても一向にかまわないですね。ここでは、development.ymlを読み込むこととします。

site.yml

- include: development.yml

読み込まれるdevelopment.ymlを見てみましょう。

---
- name: Install LAMP
  hosts: lamp
  remote_user: vagrant
  become: yes
  vars_files:
    - host_vars/development.yml
  roles:
    - common
    - httpd
    - php
    - mysql

こちらでは、rolesという形で、タスクを設定しています。上に書いたように、それぞれroles以下にあるPlaybook(roles/xxxx/tasks/main.yml)を見に行き、実行します。hostsにはlampが設定してありますので、Inventory File(development)で読み込まれたグループlampが今回の対象サーバーになります。

vars_filesは設定ファイルで、ここに変数を書いてやると、Playbookの中で{{ hostname }}のような感じで参照することが可能です。勿論テンプレートの中でもバリバリ使用できます(Chefのnodeとかvariablesの考え方はややこしかったですね…)。

タスクを設定

Apacheをインストールするタスクを見てみましょう。/roles/httpd/tasks/main.ymlで設定されています。

/roles/httpd/tasks/main.yml

- name: Install httpd
  yum: name=httpd state=present
  tags: [lamp, httpd]

nameでyumのパッケージ名、statepresent(現行版)、latest(最新版)、absent(削除)を選択することが出来ます。この辺の仕様は、$ ansible-doc yumで確認できます。

tagsは、Ansible Playbook実行時に、-t httpdなどとオプションを指定することで、そのタグがついたタスクだけを実行するのに使います。主な使い道としては、どこかで処理がコケた時に、それまで成功していた処理をショートカットするのに使ったり、ごく一部のタスクだけを実行する必要に迫られた場合(php.iniを書き換える…とか)に使用します。

タスクのリストを確認

実際に実行されるタスクの一覧を確認することも出来て、非常に便利!

$ ansible-playbook -i ansible/development ansible/site.yml --list-tasks

実行!

$ ansible-playbook -i ansible/development ansible/site.yml

VagrantのProvisionerとして、Ansibleを使用する

ここまでできちゃえば、後は非常に簡単です。

Vagrantfile

設定自体は、このぐらい

config.vm.provision "ansible" do |ansible|
  ansible.limit = 'all'
  ansible.inventory_path = "ansible/development"
  ansible.playbook = "ansible/site.yml"
end
  • limit : ここにはallを入れておきます
  • inventory_path : Inventory Fileのパスです。Vagrantで使用するのであれば、developmentを参照すればOKですね
  • playbook : Playbookのパスです。site.ymlを指定します

これで$ vagrant up、もしくは$ vagrant provisionを叩けば、あっという間に仮想環境の構築が終わるはずです。VagrantのProvisionerとして登録しておくと、SSHキーの設定も不要なので非常に楽。


まとめ

超駆け足ですが、こんな感じで無事ChefからAnsibleに乗り換えることが出来ました。

まだ、ごく簡単なLAMP構成のサーバーを構築できるレベルのものですが、githubに今回使ったファイルの一式を公開しましたので、眺めてみてください。

個人的に、Chefと比較した時のAnsibleのメリットは以下の様なものがあります

  • 設定が直感的(コンソールの出力も見やすいです)
  • ファイル構成をある程度自由に組みかえられる
  • 設定先のサーバーを弄る必要がほとんどないので、認証周りの厄介なトラブルを避けられる
  • Vagrantの設定がすげー簡潔

逆にデメリットは以下かな。

  • berkshelfの不在
  • PlaybookをScaffolding出来ない
  • 冪等性を担保するのがChefよりしんどい

しかしながら、berkshelfってあんまり使わない+使うとブラックボックスになってしまうので、個人的にはAnsibleの方が使いやすいのと、その分ノウハウが小さい単位で転がってて再利用しやすいので問題はないかなと思っています。

冪等性については、PlaybookがYamlでの記述になる分、分岐などがややこしくなるなーっていう印象。しかしながらその分柔軟なので、もしステージングはCentOS、本番はUbuntuで運用している…みたいな地獄の案件とかは、Inventory Groupを上手く使ってやればいいんじゃないかなと思います。

PlaybookのScaffoldingはいずれ実装して欲しいですね。(ドキュメントを良く読んでないから、もしかしたら存在するのかもしれないですね)

ということで、俺はChefを卒業しました。明日からは、Ansible使いとして生きます!ご声援よろしくお願いします!


関連リンク