Goの環境を作るAnsibleの設定をリファクタした

 · 5 min read

の投稿です。

まだGoもAnsibleも良くわかってない頃に作った、Goの環境を整えるAnsibleの設定をリファクタリングしました。

やってる事はごく当たり前なんですが、冪等性を担保し、changedが出ないことによって何回でもいつでも実行できる環境にしたので、その過程をメモします。

まえおき

リファクタリング前リファクタリング後はそれぞれリンクをご参照下さい

Goのバージョンを最新に

Goのバージョンが1.4で古かったので1.5に上げました。
ちなみに1.4と1.5はこんな感じに違うそうです。

URL内にバージョン番号をハードコードしていたのでvarsの中に移して、バージョン番号の変更漏れを起こさないようにしました。(差分)
以後はURLに変更がなければこのように変えるだけで良くなりました。

shell, commandモジュールをなるべく使わない

shell, commandモジュールはシェルなので便利ですが、代わりに全ての操作がchangedになってしまいます。
これでは プロビジョニングを実行した結果何が変わったのか が分かりません。安心感に欠けます。

幸い、それらのモジュールを使わないで済む代替手段が色々あったので、なるべくそちらに寄せていきます。 ファイルの上書きなどで冪等性をシェルだけで担保しようとするとかなり煩雑になってしまうので、とても有り難いです。
以下に何かと使いそうな例と、それを利用したリファクタの差分を出してみました。

  • ファイルの存在チェックならstatモジュール (差分)
  • apt-update, apt-upgradeはaptモジュール(差分)
  • ファイルの末尾に挿入、ファイル内の編集はlineinfileモジュール(差分)

shell, commandモジュールを使うならchanged_whenをつける

それでもやっぱり、シェルにお力添え頂きたい箇所は出てしまいます。
そんなときはchanged_whenというプロパティを足して、実行した結果何か変わったのか否か? を明示してあげると、シェル系のモジュールを使用してもokが出るようになります。

例えばGoのバージョンチェックでは標準出力の内容に指定した文字列が含まれるか否かでchangedを出しています。

- name: check Go version
    shell: go version | awk '{ print $3 }'
    register: go_version
    ignore_errors: yes
    changed_when: "go_version.stdout.find('go{{ goversion }}')"

例えばgodep saveでは、終了コードも標準出力の内容も違わないため無理かと思いましたが、ゴリ推しました。
godep save実行後にGodeps/Godeps.jsonのdiffを見てもし差分が出ていればchangedという判定にしました。

- name: save go dependencies
    shell: cd {{ apppath }} && go get && godep save && git diff Godeps/Godeps.json
    register: godep_diff
    changed_when: "godep_diff.stdout != ''"

結果

実行結果のgifアニメを撮ってみました。

Pw4PrxxEfo

二回目の実行では全部okになります。
これで(シェルがバグってなければ)冪等性が担保できるようになりました。

今回の場合は開発環境の初期構築しかやってないので最初の一回しか実行する必要無いんですが、冪等性のある設定がきちんと書けるようになっていると必要なときに何かと役立つと思います。
まだまだAnsibleの知識と慣れが不足しているので、よりよい書き方などご教授頂けると幸いです。

AnsibleGo
© 2012-2021 Leko