最近チームで障害調査の割合が増えだしたのでざっとまとめてみた。
ansibleコマンドを使って複数ホストに対して同じ処理を同時に行う。
メンテや障害調査で何十台もあるホストに同じコマンド実行したりログ収集したり。
普段はansible-playbookで作成したplaybookの内容を処理させてるけど、ワンショットでちょっとした操作をしたい場合に使う。
コマンドの基本は以下の通り。
ansible all -i /path/to/inventory [-b] -m <module name> -a <module arguments>
allはinventoryファイルに記述してるグループ名。allだと全ノードで、その他はinventoryの内容に拠る-i inventoryはinventoryファイルの指定。どのホストにアクセスするかを記述している-bは付けるとroot権限での実行-m <module name>は使うモジュール名。省略時はcommandになる。だいたいshell・fetch・copyを使うことになる気がする-a <module argument>はモジュールに対する引数。普段playbookにyamlで書く内容をここに書き足す。shellならリモートで実行するコマンド名とか
そのほかはansible --help見てね。
Ansibleはすでに使える状態とする。
(Ansible使って構築したシステムが対象で、inventoryファイルも見れる状態、みたいな)
環境 (CentOS 7)
[vagrant@ansible-controller ~]$ ansible --version ansible 2.6.14 config file = /etc/ansible/ansible.cfg configured module search path = [u'/home/vagrant/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Oct 30 2018, 23:45:53) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
※ 注意: あくまで調査のためなどのワンショット用。定型のコマンド実行がいくつもある場合は「ansibleコマンド実行を並べてシェルスクリプトにすればいいんじゃね?」ではなく、playbook書こうね
ping
まずは疎通確認。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini
-m ping
ansible-node01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-node02 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-controller | SUCCESS => {
"changed": false,
"ping": "pong"
}
-m pingでping moduleを使用する。
全台でコマンド実行
例としてdf -hを全ホストで実行。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -a "df -h" ansible-node02 | SUCCESS | rc=0 >> Filesystem Size Used Avail Use% Mounted on /dev/sda1 40G 3.3G 37G 9% / devtmpfs 489M 0 489M 0% /dev tmpfs 496M 0 496M 0% /dev/shm tmpfs 496M 6.7M 489M 2% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup ansible 476G 261G 215G 55% /ansible tmpfs 100M 0 100M 0% /run/user/1000 ansible-node01 | SUCCESS | rc=0 >> Filesystem Size Used Avail Use% Mounted on /dev/sda1 40G 3.3G 37G 9% / devtmpfs 489M 0 489M 0% /dev tmpfs 496M 0 496M 0% /dev/shm tmpfs 496M 6.7M 489M 2% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup ansible 476G 261G 215G 55% /ansible tmpfs 100M 0 100M 0% /run/user/1000 ansible-controller | SUCCESS | rc=0 >> Filesystem Size Used Avail Use% Mounted on /dev/sda1 40G 3.4G 37G 9% / devtmpfs 489M 0 489M 0% /dev tmpfs 496M 160K 496M 1% /dev/shm tmpfs 496M 6.7M 489M 2% /run tmpfs 496M 0 496M 0% /sys/fs/cgroup ansible 476G 261G 215G 55% /ansible tmpfs 100M 0 100M 0% /run/user/1000 [vagrant@ansible-controller ~]$
-m <module name>を省略すると、commandモジュールが使われる。
モジュールへの引数(この場合df -h)は-aオプションで指定する。
shellモジュールじゃないのでdf -h > /tmp/df.logみたいなことはできない。
リダイレクトとかが必要なら-m shellを指定するか、-a "bash -c 'df -h > /tmp/df.log'"みたいに書く。
ホスト名を変数として参照する
inventoryに記述してる「Ansible実行ノードから見たホスト名」は{{ inventory_hostname }}で参照できる。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -a "echo {{ inventory_hostname }}"
ansible-node02 | SUCCESS | rc=0 >>
ansible-node02
ansible-node01 | SUCCESS | rc=0 >>
ansible-node01
ansible-controller | SUCCESS | rc=0 >>
ansible-controller
[vagrant@ansible-controller ~]$
ファイルの取得(リモートからget)
fetchモジュールを使う。
ログファイルを収集するときとか。
flat=yesは付けないとフルパスで取得するので、ファイル1個持ってくるような場合は付けたほうが良いかも。
$ ansible all -i /ansible/practice/inventory.ini -m fetch -a "src=/tmp/df.log dest=/tmp/df.log flat=yes"
ちなみに↑こうすると、全ホストのファイルをローカルの/tmp/df.logに転送してしまって最後に実行したホストのファイルしか残らないので、転送後ファイル名には{{ inventory_hostname }}を使うと良い。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -m fetch -a "src=/tmp/df.log dest=/tmp/df-{{ inventory_hostname }}.log flat=yes"
ansible-node02 | SUCCESS => {
"changed": true,
"checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"dest": "/tmp/df-ansible-node02.log",
"md5sum": "5d0209756abf2aff520810a025f6f8ee",
"remote_checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"remote_md5sum": null
}
ansible-node01 | SUCCESS => {
"changed": true,
"checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"dest": "/tmp/df-ansible-node01.log",
"md5sum": "5d0209756abf2aff520810a025f6f8ee",
"remote_checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"remote_md5sum": null
}
ansible-controller | SUCCESS => {
"changed": true,
"checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"dest": "/tmp/df-ansible-controller.log",
"md5sum": "5d0209756abf2aff520810a025f6f8ee",
"remote_checksum": "01d36a6de187e0f927f4125396d48437ed78dd58",
"remote_md5sum": null
}
[vagrant@ansible-controller ~]$
[vagrant@ansible-controller ~]$ ll /tmp/df* -rw-rw-r--. 1 vagrant vagrant 375 Oct 8 21:59 /tmp/df-ansible-controller.log -rw-rw-r--. 1 vagrant vagrant 375 Oct 8 21:59 /tmp/df-ansible-node01.log -rw-rw-r--. 1 vagrant vagrant 375 Oct 8 21:59 /tmp/df-ansible-node02.log [vagrant@ansible-controller ~]$
ファイルの送信(リモートへpush)
copyモジュールを使う。
調査用スクリプトを各ホストに配置して実行、みたいなケースでファイルを送信する。
[vagrant@ansible-controller ~]$ ll ~/script.sh
-rw-rw-r--. 1 vagrant vagrant 5 Oct 8 22:02 /home/vagrant/script.sh
[vagrant@ansible-controller ~]$
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini
-m copy -a "src=~/script.sh dest=/tmp/"
ansible-node01 | SUCCESS => {
"changed": true,
"checksum": "eefd5bc2c547bf82b177b6259c13f7723dc876d9",
"dest": "/tmp/script.sh",
"gid": 1000,
"group": "vagrant",
"md5sum": "c59548c3c576228486a1f0037eb16a1b",
"mode": "0664",
"owner": "vagrant",
"secontext": "unconfined_u:object_r:user_home_t:s0",
"size": 5,
"src": "/home/vagrant/.ansible/tmp/ansible-tmp-1570572200.39-212610671017175/source",
"state": "file",
"uid": 1000
}
ansible-node02 | SUCCESS => {
"changed": true,
"checksum": "eefd5bc2c547bf82b177b6259c13f7723dc876d9",
"dest": "/tmp/script.sh",
"gid": 1000,
"group": "vagrant",
"md5sum": "c59548c3c576228486a1f0037eb16a1b",
"mode": "0664",
"owner": "vagrant",
"secontext": "unconfined_u:object_r:user_home_t:s0",
"size": 5,
"src": "/home/vagrant/.ansible/tmp/ansible-tmp-1570572200.14-254346991562955/source",
"state": "file",
"uid": 1000
}
ansible-controller | SUCCESS => {
"changed": true,
"checksum": "eefd5bc2c547bf82b177b6259c13f7723dc876d9",
"dest": "/tmp/script.sh",
"gid": 1000,
"group": "vagrant",
"md5sum": "c59548c3c576228486a1f0037eb16a1b",
"mode": "0664",
"owner": "vagrant",
"secontext": "unconfined_u:object_r:user_home_t:s0",
"size": 5,
"src": "/home/vagrant/.ansible/tmp/ansible-tmp-1570572200.23-184499488704481/source",
"state": "file",
"uid": 1000
}
[vagrant@ansible-controller ~]$
特権(root権限)での実行
/var/log/messagesを転送したりする場合。-bを使う。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -b -a "head -1 /var/log/messages" ansible-node01 | SUCCESS | rc=0 >> Aug 25 03:27:01 ansible-node01 rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-34.el7" x-pid="2553" x-info="http://www.rsyslog.com"] rsyslogd was HUPed ansible-node02 | SUCCESS | rc=0 >> Aug 25 03:15:02 ansible-node02 rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-34.el7" x-pid="2560" x-info="http://www.rsyslog.com"] rsyslogd was HUPed ansible-controller | SUCCESS | rc=0 >> Aug 25 03:39:01 ansible-controller rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-34.el7" x-pid="2553" x-info="http://www.rsyslog.com"] rsyslogd was HUPed [vagrant@ansible-controller ~]$
-b(--become)がないと、実行しているユーザ権限になるのでroot権限が必要な操作はエラーになる。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -a "head -1 /var/log/messages" ansible-node02 | FAILED | rc=1 >> head: cannot open ‘/var/log/messages’ for reading: Permission deniednon-zero return code ansible-node01 | FAILED | rc=1 >> head: cannot open ‘/var/log/messages’ for reading: Permission deniednon-zero return code ansible-controller | FAILED | rc=1 >> head: cannot open ‘/var/log/messages’ for reading: Permission deniednon-zero return code [vagrant@ansible-controller ~]$
shellやfetch・copyなど、ほかの操作も同様。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -m fetch -b -a "src=/var/log/messages dest=/tmp/messages-{{ inventory_hostname }}.log flat=yes"
ansible-node02 | SUCCESS => {
"changed": true,
"checksum": "bcbfea8c6f6c2fbb2ab029f6768c4fce68cc956e",
"dest": "/tmp/messages-ansible-node02.log",
"md5sum": "fe0451caa2a48f85eded78602e8d26c7",
"remote_checksum": "bcbfea8c6f6c2fbb2ab029f6768c4fce68cc956e",
"remote_md5sum": null
}
ansible-node01 | SUCCESS => {
"changed": true,
"checksum": "6039559ed28f2f8dcb4868b7cbcdc847ade7c411",
"dest": "/tmp/messages-ansible-node01.log",
"md5sum": "0b5fb83405738892c5cdc5361541370a",
"remote_checksum": "6039559ed28f2f8dcb4868b7cbcdc847ade7c411",
"remote_md5sum": null
}
ansible-controller | SUCCESS => {
"changed": true,
"checksum": "ea9db0b38da4672e42bb16b0685730b1b3a5cd75",
"dest": "/tmp/messages-ansible-controller.log",
"md5sum": "99981f36e54dbdb954d8ecf32e1f6a11",
"remote_checksum": "ea9db0b38da4672e42bb16b0685730b1b3a5cd75",
"remote_md5sum": null
}
[vagrant@ansible-controller ~]$
鍵認証設定してない場合
-kを使う。
[vagrant@ansible-controller ~]$ ansible all -i /ansible/practice/inventory.ini -m ping -k
SSH password:
ansible-node02 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-node01 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-controller | SUCCESS => {
"changed": false,
"ping": "pong"
}
[vagrant@ansible-controller ~]$
-kを付けると公開鍵認証でなくパスワード認証になる。
「アドホック コマンド」というのはAnsibleユーザ会のもくもく会に参加して初めて聞いたんだけど、helpメッセージの最後の行に出てましたわ…
[vagrant@ansible-controller ~]$ ansible --help
Usage: ansible <host-pattern> [options]
Define and run a single task 'playbook' against a set of hosts
Options:
-a MODULE_ARGS, --args=MODULE_ARGS
module arguments
--ask-vault-pass ask for vault password
-B SECONDS, --background=SECONDS
run asynchronously, failing after X seconds
(default=N/A)
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-e EXTRA_VARS, --extra-vars=EXTRA_VARS
set additional variables as key=value or YAML/JSON, if
filename prepend with @
-f FORKS, --forks=FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory=INVENTORY, --inventory-file=INVENTORY
specify inventory host path or comma separated host
list. --inventory-file is deprecated
-l SUBSET, --limit=SUBSET
further limit selected hosts to an additional pattern
--list-hosts outputs a list of matching hosts; does not execute
anything else
-m MODULE_NAME, --module-name=MODULE_NAME
module name to execute (default=command)
-M MODULE_PATH, --module-path=MODULE_PATH
prepend colon-separated path(s) to module library
(default=[u'/home/vagrant/.ansible/plugins/modules',
u'/usr/share/ansible/plugins/modules'])
-o, --one-line condense output
--playbook-dir=BASEDIR
Since this tool does not use playbooks, use this as a
subsitute playbook directory.This sets the relative
path for many features including roles/ group_vars/
etc.
-P POLL_INTERVAL, --poll=POLL_INTERVAL
set the poll interval if using -B (default=15)
--syntax-check perform a syntax check on the playbook, but do not
execute it
-t TREE, --tree=TREE log output to this directory
--vault-id=VAULT_IDS the vault identity to use
--vault-password-file=VAULT_PASSWORD_FILES
vault password file
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
--version show program's version number and exit
Connection Options:
control as whom and how to connect to hosts
-k, --ask-pass ask for connection password
--private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE
use this file to authenticate the connection
-u REMOTE_USER, --user=REMOTE_USER
connect as this user (default=None)
-c CONNECTION, --connection=CONNECTION
connection type to use (default=smart)
-T TIMEOUT, --timeout=TIMEOUT
override the connection timeout in seconds
(default=10)
--ssh-common-args=SSH_COMMON_ARGS
specify common arguments to pass to sftp/scp/ssh (e.g.
ProxyCommand)
--sftp-extra-args=SFTP_EXTRA_ARGS
specify extra arguments to pass to sftp only (e.g. -f,
-l)
--scp-extra-args=SCP_EXTRA_ARGS
specify extra arguments to pass to scp only (e.g. -l)
--ssh-extra-args=SSH_EXTRA_ARGS
specify extra arguments to pass to ssh only (e.g. -R)
Privilege Escalation Options:
control how and which user you become as on target hosts
-s, --sudo run operations with sudo (nopasswd) (deprecated, use
become)
-U SUDO_USER, --sudo-user=SUDO_USER
desired sudo user (default=root) (deprecated, use
become)
-S, --su run operations with su (deprecated, use become)
-R SU_USER, --su-user=SU_USER
run operations with su as this user (default=None)
(deprecated, use become)
-b, --become run operations with become (does not imply password
prompting)
--become-method=BECOME_METHOD
privilege escalation method to use (default=sudo),
valid choices: [ sudo | su | pbrun | pfexec | doas |
dzdo | ksu | runas | pmrun | enable | machinectl ]
--become-user=BECOME_USER
run operations as this user (default=root)
--ask-sudo-pass ask for sudo password (deprecated, use become)
--ask-su-pass ask for su password (deprecated, use become)
-K, --ask-become-pass
ask for privilege escalation password
Some modules do not make sense in Ad-Hoc (include, meta, etc)