ansibleのオプションが長くて覚えられないので工夫した話

結構前にansibleの実行時のオプションが長すぎて覚えられず、工夫したものをどこにも資料を残してなかったので、まとめてみました。

あくまで僕が取った一つの手段であり、ベストプラクティスだとは思ってないですが、少しでも誰かの役に立てばと思い残しておきます。

ansibleって?

サーバの構成を管理するためのツールです。これを使うことでアプリケーションを実行するための設定などをコードで管理し、設定を自動化することができます。

設定をコードで管理、自動化出来ることのメリットとしては、サーバの設定項目に対してレビューを挟むことがしやすくなり誤った設定などを防いだり、急遽サーバを増やす(スケールアウト)対応が必要になったときなどにすぐ対応することができる、などがあげられます。

ansibleのコマンド長い問題

今回の記事ではansibleのための細かい書き方などについては記載しません。(他のサイトや公式で十分いっぱい記事がありますので、そちらを見てください。)

ansibleを書いていると実行コマンドが下記のようにオプションがいっぱいついて長くなることはないだろうか?

ansible-playbook --vault-password-file $(VAULT_PASS) -i ec2.py -l tag_Environment_${ENV} --private-key=$(KEY) site.yml -u ${user} --check

上記は私が使ってる環境のプロビジョニング用のコマンドですが、もう長すぎて覚えられません。 一応解説しておくと、

  • --vault-password-file $(VAULT_PASS) はファイルを暗号化して管理しているときに複合化してプロビジョニングを実行するための鍵となるファイルを指定するオプション
  • -i ec2.py はダイナミックインベントリという仕組みを使うためのオプションで、プロビジョニング対象が動的に変化する際に使用する
  • -l tag_Environment_${ENV} はプロビジョニングを実行するホストのフィルタリングオプション
  • --private-key=$(KEY) はプロビジョニングの際に使用するssh用の鍵のオプション
  • -u ${user} はプロビジョニングの際に使用するssh用のユーザのオプション
  • --check はdry-runのためのオプションで、これをつけて実行すると実際にはプロビジョニングせずに実行したときの結果をテストすることができます

もちろん一つ一つの意味は理解しているので、思い出しながら書けば実行できないこともないですが、そう頻繁に実行するものでもなかったりするので、久しぶりに「さープロビジョニングするぞ」っていうときに「あれ、コマンドなんだっけ?」となることが多いです。

もちろん忘れても大丈夫なようにコマンドをどこかにメモしておいたり、READMEに書いておいてもいいと思うのですが、それを毎回見たりコピペして実行するのもなんだかイケてないですよね。

対策候補

上記の解決策として、下記を考えました。 1. Alias 1. シェルスクリプト 1. Makefile

Alias

一番最初に思いついたのがAliasでした。長ったらしいコマンドに対してAliasを張るというのはよくやりますよね。 ですが下記の理由から、Aliasでやることを断念しました。

  1. 1台のansible発射サーバから複数サービスのansibleを実行する際にオプションがそれぞれ違うためaliasでは対応しきれない
  2. ダイナミックインベントリを使うためのec2.pyにコマンドが依存しているが、この依存解決ができない

1台のansible発射サーバから複数サービスのansibleを実行する際にオプションがそれぞれ違うためaliasでは対応しきれない

私の触ってる環境的な問題でもあるかもしれませんが、複数のサービスを触っててそれぞれに対してansibleがある状態で、かつその実行を一台のansible実行用環境からプロビジョニングをかけているため、 aliasに登録すると他のサービスのプロビジョニングのコマンドとバッティングしてしまいます。もちろんこれをalias張る名前にサービス名などをつけて対応してもいいのですが、煩雑になりそうだったのでやめました。

ダイナミックインベントリを使うためのec2.pyにコマンドが依存しているが、この依存解決ができない

これについても私の環境によるものでもあるのですが、ダイナミックインベントリを使用しており、その解決にawsのec2.pyを使用しています。これについては公式でも書かれているので詳細はこちらを確認してください。

Working With Dynamic Inventory — Ansible Documentation

問題としては、このプロビジョニングコマンドを実行する際にあらかじめec2.pyを取得しておくことが必要なのですが、環境のセットアップはせっかくコードで管理できるようになったのに、環境セットアップするための手順がコードで管理できていないのでは、意味がないじゃないか。というのが私の意見です。なのでこのec2.pyに対しても何らかの形で取得しておくことが必要だということをコードで表現したいなと思い、aliasは却下になりました。

シェルスクリプト

次に思いついたのがシェルスクリプトです。まぁ、いくつかの手順があってそれを自動化したいとなると、カスタマイズ性の高いシェルスクリプトが候補に上がるのは当然かと思います。 シェルスクリプトであればサービスごとのansibleのレポジトリにスクリプトを含めて実行するようにすれば、aliasのようにバッティングしてしまう問題も防げます。

結論から言うと、私はシェルスクリプトを選びませんでした。もちろんシェルスクリプトでできないわけではありませんし、十分にありな選択肢ではあると思います。 ただ、自分がシェルスクリプトを書くほどのものではなく、かつシェルスクリプト書くのがめんどくさいと思ってしまったために却下しました。

Makefile

Makefileです。普段あまり触ってない人からすると「え、Makefile?」となるかもしれません。ですが、自分はMakefileを結構気に入っています。Makefileのいい点としては、依存解決ができ、簡単なコマンドのラップが書きやすい。これに尽きるかと思います。今回の目的でいうと、ansibleの長いオプションをラップし、サービスごとに微妙に違うオプションもサービスごとにMakefileを書くことで解決し、ec2.pyの依存解決も簡単に表現することができます。

具体的にどうしたか

最終的に下記のようなMakefileをサービスのansibleレポジトリに含めるようにしました。

init: ec2.py ec2.ini
.PHONY: init

ec2.py:
    wget https://raw.github.com/ansible/ansible/devel/contrib/inventory/ec2.py
    chmod +x ec2.py

ec2.ini:
    @echo 'please set up your credential ec2.ini'
    exit -1

VAULT_PASS=./default/path
ENV=default-env
KEY=default-key
USER=default-user
dry-run: init
    ansible-playbook --vault-password-file $(VAULT_PASS) -i ec2.py -l tag_Environment_${ENV} --private-key=$(KEY) site.yml -u ${USER} --check
.PHONY: dry-run

run: init
    ansible-playbook --vault-password-file $(VAULT_PASS) -i ec2.py -l tag_Environment_${ENV} --private-key=$(KEY) site.yml -u ${USER}
.PHONY: run

MODE=encrypt/decrypt
TARGET=your_target_file
vault:
    ansible-vault $(MODE) --vault-password-file $(VAULT_PASS) $(TARGET)
.PHONY: vault

encrypt:
    @$(MAKE) vault MODE=encrypt
.PHONY: encrypt

decrypt:
    @$(MAKE) vault MODE=decrypt
.PHONY: decrypt

このMakefileがあるディレクトリ上で make dry-run のように実行すると初回実行時は init のターゲットも実行されるのでec2.pyは自動でDLされ、ec2.iniにクレデンシャル情報を記入しろ、という旨のメッセージを出して終了します。また、ec2.iniがターゲットになっているのでこのファイルが生成されるまでこのエラーは解消されないので、作成されていないのにansibleが実行されることはありません。

また、おまけでファイルの暗号化のコマンドも僕は覚えられないので、make のターゲットにしてみました。こういう感じでコマンドのラップとしても使え、忘れたとしても make の補完リストから、何ができるかを判断できるので、便利ですね。

新しい人がプロジェクトに入ってきたとしてもよく使うコマンドがmakeにまとまっているとコマンドの説明を細かくしなくても理解してもらえるのでとても助かってます。

(本当は、公式でansibleの実行オプションをファイルで記述できれば一番いいんだろうけど、、