ansible で json ファイル (今回は /etc/docker/daemon.json) を更新したかったのですが、 lineinfilereplaceini_file のように単独のモジュールで簡単にできるものではなかったので、少し工夫をして実現しました。

動作確認バージョン

  • ansible 2.3.1.0

combine フィルター (後述) が New in version 2.0 なので、 1.x では動かないと思います。

実例

https://github.com/znz/ansible-role-dockerhttps://github.com/znz/ansible-playbook-gitlab-dokku/tree/master/provision/roles/docker-dns にあります。

json ファイル読み込み

まずは command モジュールで読み込んで、 set_fact で変数に設定しておきます。

- name: "Read daemon.json"
  command: cat /etc/docker/daemon.json
  register: result
  changed_when: no

記事を書いていて気づいたのですが、リモートからファイルを読み込むには slurp モジュールというのがあるようですが、作った時点では知らなかったので、使っていません。

base64 でエンコードされていて b64decode を通す必要があるようなので、何度も参照するなら、次の set_fact を組み合わせた方が良さそうなのは変わらなさそうです。

json から dict に変換

json の文字列から from_jsonフィルターで変換します。


- set_fact: docker_daemon_json="{{ result.stdout | from_json }}"

combine フィルターでマージ

combineフィルターで設定をマージして、 to_json フィルターで json 文字列に変換してファイルに書き出します。

今回の用途では、ネストしたデータは考慮する必要がなく、トップレベルのキーが一致するもので置き換えられればよかったので、 recursive=True は指定していません。

when でのチェックもしておかないと、設定内容としては変わっていないのに、 json 文字列になった時にキーの順番が変わっているのか、 changed になってしまうことがあったので、 when で設定内容に変更がある時だけ書き込むようにしています。

- name: "Update daemon.json"
  template:
    src: daemon.json.j2
    dest: /etc/docker/daemon.json
    owner: root
    group: root
    mode: 0400
  when: "docker_daemon_json != docker_daemon_json|combine({'dns':dns})"
  notify:
  - restart docker

templates/daemon.json.j2:


{{ docker_daemon_json | combine({"dns": dns}) | to_json }}

動作確認

全体ができた後に、

  • ファイルがない時の動作
  • 設定が変わらない時の動作
  • 設定が変わる時の動作

も確認しておきます。

docker のデーモン設定ファイル

docker のデーモン設定ファイルinsecure-registries (--insecure-registry=[]) や dnsbip など dockerd のオプションで指定できるものはなんでも指定できます。

docker デーモンのオプション変更は systemd の docker.service の設定を変更する方法もあるようですが、ローカルの変更をローカルの独立ファイルに隔離できて、バージョンアップの影響も少なそうなので、 daemon.json を使うことにしました。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published