読者です 読者をやめる 読者になる 読者になる

無印吉澤

ソフトウェア開発、運用管理(俗にいう DevOps)、クラウドコンピューティングなどについて、吉澤が調べたり試したことを書いていくブログです。

Ansible の --extra-vars 引数を安全に使うためのラッパーを書いてみた

f:id:muziyoshiz:20160313233740p:plain

最近は、仕事でも趣味でも、サーバ構築を自動化したいときは Ansible を使ってます。

アプリケーションのデプロイには Capistrano も使うんですが、つい最近 Ansistrano という便利な Ansible role の使い方を覚えてしまったので、そこも Ansible で済むようになりました。

recruit.gmo.jp

ansible-playbook の --extra-vars 引数

ところで、Ansible の playbook を書いていると、「普段の動作は決まっているけど、ごくまれに違う動作をさせたい」ことがたまにありませんか? そういうとき、僕は ansible-playbook の --extra-vars 引数(-e 引数)を良く使います。

例えば、自作のアプリケーションをデプロイするための playbook で、「普段は master ブランチをデプロイするけど、たまに違うブランチをデプロイしたい」ことがあったとします。そういう場合、playbook のなかで version 変数を、

- hosts: apservers
  vars:
    version: master

のように定義しておいて、master ブランチをデプロイしたい場合は --extra-vars 引数なしで実行します。

$ ansible-playbook -i inventory deploy-app.yml

そして master 以外のブランチをデプロイしたい場合だけ、以下のように --extra-vars 引数を使ってブランチ名を指定します。

$ ansible-playbook -i inventory deploy-app.yml --extra-vars="version=develop"

Ansible 公式の Variables にある通り、あらゆる変数指定のなかで --extra-vars の指定は最優先されます。そのため、このような上書きが可能なわけです。

--extra-vars のデメリット

この方法はだいたいうまくいくのですが、「変数名を間違えても何のアラートも出ない」というデメリットがあります。

例えばつい最近、僕が書いた playbook を使ってアプリをデプロイした同僚から、「develop ブランチを指定したのに master ブランチがデプロイされてる。playbook がバグってないか?」と言われたことがありました。何か実装間違えたかな、と思って彼が実行したコマンドを見たら、こうなっていました。

$ ansible-playbook -i inventory deploy-app.yml --extra-vars="develop"

調べてみたところ、これは無効な変数指定として ansible-playbook に無視されるようです。その結果、version 変数はデフォルトの master のままで、master ブランチがデプロイされました。その同僚はどうも「引数でブランチ名を変えられる」程度の理解だったようです。

そのときは同僚に --extra-vars 引数の使い方を解説して終わったのですが、あとから考えてみると、--extra-vars で動作を変更させること自体が危険なんじゃないか? という気がしてきました。今回は引数の使い間違えでしたが、引数の使い方を理解していても version を versoin と書き間違えてしまうくらいは、普通にありそうです。

--extra-vars の代替案としての vars_prompt

--extra-vars の代替案としては、Prompts に説明のある vars_prompt を使うという方法があります。

vars_prompt は、playbook の実行後に、変数入力のプロンプトを表示するためのオプションです。例えば、playbook に、

- hosts: apservers
  vars_prompt:
    - name: "version"
      prompt: "Branch name?"
      default: master

と書いておくと、playbook の実行時に以下のプロンプトが表示されます。そのまま Enter キーを押せば version 変数に "master" が代入され、ブランチ名を入れればそちらに変わります。

Branch name? [master]:

これでまあ確かに安全になるので、多くの場合は vars_prompt を使うのがよいと思います。

ただ、master ブランチをデプロイするのが大半、というケースでは Enter キーを無駄にぺちぺち押さないといけないのが面倒です。また、カスタマイズ可能な変数がもっと多い場合は、その変数の数だけ Enter キーをぺちぺち押さないといけなくなります。何も考えずに Enter キーをぺちぺち押す習慣ができるのは、またなにか別の障害の原因になりそうで嫌な感じです。

--extra-vars を安全に使うためのラッパー ansible-playbook-se

さっきの同僚の例について考え直してみると、要するにあれは "develop" という僕の想定しない変数名を、ansible-playbook コマンドが受け入れてしまったのがいけなかったわけです。

それなら、--extra-vars 引数に指定できる変数名を限定できれば、それで十分安全になるのでは? そう考えて、ansible-playbook コマンドのラッパー "ansible-playbook-se" を試作してみました。最近覚えた Python 3 で実装し、GitHub にソースコードを置いておきました。

github.com

使い方はまず、このリンク先にある ansible-playbook-se と extra-vars-cheker を、どこかパスが通ったところに置きます。

次に、playbook が置いてあるのと同じディレクトリに、以下のような内容で extra-vars.yml という名前のファイルを作ります。このファイルには、playbook のファイル名と、各ファイルが --extra-vars で指定するのを許す変数名を書きます。

---
deploy-app.yml:
  - version

そして、いつも使っている ansible-playbook の代わりに、ansible-playbook-se を使うようにします。そうすると、想定外の変数が指定された場合、ansible-playbook-se は以下のようなエラーを出して、処理を中断します。

$ ansible-playbook-se -i inventory deploy-app.yml --extra-vars="develop"
ERROR: Invalid extra-var format: develop
ERROR: extra-vars-checker Failed.

安全になりましたね? なりましたよね? でも、これはこれで何だか面倒な気がしますね……。

試しに作ってはみたのですが、まだ実際の環境には導入していません。こういうニーズって、他の人にもあるもんでしょうか? もしニーズがあればもう少しちゃんと作ろうと思うので、ご意見お待ちしています。