【Ansible】ansible-playbook 取得した結果を JSON 形式で出力する方法

最近 Ansible を勉強しています。

「IT技術者のための現場ノウハウ Ansible 実践ガイド」を読んでいますが現場に近いエンジニアが記述しているので参考になります。

Ansible実践ガイド (impress top gear)

 

通常 Ansible は「インフラ構成管理ツール」として、複数台の Linux サーバーに対して一気にアップデートしたり、設定を変更するために利用するケースが多いと思いますが、上記の本を読むと「構成管理」に対して以下の2つの定義が説かれています。

 

Ansible のインストールと初期設定についてはこちらを参考してください。

 

Ansibleのインストールと初期設定について解説

 

 

構成管理とは

そもそも「構成管理」とは「ITサービスを効率よく提供するために必要な資産や成果物を維持管理するプロセス」で以下2つの定義が考えられます。

 

ITサービスとしての構成管理

ITサービスのライフサイクルにおける、ハードウェアやソフトウェア、仕様書や契約書における変更記録や、成果物を管理するプロセス

 

オペレーション自動化としての構成管理

最終的にある機器を、意図する状態に収束させるための設定および状態を管理するプロセス

 

つまりインフラにとってシステムに対して「設定」をすることも重要だし「状態」を把握することも重要なのです。

だからせっかく Ansible という強力なツール(しかも無料)を手に入れたわけですから「yum update」用に使うだけなのはもったいないわけです。(それだけでも十分ですが)

シェルも実行できるし、コマンドも実行できるのでもっといろんな使い方ができます。

 

Ansible で情報収集をする

素人的な使い方かもしれませんが、Ansible で情報収集もできますし、しかも便利です。

「Serverspec」というツールもありますが、Serverspec はあくまでも「正しいか」「正しくないか」をチェックするためのツールなので、情報収集用のツールとしてはやや使い勝手が悪いです。

「tomcat が特定のバージョンであること」→ 「真」か「偽」かという使い方なら Serverspec は非常に使い勝手がいいです。

しかし単純な情報収集なら Ansible が優れています。

 

Ansible が情報収集ツールに優れている理由

なぜ Ansible は情報収集ツールとして優れているのでしょうか?

 

抽象化ができる

OSの違い、バージョンの違いを吸収して Playbook を書くことができます。

これはシェルスクリプトではなかなかできません。

頑張ればできますが、かなり面倒で管理が大変です。(ヒューマンエラーが多発します)

しかし Ansible は抽象化ができているので、例えば「OS」の情報が欲しければ、ディストリビューションを気にせずに様々な情報を取得することができます。

 

JSON 形式で情報を取得できる

この機能が一番大きいと思います。

Ansible で収集した情報を一旦 JSON ファイルとして出力すれば、後は Python でも PHP でも Ruby でもデータを加工することが簡単にできます。

JSON 形式から欲しい情報を配列に入れることもできますし、多次元配列として情報を格納することも簡単にできますし、必要な情報のみ MySQL などのデータベースに保存することもできます。

とにかく JSON 形式でファイルを出力させることができるので、素材を様々な調理方法で調理することができるようになるわけです。

 

「なぜ Ansible が情報収集ツールとして優れているか?」私はこの JSON 形式で情報を取得できることが一番大きいと思います。

 

Ansible で情報を取得して JSON 形式で出力してみる

最初に ansible の設定を確認します。

ディレクトリ:/home/test/ansible

ファイル:hostlist

hostlist には、Ansible で管理するホストのリストを設定します。

[test@cent07 ansible]$ pwd
/home/test/ansible
[test@cent07 ansible]$ ls
hostlist
[test@cent07 ansible]$ cat hostlist
192.168.1.10
192.168.1.11
192.168.1.12

 

[all:vars]
ansible_ssh_port=22
ansible_ssh_user=test
ansible_ssh_pass=xxxxxxxx ← sshでログインする際のパスワードを設定します。
[test@cent07 ansible]$

 

 

最初に ping で疎通確認

ping で設定を確認します。

[test@cent07 ansible]$ ansible -i hostlist all -m ping
192.168.1.10 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.1.11 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
192.168.1.12 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
[test@cent07 ansible]$

 

疎通確認はOKです。

 

エラーが出た場合の対処

もし以下のようなエラーが出た場合の対処方法です。

[test@cent07 ansible]$ ansible -i hostlist all -m ping
192.168.1.10 | FAILED! => {
  "failed": true,
  "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
192.168.1.11 | FAILED! => {
  "failed": true,
  "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
192.168.1.12 | FAILED! => {
  "failed": true,
  "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
}
[test@cent07 ansible]$

 

 

Ansible の設定ファイル「/etc/ansible/ansible.cfg」を編集します。

[test@cent07 ansible]$ vi /etc/ansible/ansible.cfg
# config file for ansible -- https://ansible.com/
# ===============================================

# nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory or /etc/ansible/ansible.cfg, whichever it
# finds first

 

~ 省略 ~

 

# uncomment this to disable SSH key host checking
# host_key_checking = False

host_key_checking = False ← 「host_key_checking = False」をコメントアウトします。

 

ansible の結果を JSON で取得するために ansible-playbook で実行する

ansible で取得した情報を JSON 形式で取得するためには ansible

 

JSON用の「ansible.cfg」を作成します。

[test@cent07 ansible]$ vi json_ansible.cfg

[defaults]
stdout_callback = json

 

Playbook を作成します。

[test@cent07 ansible]$ vi test-check-os-playbook.yml
- hosts: all ← 全台に対して実施します。
  become: true ← rootになります。
  become_user: root ← rootになります。
  become_method: sudo ← rootになります。
  gather_facts: no ← 最初に情報を取得しないことで高速化を計っています。
  serial: 1 ← 順番が変わらないように1台ずつ情報を取得します。
  ignore_errors: True ← エラーが出力されると、ansible-playbook コマンドが終了してしまうので、最後まで情報を取得するように「ignore_errors」を入れます。
  tasks:
    - name: Check OS
      command: cat /etc/redhat-release ← 単純にディストリビューション情報を持ってくるだけです。

 

 

まずは通常の ansible-playbook コマンドです。

これは debug を入れていないため、単純にコマンドを実行しただけになります。

そのため、一見すると意味のない ansible-playbook コマンドになっています。

[test@cent07 ansible]$ ansible-playbook -i hostlist test-check-os-playbook.yml

 

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

 

TASK [Check OS] ****************************************************************************************
changed: [192.168.1.10]

 

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

 

TASK [Check OS] ****************************************************************************************
changed: [192.168.1.11]

 

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

 

TASK [Check OS] ****************************************************************************************
changed: [192.168.1.12]

 

PLAY RECAP *********************************************************************************************
192.168.1.10   : ok=1 changed=1 unreachable=0 failed=0
192.168.1.11   : ok=1 changed=1 unreachable=0 failed=0
192.168.1.12   : ok=1 changed=1 unreachable=0 failed=0

 

[test@cent07 ansible]$

 

 

次に JSON 形式で出力されるようにコンフィグを読み込んで実行してみます。

[test@cent07 ansible]$ ANSIBLE_CONFIG=/home/test/ansible/json_ansible.cfg ansible-playbook -i hostlist test-check-os-playbook.yml
{
  "plays": [
    {
      "play": {
        "id": "000c296b-9db5-2211-f7e0-000000000004",
        "name": "all"
      },
      "tasks": [
        {
          "hosts": {
            "192.168.1.10": {
              "_ansible_no_log": false,
              "_ansible_parsed": true,
              "changed": true,
              "cmd": [
                "cat",
                "/etc/redhat-release"
              ],
              "delta": "0:00:00.003863",
              "end": "2017-08-31 22:55:08.301404",
              "invocation": {
                "module_args": {
                  "_raw_params": "cat /etc/redhat-release",
                  "_uses_shell": false,
                  "chdir": null,
                  "creates": null,
                  "executable": null,
                  "removes": null,
                  "warn": true
                }
              },
              "rc": 0,
              "start": "2017-08-31 22:55:08.297541",
              "stderr": "",
              "stderr_lines": [],
              "stdout": "CentOS Linux release 7.3.1611 (Core) ",
              "stdout_lines": [
                "CentOS Linux release 7.3.1611 (Core) "
              ]
            }
          },
          "task": {
            "id": "000c296b-9db5-2211-f7e0-000000000006",
            "name": "Check OS"
          }
        }
      ]
    },
    {
      "play": {
        "id": "000c296b-9db5-2211-f7e0-000000000004",
        "name": "all"
      },
      "tasks": [
        {
          "hosts": {
            "192.168.1.11": {
              "_ansible_no_log": false,
              "_ansible_parsed": true,
              "changed": true,
              "cmd": [
                "cat",
                "/etc/redhat-release"
              ],
              "delta": "0:00:00.003512",
              "end": "2017-08-31 22:54:30.170146",
              "invocation": {
                "module_args": {
                  "_raw_params": "cat /etc/redhat-release",
                  "_uses_shell": false,
                  "chdir": null,
                  "creates": null,
                  "executable": null,
                  "removes": null,
                  "warn": true
                }
              },
              "rc": 0,
              "start": "2017-08-31 22:54:30.166634",
              "stderr": "",
              "stderr_lines": [],
              "stdout": "CentOS release 6.5 (Final)",
              "stdout_lines": [
                "CentOS release 6.5 (Final)"
              ]
            }
          },
          "task": {
            "id": "000c296b-9db5-2211-f7e0-000000000006",
            "name": "Check OS"
          }
        }
      ]
    },
    {
      "play": {
        "id": "000c296b-9db5-2211-f7e0-000000000004",
        "name": "all"
      },
      "tasks": [
        {
          "hosts": {
            "192.168.1.12": {
              "_ansible_no_log": false,
              "_ansible_parsed": true,
              "changed": true,
              "cmd": [
                "cat",
                "/etc/redhat-release"
              ],
              "delta": "0:00:00.005001",
              "end": "2017-08-31 22:55:21.260203",
              "invocation": {
                "module_args": {
                  "_raw_params": "cat /etc/redhat-release",
                  "_uses_shell": false,
                  "chdir": null,
                  "creates": null,
                  "executable": null,
                  "removes": null,
                  "warn": true
                }
              },
              "rc": 0,
              "start": "2017-08-31 22:55:21.255202",
              "stderr": "",
              "stderr_lines": [],
              "stdout": "CentOS Linux release 7.3.1611 (Core) ",
              "stdout_lines": [
                "CentOS Linux release 7.3.1611 (Core) "
              ]
            }
          },
          "task": {
            "id": "000c296b-9db5-2211-f7e0-000000000006",
            "name": "Check OS"
          }
        }
      ]
    }
  ],
  "stats": {
    "192.168.1.10": {
      "changed": 1,
      "failures": 0,
      "ok": 1,
      "skipped": 0,
      "unreachable": 0
    },
    "192.168.1.11": {
      "changed": 1,
      "failures": 0,
      "ok": 1,
      "skipped": 0,
      "unreachable": 0
    },
    "192.168.1.12": {
      "changed": 1,
      "failures": 0,
      "ok": 1,
      "skipped": 0,
      "unreachable": 0
    }
  }
}
[test@cent07 ansible]$

 

どうでしょうか。

かなり汎用性がありそうな感じで ansible-playbook が表示されました。

この JSON 形式の出力結果は、どの言語でも綺麗に処理できそうです。

 

 

Posted by 100%レンタルサーバーを使いこなすサイト管理人

コメントを残す

メールアドレスが公開されることはありません。