Usual Software Engineer

よくあるソフトウェアエンジニアのブログ

Ansibleでデプロイする時に使える小ネタ

Ansible ってとても良いツールですよね。3年以上前に初めて触った時は Chef や Puppet から開放されると思うと感動するくらいでした。今でもお気に入りなプロダクトの一つです。 というわけで今回は小ネタで、 Ansible でアプリケーションのデプロイ用 playbook を書く時のテクニックなどを紹介します。

LB からインスタンスを切り離す

- hosts: all
  name: deploy application
  become: yes
  serial:
    - 1
    - "50%"
...
  pre_tasks:
    - ec2_metadata_facts:

    - name: deregister instance from load balancer
      local_action:
        module: ec2_elb
        instance_id: "{{ ansible_ec2_instance_id }}"
        state: absent

    - name: wait for instance port to close active connections
      wait_for:
        host: 0.0.0.0
        port: 80
        delay: 10
        sleep: 10
        state: drained
        timeout: 300
        exclude_hosts: 127.0.0.1
...

ポイントは2つです。

  • serial キーワードで複数ホストへの playbook 適用を制御する
    • この例では初回は1台目だけ、2台目以降は半分ずつ playbook が実行される
  • wait_for モジュールでアクティブなコネクションを監視する
    • LB の切り離し後にコネクションが全てクローズするまで待つことができる

実行結果の stdout を見やすくする

tasks:
  - name: apply puppet manifest
    puppet:
      timeout: 30m
    register: apply_puppet_result

  - debug:
    var: apply_puppet_result.stdout_lines

コマンドの複数行の出力結果、見づらくなりがちですよね。 debug モジュールの var で command などの実行結果の stdout_lines を出力すると、改行ごとに表示されるので少し見やすくなります。

Check モードを考慮する

- name: check something
  command: which foo
  register: foo_result
  check_mode: no
  changed_when: false
  failed_when: foo_result.rc != 0
  ignore_errors: "{{ ansible_check_mode }}"

ポイントは2つです。

  • check_mode: no
    • Check モード時も実際にコマンドが実行されるようになる
  • ignore_errors: "{{ ansible_check_mode }}"
    • Check モード時にそのタスクが失敗しても中断せず以降のタスクを継続して実行する

実行時プロンプトで制御する

...
vars_prompt:
  - name: application_version
    prompt: Please input target application version
    private: no
    default: "1.0.0"
...
tasks:
  - pause:
      prompt: Please press 'Enter' to continue ('Enter'/'Ctrl+C')
    when: not without_prompt
...

変数をプロンプトで入力させたり、 playbook 実行の途中でプロンプトの入力待ちをさせたりできます。 いきなりフルオートメーションするのが不安な場合には pause モジュールで入力を待たせるのも有効だと思います。

タグをまとめる

tasks:
  - block: # deploy
    - name: task1
      command: foo

    - name: task2
      command: bar

    when: target_role | match("(web|batch)")
    tags: deploy

block は本来 rescue, always と合わせてエラーハンドリングに使われるものですが、 whentagsblock に対して設定できるので、タスクをまとめて同じタグを付けたい時などに便利です。

いざ書くとなると意外と情報量少なくなってしまいましたが Ansible とても便利です。 yaml で書けるって幸せ。

Ansible実践ガイド

Ansible実践ガイド

Ansible徹底入門 クラウド時代の新しい構成管理の実現

Ansible徹底入門 クラウド時代の新しい構成管理の実現