Ansibleで開発用サーバー作るのに覚えたはじめの一歩

More than 1 year has passed since last update.

Ansible自分でやってみると書くの短時間で済むし、構成はシンプルで管理しやすいし、だいぶ好きになってきました。まだ開発用のVPS1台作るのに触っただけなので本格的に学べてはいないですが、導入部分とつまずきポイントをさっくりまとめときます。自分のplaybookは以下レポジトリ。

Ansibleの構成

やっていることは極めてシンプルで、サーバーの設定/構築等の処理を「モジュール」と呼ばれるリソースで定義し、指定したIPやホスト名の対象サーバーに対して、SSH経由で処理を流し込んでいくというだけ。ansibleコマンドを使ってコマンド1発だけを送ったりもできるけど、基本的にはモジュールを複数記載した playbook と呼ばれるyamlファイルを用意して、ホスト情報も インベントリファイル にリストアップしていくことになる。playbookを使用したデプロイにはansible-playbookコマンドを使用する。

$ ansible-playbook -i hosts playbook.yml

オプションとしてよく使いそうなのは-Cで実行を伴わないDry runができたり、-kでSSHの、-Kでsudoのパスワードを対話式に入力できるようになるなどのあたりか。あとは後述するが、playbook内の一部taskだけを選択して実行できるようなオプションもある。

なので言ってしまえばモジュールの書き方さえ覚えれば最初はなんとかなる。Ansibleは内部的にはPythonによるツールだが、ChefやPuppetがRubyに則った構成ファイルを自分で書かなくてはならないのに対し、AnsibleではPython自体に触れる必要がないので、だいぶ敷居は低い。

playbook

主に使用するキー

  • name: コメント。playbookの概要を簡潔に書いておくとよい。
  • hosts: 対象ホスト。インベントリファイルに記載した名前を定義する。後述。
  • user: playbook内のタスクを実行するユーザー。
  • sudo: sudoが必要か否か指定する。
  • vars: 変数。実際の変数はネストして定義していく。
  • tasks: タスクのモジュールを列挙。
  • handlers: タスク実行の後続で呼び出す処理を列挙。

tasks

やりたいことを公式docsのModule Indexで探して書いていけばよい。こちらでも同じくname:でタスクの概要を書いておくのが通例。ansible-playbookコマンドの--start-at-taskオプションにこのname:を渡すと、そのタスク以降だけを実行したりできるので、あまり冗長な名前は避けた方が良いかと思う。

よく使うモジュールとしてはユーザー制御に使うusergroup、言わずもがなのyum、ファイル内の一部を編集するlineinfile、テンプレートファイルを変数埋め込んで配置するtemplates、読んで字のごとくgit、ファイルとディレクトリ制御に使うfilecopy、シェルコマンド実行のためのcommandといったところか。

taskにはいろいろと効率化のための書き方が用意されている。例えば同一のモジュールを複数回用いることがある場合には、with_items:を使うことでループが可能。

- name: install via yum
  yum: name={{ item }} state=installed
  with_items:
    - vim
    - zsh
    - git

with_items:に定義した配列が{{ item }}に代入されてループ実行される。1回のループで複数の変数が必要な場合には、代入先を{{ item.foo }}といった形で定義し、with_items:{ foo: 'foo', bar: 'bar' }とリスト型で定義すればよい。さらにループをネストしたり、複雑なこともできるっぽい。詳細は公式参照。

あと便利な使い方としては、taskにタグを設定することで、特定のタグがついたtaskだけを実行したりしなかったりという指定ができる。自分のplaybookではCentOS6と7の分岐でタグをつかっているが、本来この場面であればWhen Statementを使うべきと思うので、あまりよろしい見本ではないのかなと。

playbook.yml
- name: only DB server
  yum: name=mysql state=installed
  tags:
    - db
$ ansible-playbook playbook.yml --tags "db"
$ ansible-playbook playbook.yml --skip-tags "db"

handlers

書き方はtasksと同様。実行したいhanderのname:をtask内のnotify:で定義する。なおhandlerはnotifyされた直後の実行ではなく、全task完了後の実行となる。呼び出しというよりは、実行フラグを立てるためのものと考えた方がいい。

tasks:
  - name: change SSH port
    lineinfile: dest=/etc/ssh/sshd_config regexp="^#Port " line="Port {{ ssh_port }}" state=present
    notify: restart sshd

handlers:
  - name: restart sshd
    service: name=sshd state=restart

vars

当然のごとく変数が使える。基本はvars:で変数を定義し、{{ var }}の形で参照する。変数名は英数字とアンダースコアしか使えないので注意。またコロン直後の変数参照等ではダブルクォートで囲う必要のあるときがある

変数の定義はいくつかパターンが有る。外部ファイルに定義した変数を読み込む際にはvars_files:でパスを指定する。

/vars/external_vars.yml
foo: foo
var: var
playbook.yml
vars_files:
  - /vars/external_vars.yml

実行時に対話式に変数を定義させる場合はvars_prompt:が使える。プロンプトはマスターするとだいぶ便利そう

vars_prompt:
  - name: "your_name"
    prompt: "what's your name?"
    default: "John Doe"

またこれら変数定義を一切行わずとも、ansible-playbookコマンドのオプションで変数を直接定義できる。

$ ansible-playbook playbook.yml --extra-vars "foo=foo bar=bar"

インベントリファイル

インベントリファイルは特に難しいこともない。ホスト名でもIPでもSSH接続できる形で対象サーバーを列挙しておけばよい。~/.ssh/configはちゃんと見に行ってくれるようなので、そちらの指定に従った定義でも可。また[group]の形でホストをグループ化できるので、特定のグループ全体に対して同一のplaybookを実行するといったこともできる。

[web_server]
192.168.1.1
web1.example.com
web2.example.com

[db_server]
192.168.10.1

つまずきポイント

以降は個人的なつまずきポイントのまとめ。

つまずいてもかなりのノウハウがすでに日本語でも蓄積されていることと、何より公式ドキュメントがベストプラクティス含めだいぶ充実しているので、それほど悩むことなく使いこなせるように思う。特に公式が本当に役に立つので、下手にググったりする前にすべて目を通しておくべきかなと。特に、ここに書いたのはあくまで少数のサーバー構築に使ったわずかな知識なので、より大規模な管理に必要なことはまたベストプラクティスが異なってくるはず。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.