前回はテンプレートエンジンを使ったファイルの作成方法についてご紹介しました。今回はAnsibleが内部で用意しているグローバル変数Factについてまとめていきます。
Factの一覧を確認する
Ansibleにはシステム全体で利用するグローバル変数のような物が用意されており、必要に応じてPlaybookなどから利用することができます。これをFact
と呼びます。
Fact
に何が設定されているかは次のコマンドですべて表示することができます。serversの部分はInventoryファイルに記載したグループ名を指定してください。実際に実行すると非常に長大なリストがJSON形式で表示されます。
$ ansible servers -m setup example.com | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.0.1" ], "ansible_all_ipv6_addresses": [ "fe80::7c20:5cff:fe3d:4efd" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "08/24/2006", "ansible_bios_version": "4.2.amazon", (略)
FactはPlaybookからも参照できます。これを利用して例えばOSの種類ごとに実行するタスクを変更するなど細かい制御を行うことが可能になります。
Factの利用方法
Playbookの「条件」に利用する
Factにはansible_facts
という名前のハッシュを参照することでアクセスできます。お手軽すぎてちょっと怖いですねw 以下はOSのdistribution
がAmazonLinuxであればshellモジュールを実行するタスクの例になります。
- hosts: servers remote_user: ansibleman tasks: - name: write date if AmazonLinux shell: date >> ansible_fact.log when: ansible_facts["distribution"] == "Amazon"
Factの一覧を表示するコマンドではキーがansible_distribution
となっていましたが、最初の接頭詞ansible_
は削除し残った文字列を利用します。
$ ansible servers -m setup | grep distribution "ansible_distribution": "Amazon",
Playbookの「変数」に利用する
もちろんFactは変数の中でも利用できます。次の例ではファイルをコピーする際に、ディストリビューション毎に設定ファイルを切り替える処理に利用しています。
- hosts: servers remote_user: ansibleman vars: path: "conf/{{ ansible_facts[\"distribution\"] }}.conf" tasks: - name: write date if AmazonLinux copy: src: "{{ path }}" dest: ~/foo.conf
ファイル構成は以下の通り。confディレクトリの下にdistribution毎にファイルを用意してやります。
~/📁 ansible1st 📒 ansible.cfg 📒 playbook.yml 📁 inventory 📒 production 📁 conf 📒 Amazon.conf ★NEW 📒 CentOS.conf ★NEW 📒 RedHat.conf ★NEW
ちなみにFactへのアクセスはJavaScriptのようにansible_facts.distribution
とドットで区切る形式でも同じ意味になります。変数の一部として利用する際にはこちらの方がエスケープしなくて良いので使いやすいですね。お好みの書き方でどうぞ。
vars: path: "conf/{{ ansible_facts.distribution }}.conf"
templateで利用する
前回まとめたテンプレートの中でも利用できます。
Playbookの方は特別なことをする必要はありません。
- hosts: servers remote_user: ansibleman tasks: - name: include fact variable template: src: foo.txt.j2 dest: ~/foo.txt
Jinja2側の変数にそのままansible_facts
を書くことができます。
このサーバのディストリビューションは{{ ansible_facts.distribution }}です。
実際に実行すると埋め込まれているのがわかりますね。
$ ansible-playbook playbook.yml $ ssh ansibleman@exmaple.com [exmaple.com] $ cat foo.txt このサーバのディストリビューションはAmazonです。
Local Factsを設定する
管理対象のサーバへ事前にFactを定義したファイルを配置しておき、それをPlaybook上から呼び出すことができます。これをLocal Facts
と呼びます。例えば特定のサーバだけ特別な処理をしたいといった場合のトリガーに使うなど、アイデア次第で色々と活用できると思います。
公式ドキュメントによると、設置場所やフォーマットは以下の通り。
If a remotely managed system has an /etc/ansible/facts.d directory, any files in this directory ending in .fact, can be JSON, INI, or executable files returning JSON, and these can supply local facts in Ansible. An alternate directory can be specified using the fact_path play keyword.
/etc/ansible/facts.d
の下にファイルを配置する- ファイル形式はJSONかINI
- ファイルの拡張子は
.fact
では試しにやってみましょう。
サーバ側にfactファイルを用意
対象のサーバにログインし、所定の場所にファイルを置きます。今回はINI形式にしましたが、JSONでももちろん大丈夫。
$ ssh katsube@example.com [example.com] $ sudo mkdir -p /etc/ansible/facts.d [example.com] $ sudo vi /etc/ansible/facts.d/preferences.fact [general] message = Hiya, Georgie!
/etc/ansible/facts.d/
ディレクトリ配下に複数のファイルを配置した場合、拡張子が.fact
になっていればすべて読みこんでくれます。何らかの理由でファイルを分割したい場合でも対応可能です。
パスを変更するには?
Playbook上でfact_path
の項目を追加するだけでOKです。
- hosts: servers fact_path: ~/fact.d/
Playbookから参照する
Local Factの場合はansible_local
を参照します。
- hosts: servers remote_user: ansibleman tasks: - name: include local fact variable shell: echo "{{ ansible_local.preferences.general.message }}" >> ansible-fact.log
何となく想像がつくと思いますが、ansible_local[ファイル名][グループ][項目]
という具合に指定してやります。
実行する
実行すると、無事に事前に設定した値を取得することができました。
$ ansible-playbook playbook.yml $ ssh ansibleman@exmaple.com [exmaple.com] $ cat ansible-fact.log Hiya, Georgie!
繰り返しになりますがLocal Factsの定義ファイルはPlaybookを実行するPCではなく、管理対象のサーバに置く必要があることに注意してください。
その他
Factを無効にする
Factを利用しないことが最初からわかっている場合はgather_facts
にno
を設定することで無効化することができます。
- hosts: servers remote_user: ansibleman gather_facts: no tasks: - name: foobar shell: ls
AnsibleがFactに情報を収集する処理はそれなりに時間がかかります。大量のサーバ群に対して実行するようなケースで、予め環境情報が判明しているような場合はOFFにした方が実行速度を上げることが期待できます。
Fact一覧
最後にansible servers -m setup
の実行結果を掲載します。ここではAmazonLinuxに対して実行しています。
{ "ansible_facts": { "ansible_all_ipv4_addresses": [ "172.26.4.60" ], "ansible_all_ipv6_addresses": [ "fe80::467:75ff:fe48:c35c" ], "ansible_apparmor": { "status": "disabled" }, "ansible_architecture": "x86_64", "ansible_bios_date": "08/24/2006", "ansible_bios_version": "4.2.amazon", "ansible_cmdline": { "KEYTABLE": "us", "LANG": "en_US.UTF-8", "console": "ttyS0", "nvme_core.io_timeout": "4294967295", "root": "LABEL=/", "selinux": "0" }, "ansible_date_time": { "date": "2019-11-08", "day": "08", "epoch": "1573220817", "hour": "22", "iso8601": "2019-11-08T13:46:57Z", "iso8601_basic": "20191108T224657973495", "iso8601_basic_short": "20191108T224657", "iso8601_micro": "2019-11-08T13:46:57.973578Z", "minute": "46", "month": "11", "second": "57", "time": "22:46:57", "tz": "JST", "tz_offset": "+0900", "weekday": "金曜日", "weekday_number": "5", "weeknumber": "44", "year": "2019" }, "ansible_default_ipv4": { "address": "172.26.4.60", "alias": "eth0", "broadcast": "172.26.15.255", "gateway": "172.26.0.1", "interface": "eth0", "macaddress": "06:67:75:48:c3:5c", "mtu": 9001, "netmask": "255.255.240.0", "network": "172.26.0.0", "type": "ether" }, "ansible_default_ipv6": {}, "ansible_device_links": { "ids": {}, "labels": { "xvda1": [ "\\x2f" ] }, "masters": {}, "uuids": { "xvda1": [ "f25f5092-0401-4edb-9fac-c57f3c673803" ] } }, "ansible_devices": { "xvda": { "holders": [], "host": "", "links": { "ids": [], "labels": [], "masters": [], "uuids": [] }, "model": null, "partitions": { "xvda1": { "holders": [], "links": { "ids": [], "labels": [ "\\x2f" ], "masters": [], "uuids": [ "f25f5092-0401-4edb-9fac-c57f3c673803" ] }, "sectors": "167768031", "sectorsize": 512, "size": "80.00 GB", "start": "4096", "uuid": "f25f5092-0401-4edb-9fac-c57f3c673803" } }, "removable": "0", "rotational": "0", "sas_address": null, "sas_device_handle": null, "scheduler_mode": "noop", "sectors": "167772160", "sectorsize": "512", "size": "80.00 GB", "support_discard": "0", "vendor": null, "virtual": 1 } }, "ansible_distribution": "Amazon", "ansible_distribution_file_parsed": true, "ansible_distribution_file_path": "/etc/system-release", "ansible_distribution_file_variety": "Amazon", "ansible_distribution_major_version": "2018", "ansible_distribution_release": "NA", "ansible_distribution_version": "NA", "ansible_dns": { "nameservers": [ "172.26.0.2" ], "options": { "attempts": "5", "timeout": "2" }, "search": [ "ap-northeast-1.compute.internal" ] }, "ansible_domain": "ap-northeast-1.compute.internal", "ansible_effective_group_id": 503, "ansible_effective_user_id": 502, "ansible_env": { "AWS_AUTO_SCALING_HOME": "/opt/aws/apitools/as", "AWS_CLOUDWATCH_HOME": "/opt/aws/apitools/mon", "AWS_ELB_HOME": "/opt/aws/apitools/elb", "AWS_PATH": "/opt/aws", "EC2_AMITOOL_HOME": "/opt/aws/amitools/ec2", "EC2_HOME": "/opt/aws/apitools/ec2", "HOME": "/home/ansibleman", "JAVA_HOME": "/usr/lib/jvm/jre", "LANG": "ja_JP.UTF-8", "LESSOPEN": "||/usr/bin/lesspipe.sh %s", "LESS_TERMCAP_mb": "\u001b[01;31m", "LESS_TERMCAP_md": "\u001b[01;38;5;208m", "LESS_TERMCAP_me": "\u001b[0m", "LESS_TERMCAP_se": "\u001b[0m", "LESS_TERMCAP_ue": "\u001b[0m", "LESS_TERMCAP_us": "\u001b[04;38;5;111m", "LOGNAME": "ansibleman", "MAIL": "/var/mail/ansibleman", "PATH": "/usr/local/bin:/bin:/usr/bin:/opt/aws/bin", "PWD": "/home/ansibleman", "PYTHON_INSTALL_LAYOUT": "amzn", "SHELL": "/bin/bash", "SHLVL": "2", "SSH_CLIENT": "110.233.244.246 52359 50022", "SSH_CONNECTION": "110.233.244.246 52359 172.26.4.60 50022", "SSH_TTY": "/dev/pts/1", "TERM": "xterm-256color", "USER": "ansibleman", "_": "/usr/bin/python" }, "ansible_eth0": { "active": true, "device": "eth0", "features": { "esp_hw_offload": "off [fixed]", "esp_tx_csum_hw_offload": "off [fixed]", "fcoe_mtu": "off [fixed]", "generic_receive_offload": "on", "generic_segmentation_offload": "on", "highdma": "off [fixed]", "hw_tc_offload": "off [fixed]", "l2_fwd_offload": "off [fixed]", "large_receive_offload": "off [fixed]", "loopback": "off [fixed]", "netns_local": "off [fixed]", "ntuple_filters": "off [fixed]", "receive_hashing": "off [fixed]", "rx_all": "off [fixed]", "rx_checksumming": "on [fixed]", "rx_fcs": "off [fixed]", "rx_udp_tunnel_port_offload": "off [fixed]", "rx_vlan_filter": "off [fixed]", "rx_vlan_offload": "off [fixed]", "rx_vlan_stag_filter": "off [fixed]", "rx_vlan_stag_hw_parse": "off [fixed]", "scatter_gather": "on", "tcp_segmentation_offload": "on", "tx_checksum_fcoe_crc": "off [fixed]", "tx_checksum_ip_generic": "off [fixed]", "tx_checksum_ipv4": "on [fixed]", "tx_checksum_ipv6": "off [requested on]", "tx_checksum_sctp": "off [fixed]", "tx_checksumming": "on", "tx_esp_segmentation": "off [fixed]", "tx_fcoe_segmentation": "off [fixed]", "tx_gre_csum_segmentation": "off [fixed]", "tx_gre_segmentation": "off [fixed]", "tx_gso_partial": "off [fixed]", "tx_gso_robust": "on [fixed]", "tx_ipxip4_segmentation": "off [fixed]", "tx_ipxip6_segmentation": "off [fixed]", "tx_lockless": "off [fixed]", "tx_nocache_copy": "off", "tx_scatter_gather": "on", "tx_scatter_gather_fraglist": "off [fixed]", "tx_sctp_segmentation": "off [fixed]", "tx_tcp6_segmentation": "off [requested on]", "tx_tcp_ecn_segmentation": "off [fixed]", "tx_tcp_mangleid_segmentation": "off", "tx_tcp_segmentation": "on", "tx_udp_tnl_csum_segmentation": "off [fixed]", "tx_udp_tnl_segmentation": "off [fixed]", "tx_vlan_offload": "off [fixed]", "tx_vlan_stag_hw_insert": "off [fixed]", "udp_fragmentation_offload": "off", "vlan_challenged": "off [fixed]" }, "hw_timestamp_filters": [], "ipv4": { "address": "172.26.4.60", "broadcast": "172.26.15.255", "netmask": "255.255.240.0", "network": "172.26.0.0" }, "ipv6": [ { "address": "fe80::467:75ff:fe48:c35c", "prefix": "64", "scope": "link" } ], "macaddress": "06:67:75:48:c3:5c", "module": "xen_netfront", "mtu": 9001, "pciid": "vif-0", "promisc": false, "timestamping": [ "rx_software", "software" ], "type": "ether" }, "ansible_fibre_channel_wwn": [], "ansible_fips": false, "ansible_form_factor": "Other", "ansible_fqdn": "ip-172-26-4-60.ap-northeast-1.compute.internal", "ansible_hostname": "ip-172-26-4-60", "ansible_hostnqn": "", "ansible_interfaces": [ "lo", "eth0" ], "ansible_is_chroot": false, "ansible_iscsi_iqn": "", "ansible_kernel": "4.14.114-82.97.amzn1.x86_64", "ansible_lo": { "active": true, "device": "lo", "features": { "esp_hw_offload": "off [fixed]", "esp_tx_csum_hw_offload": "off [fixed]", "fcoe_mtu": "off [fixed]", "generic_receive_offload": "on", "generic_segmentation_offload": "on", "highdma": "on [fixed]", "hw_tc_offload": "off [fixed]", "l2_fwd_offload": "off [fixed]", "large_receive_offload": "off [fixed]", "loopback": "on [fixed]", "netns_local": "on [fixed]", "ntuple_filters": "off [fixed]", "receive_hashing": "off [fixed]", "rx_all": "off [fixed]", "rx_checksumming": "on [fixed]", "rx_fcs": "off [fixed]", "rx_udp_tunnel_port_offload": "off [fixed]", "rx_vlan_filter": "off [fixed]", "rx_vlan_offload": "off [fixed]", "rx_vlan_stag_filter": "off [fixed]", "rx_vlan_stag_hw_parse": "off [fixed]", "scatter_gather": "on", "tcp_segmentation_offload": "on", "tx_checksum_fcoe_crc": "off [fixed]", "tx_checksum_ip_generic": "on [fixed]", "tx_checksum_ipv4": "off [fixed]", "tx_checksum_ipv6": "off [fixed]", "tx_checksum_sctp": "on [fixed]", "tx_checksumming": "on", "tx_esp_segmentation": "off [fixed]", "tx_fcoe_segmentation": "off [fixed]", "tx_gre_csum_segmentation": "off [fixed]", "tx_gre_segmentation": "off [fixed]", "tx_gso_partial": "off [fixed]", "tx_gso_robust": "off [fixed]", "tx_ipxip4_segmentation": "off [fixed]", "tx_ipxip6_segmentation": "off [fixed]", "tx_lockless": "on [fixed]", "tx_nocache_copy": "off [fixed]", "tx_scatter_gather": "on [fixed]", "tx_scatter_gather_fraglist": "on [fixed]", "tx_sctp_segmentation": "on", "tx_tcp6_segmentation": "on", "tx_tcp_ecn_segmentation": "on", "tx_tcp_mangleid_segmentation": "on", "tx_tcp_segmentation": "on", "tx_udp_tnl_csum_segmentation": "off [fixed]", "tx_udp_tnl_segmentation": "off [fixed]", "tx_vlan_offload": "off [fixed]", "tx_vlan_stag_hw_insert": "off [fixed]", "udp_fragmentation_offload": "off", "vlan_challenged": "on [fixed]" }, "hw_timestamp_filters": [], "ipv4": { "address": "127.0.0.1", "broadcast": "host", "netmask": "255.0.0.0", "network": "127.0.0.0" }, "ipv6": [ { "address": "::1", "prefix": "128", "scope": "host" } ], "mtu": 65536, "promisc": false, "timestamping": [ "tx_software", "rx_software", "software" ], "type": "loopback" }, "ansible_local": { "preferences": { "general": { "message": "Hiya, Georgie!" } } }, "ansible_lsb": {}, "ansible_machine": "x86_64", "ansible_machine_id": "9aa32d5b81fc647aabb1f5835cd420af", "ansible_memfree_mb": 344, "ansible_memory_mb": { "nocache": { "free": 3557, "used": 388 }, "real": { "free": 344, "total": 3945, "used": 3601 }, "swap": { "cached": 0, "free": 1023, "total": 1023, "used": 0 } }, "ansible_memtotal_mb": 3945, "ansible_mounts": [ { "block_available": 18312080, "block_size": 4096, "block_total": 20609191, "block_used": 2297111, "device": "/dev/xvda1", "fstype": "ext4", "inode_available": 5153095, "inode_total": 5242880, "inode_used": 89785, "mount": "/", "options": "rw,noatime,data=ordered", "size_available": 75006279680, "size_total": 84415246336, "uuid": "f25f5092-0401-4edb-9fac-c57f3c673803" } ], "ansible_nodename": "ip-172-26-4-60", "ansible_os_family": "RedHat", "ansible_pkg_mgr": "dnf", "ansible_proc_cmdline": { "KEYTABLE": "us", "LANG": "en_US.UTF-8", "console": [ "tty1", "ttyS0" ], "nvme_core.io_timeout": "4294967295", "root": "LABEL=/", "selinux": "0" }, "ansible_processor": [ "0", "GenuineIntel", "Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz", "1", "GenuineIntel", "Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz" ], "ansible_processor_cores": 2, "ansible_processor_count": 1, "ansible_processor_threads_per_core": 1, "ansible_processor_vcpus": 2, "ansible_product_name": "HVM domU", "ansible_product_serial": "NA", "ansible_product_uuid": "NA", "ansible_product_version": "4.2.amazon", "ansible_python": { "executable": "/usr/bin/python", "has_sslcontext": true, "type": "CPython", "version": { "major": 2, "micro": 16, "minor": 7, "releaselevel": "final", "serial": 0 }, "version_info": [ 2, 7, 16, "final", 0 ] }, "ansible_python_version": "2.7.16", "ansible_real_group_id": 503, "ansible_real_user_id": 502, "ansible_selinux": { "status": "Missing selinux Python library" }, "ansible_selinux_python_present": false, "ansible_service_mgr": "upstart", "ansible_ssh_host_key_dsa_public": "(公開鍵)", "ansible_ssh_host_key_ecdsa_public": "(公開鍵)", "ansible_ssh_host_key_ed25519_public": "(公開鍵)", "ansible_ssh_host_key_rsa_public": "(公開鍵)", "ansible_swapfree_mb": 1023, "ansible_swaptotal_mb": 1023, "ansible_system": "Linux", "ansible_system_capabilities": [ "" ], "ansible_system_capabilities_enforced": "True", "ansible_system_vendor": "Xen", "ansible_uptime_seconds": 15630159, "ansible_user_dir": "/home/ansibleman", "ansible_user_gecos": "", "ansible_user_gid": 503, "ansible_user_id": "ansibleman", "ansible_user_shell": "/bin/bash", "ansible_user_uid": 502, "ansible_userspace_architecture": "x86_64", "ansible_userspace_bits": "64", "ansible_virtualization_role": "guest", "ansible_virtualization_type": "xen", "gather_subset": [ "all" ], "module_setup": true }, "changed": false }
参考ページ
インプレス (2019-10-18)
売り上げランキング: 17,753