最近チームで障害調査の割合が増えだしたのでざっとまとめてみた。
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)