この記事で考察すること
production、staging の2つの環境があるとします。
やりたいことは、Ansible の一つのソースで、両方に対応できるようにすること。
つまり、次のようにコマンドで環境を使い分けて実行できるようにします。
# production を対象にする
$ ansible-playbook -i production_hosts site.yml
# staging を対象にする
$ ansible-playbook -i staging_hosts site.yml
今回作成する Ansible ソースのポイント
ポイントを簡単に箇条書きにします。
- ステージごとにインベントリファイルを用意(staging_hosts, production_hosts)。このファイル中で、変数 stage にステージ名を設定します。
- web, db という粒度でプレイブックを作成(web.yml, db.yml)。これらのプレイブックから、ステージに応じたロール、変数ファイルを呼び出します。
ディレクトリ構成
|-- production_hosts
|-- staging_hosts
|
|-- site.yml
|
|-- web.yml
|-- db.yml
|
|-- roles
| |-- staging_pretask/
| |-- db/
| `-- web/
|
`-- vars
|-- common.yml
|-- production
| |-- web.yml
| |-- db.yml
`-- staging
|-- web.yml
|-- db.yml
inventory
ステージごとにインベントリファイルを用意します。
特徴的なのは、ここでステージの環境変数を設定しています。
production_hosts
[web]
web.prd.example.com
[db]
db.prd.example.com
[all:vars]
stage=production
staging_hosts
[web]
web.stg.example.com
[db]
db.stg.example.com
[all:vars]
stage=staging
Playbook
site.yml
web, db のプレイブックを import するだけの内容です。(余談ですが、include はバージョン 2.8 で無くなります。)
- import_playbook: web.yml
- import_playbook: db.yml
上位プレイブックで環境の制御
web, db という粒度でプレイブックを作成します。この中で必要なロール、変数を設定します。
ポイントは、vars_files でステージに対応した変数を読み込んでいること。
Tips
- tags をロールごとに設定しておくと、プレイブック実行時に指定ロールのみの処理を実行可能です。
- 特定ステージでのみ実行したいロールがある場合は、when を使ってステージを指定します。
web.yml
- hosts: web
become: yes
vars_files:
- vars/{{ stage }}/web.yml
- vars/common.yml
roles:
- { role: staging_pretask, tags: staging_pretask, when: stage == 'staging' }
- { role: common, tags: common }
- { role: web, tags: web }
db.yml も同じような考え方で作成します。
タスク単位で、環境ごとに動作を変えたい場合
片方の環境でのみ実行したい処理は、when 句によってステージを指定します。
roles/common/tasks/main.yml
- name: xxxxxx
...
when:
- stage == "production"
プレイブック実行
コマンド
-i でステージング、プロダクションを切り替えます。
# production を対象とする。
$ ansible-playbook -i production_hosts site.yml
# staging を対象とする。
$ ansible-playbook -i staging_hosts site.yml
# staging を対象とする。web サーバのみ。
$ ansible-playbook -i staging_hosts web.yml
# staging を対象とする。web サーバを対象に、common ロールのみ。
$ ansible-playbook -i staging_hosts web.yml --tags common
補足: なぜ group_vars を避けたか
Ansible がよしなに必要な変数ファイルを読み込んでくれるのですが、意図どおり読み込まれないことがありました。それならば、vars_files で自分が必要なものを明示的に呼びだそうと考えました。