0知識からのAnsible 詰まった所&覚えておきたいと思ったところ列挙編

投稿者: | 2018-12-11

概要

この記事は 富士通クラウドテクノロジーズ Advent Calendar 2018 の11日目の記事になります。

昨日は@jinshiさんのOperation as a code 実現に向けた運用統合ライブラリの作成活動についてでした。オペレーションのコード化は今最も求められているものと言っても過言ではないでしょう。運用の自動化だけでなく、ツールや言語のコードに定められた共通ルールが存在することによって、運用及び構成の説明をコードベースで行うことも可能です。今後の展開に目が離せませんね。

就職しました。FJCTでエンジニアをやってます@pachicourseです。
最近はもっぱらAnsibleを勉強しつつ得た知識を業務に転用しています。
現在はあるメンテナンス手順の自動化を目指す+チームにAnsibleのノウハウを共有するために活動していますが、今後はさらに範囲を広げて別チームや部署間でplaybook, rolesの引き渡しによる連携などをしていきたい所存です。

今回は0知識から始めた初心者が学習していて詰まったところや覚えておいた方が良いと感じたものについてまとめます。

環境

  • Ansible: 2.4
  • 管理対象サーバのpython: 3.6.6

用語

ここではAnsibleによってプロビジョニング、構成管理される対象のサーバを管理対象サーバと呼ぶことにします。

詰まった所

shell moduleを使用してgrepするtaskがFailedとなり落ちる

題名の通りです。shellモジュールでgrepを叩いているだけなのにFailedになって落ちます。原因はgrepのexit statusにあります。

$ man grep

~省略~

EXIT STATUS
       Normally, the exit status is 0 if selected lines are found and 1  otherwise.   But  the  exit
       status  is  2 if an error occurred, unless the -q or --quiet or --silent option is used and a
       selected line is found.  Note, however, that POSIX only mandates, for programs such as  grep,
       cmp,  and  diff,  that  the  exit  status in case of error be greater than 1; it is therefore
       advisable, for the sake of portability, to use logic that tests for  this  general  condition
       instead of strict equality with 2.

~省略~
ざっくり言うとマッチする行が存在する場合にexit statusが0になり、見つからなければ1になります(これが原因で落ちる)。

マッチしなかった場合の空文字列も欲しいもしくはマッチしなくても落ちないようにしたい場合は結果をcatに流してあげるのがシンプルです。
- name: Check contents of the file
  shell: 'grep hoge hoge.txt | cat'
  register: grep_result
registerはmoduleの結果を保存しておくことができます。grepの結果はgrep_result.stdoutで取り出すことが出来ます。特定のファイルの数を数えたいときはcatの部分をwc -lなどにすると良いでしょう。

crontab -lもFailedになりうる

です。crontab -lを実行した際にスケジューリングされたタスクが対象ユーザに存在しない場合exit statusは1となりFaildになります。例えばrootユーザ用に設定されたタスクが存在しない場合、”stderr”: “no crontab for root”というメッセージが確認できます。

この場合はfailed_when: False として無視するのが手っ取り早いです。
- name: Ensure crontab_backup file exists
  shell: crontab -l > /path/to/backup/dir/crontab_backup
  failed_when: False # taskが設定されていないときfailedになってしまうので

limitオプションを指定した場合localhostが対象から外れる

外れます。あまり無いシチュエーションですがリモートの管理対象サーバの一部の他にローカルに何かしらの設定を適用したい場合には、limitオプションへ対象group/hostsの情報に加えてlocalhostの記述も追加する必要があります。

$ ansible-playbook site.yml --limit group1,localhost -i inventoryファイルのpath

覚えておきたいと思ったところ

mysql dbにデータを挿入する

Ansibleは様々なDatabase moduleを持ちます。
それぞれのmoduleでは、ユーザ設定を行ったり、DBの追加、レプリケーションの設定などが可能です。
mysql_* moduleの中にはクエリを発行してくれるmoduleがあるかと期待しましたがどうやら無いようです(Influxdbにはありそうです)。
sqlファイルに起こしてmysql_db modulestateパラメータをimportにセットして使うか、単純にshellモジュールを使用します。
- mysql_db:
    name: db_name
    state: import # ここが大事です
    target: /path/hoge.sql # 管理対象サーバ視点でのpathです

includeは非推奨になりました

Ansibleでは2.4からincludeが非推奨(DEPRECATED)になり、実行時に警告が出るようになりました(includeは2.8で廃止予定です)。
playbookやtasksのincludeには、import_[tasks|playbook] または include_[tasks|playbook]を使います。

import_は静的読み込みで、include_は動的読み込みです。
基本的には実行前に文法エラーを吐いてくれるimport_を用いるのが良いと思います。with_itemsなどのloopは実行時に評価される必要があるのでinclude_を使わなければエラーとなります。
# 非推奨1
- include: playbook.yml

# 非推奨2
- include: tasks.yml
  with_items: '{{ something }}'

↓

# 修正後1
- import_playbook: playbook.yml

# 修正後2
- include_tasks: tasks.yml
  with_items: '{{ something }}'

hostsを正規表現で指定する

見出し通りです。特定の文字にマッチするhostsのみを実行対象とすることが出来ます。Ansibleでは先頭に~をつけると正規表現として扱われます。
## webserver1ケタ番台のサーバにだけfuga roleを適用
- name: hoge
  hosts: ~webserver00([0-9]) 
  roles:
    - fuga
変数から渡すこともできます
## 渡されたhosts_patternを適用(hoge.yml)
- name: hoge
  hosts: '{{ hosts_pattern }}'
  roles:
    - fuga

## 以下を実行する形でもOK
ansible-playbook hoge.yml -i inventoryファイルのpath -e 'hosts_pattern=~webserver00([0-9])'
-e 及び –extra-varsオプションはコマンド実行時に変数と値のセットを渡せます

↑をwhenで実装する

タスクごとに実行ホストを絞りたい場合便利です。Ansibleにはinventory_hostnameというマジック変数が定義されており、実行対象ホストの名前が格納されています(ここで格納されるのはinventoryファイルに定義されているhostnameです)。

match()を使うことで正規表現による絞り込みができます
- name: do something
  shell: echo hello
  when: inventory_hostname | match('webserver00[0-9]')

管理対象サーバ上のPythonを指定する

Ansibleはほとんどの場合、moduleを実行するために管理対象サーバにPythonを必要とします。 Ansibleでは実行時に標準パス以外のPythonインタプリタを指定することが出来ます。 設定方法はansible_python_interpreterという変数にpathを渡します。 Ansibleでは変数を様々な場所で定義できるので、予めgroup_vars/something.ymlに定義したり、set_factで指定したりすることができ、管理対象サーバ全体に適用、特定のグループに適用、ある処理だけ別のPythonを使用、などといった動作が実現可能です。
# group_vars/all.ymlで全体指定したり
## all.yml
ansible_python_interpreter: /path/to/python/bin

# set_factで定義
## something_role/tasks/main.yml
- name: Set python interpreter.
  set_fact:
    - ansible_python_interpreter: /path/to/python/bin

# inventoryで特定グループに対して定義
## inventory
[group_a:vars]
ansible_python_interpreter=/path/to/python/bin

# 実行時にextra-varsで指定
$ ansible-playbook site.yml -e 'ansible_python_interpreter=/path/to/python/bin'

limitやextra-varsはファイルに切り分けられる

上記オプションの引数は直接コマンドラインで渡す方法もありますが、ファイルに切り出すことも可能です。その場合は @file_name という形式で指定します。 [plain] $ ansible-playbook site.yml -i inventoryファイル –limit @limit_file –extra-vars @extra_vars_file [/plain] Ansibleでは、playbookの実行に失敗したときに対象ホストやグループ名を記述したretryファイルを生成します。retryファイルはlimitオプションで指定するように促されます。 [plain] ~省略(failedメッセージ)~ to retry, use: –limit @/root/ansible/test_task.retry PLAY RECAP ******************************************************************************************** cent : ok=0 changed=0 unreachable=0 failed=1
ubuntu : ok=0 changed=0 unreachable=0 failed=1 [/plain]

小ネタ

同名グループを2回inventoryに書いたとき

統合されます。こんな感じのinventoryがあったとします。
[group_a]
cent

[group_a]
ubuntu
以下のようなplaybookを用意(test_task.yml)
---
- hosts: all
  gather_facts: no
  tasks:
    - debug:
        var: groups
こうなります。
ansible-playbook test_task.yml -i inventory

PLAY [all] ********************************************************************************************

TASK [debug] ******************************************************************************************
ok: [cent] => {
    "groups": {
        "all": [
            "cent", 
            "ubuntu"
        ], 
        "group_a": [
            "cent", 
            "ubuntu"
        ], 
        "ungrouped": []
    }
}
ok: [ubuntu] => {
    "groups": {
        "all": [
            "cent", 
            "ubuntu"
        ], 
        "group_a": [
            "cent", 
            "ubuntu"
        ], 
        "ungrouped": []
    }
}

PLAY RECAP ********************************************************************************************
cent                     : ok=1    changed=0    unreachable=0    failed=0

ubuntu                   : ok=1    changed=0    unreachable=0    failed=0 

group_aにcent,ubuntuが所属していることが分かります。

まとめ

今回は個人的に引っかかった所や覚えておきたいところをまとめました。この中にお役に立てそうなものが1つでもあれば幸いです。 明日は@Ken-Moriizumiさんの溜まったアレをごっそり年末に掃除する話です。もう大掃除の時期ですね。掃除は重要な衛生活動です。それは物理世界に限った話ではありません。こまめな整理整頓を心掛けたいですね!私は掃除苦手ですけど。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です