ansible 知识点
- 1. 剧本
- 2. facts变量
- 3. register变量
- 4. include功能
- 5. handlers
- 6. when 条件
- 7. with_items 循环
- 8. Jinja2模板
- 9. group_vars
- 10. roles :star::star::star:
看起来字数很多,实际有很多是脚本执行结果,内容不多哦
1. 剧本
剧本很重要的就是,定义演员的信息(其实就是定义主机的信息),演员的具体任务(以及主机要执行的模块,动作)
ansible剧本也是由两个最基本的部分组成
-
hosts
定义的被管理的主机列表信息(演员有哪些) -
tasks
关键词定义的是被管理主机需要执行的动作(演员要做什么事)
剧本格式:
# 1
---
- name: first taskhosts: db
# gather_facts: novars:var1: avar2: btasks:- name: task1command:..- name: task2command:..
- name: second taskhosts: web- name: task1 command:.....
# 2
---
- hosts: allvars:var1: avar2: btasks:- name: task1 ...
[官网内置模块说明](Ansible.Builtin — Ansible Community Documentation)
安装nfs
[root@localhost ansible]# cat 01.nfs_install.yml
---
- hosts: allgather_facts: yestasks:- name: backup reposhell: "if [ -f /etc/yum.repos.d/CentOS-Base.repo ];then mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak; fi"- name: update yum repoyum_repository:name: aliyun_repodescription: aliyun linux repositorybaseurl: http://mirrors.aliyun.com/repo/Centos-{{ ansible_distribution_major_version }}.repoenabled: yesgpgcheck: no- name: install nfs rpcbindyum:name: "{{ item }}"state: presentwith_items:- rpcbind- nfs-utils- name: started serversystemd:name: "{{ item }}"state: startedenabled: yeswith_items:- rpcbind- nfs-utils
[root@localhost ansible]# ansible-playbook -i hosts 01.nfs_install.ymlPLAY [all] *************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [backup repo] *****************************************************************************************************************************************************
changed: [182.92.85.212]TASK [update yum repo] *************************************************************************************************************************************************
changed: [182.92.85.212]TASK [install nfs rpcbind] *********************************************************************************************************************************************
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions is deprecated. Instead of using a loop to supply multiple items and specifying
`name: "{{ item }}"`, please use `name: ['rpcbind', 'nfs-utils']` and remove the loop. This feature will be removed in version 2.11. Deprecation warnings can be
disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [182.92.85.212] => (item=[u'rpcbind', u'nfs-utils'])TASK [started server] **************************************************************************************************************************************************
ok: [182.92.85.212] => (item=rpcbind)
changed: [182.92.85.212] => (item=nfs-utils)PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
笔者发现新版本的ansible,yum已经被dnf取代了,不过目前yum仍可用
2.9及以前版本还能搜到yum的说明,以后的版本就只能搜dnf喽
2. facts变量
在Ansible中,事实变量(facts)是由Ansible自动从受管主机收集的系统信息。这些事实变量包含了与主机相关的各类信息,并且可以在playbook中用于条件判断、循环等场景。
每次运行playbook中的每个play时,Ansible会自动运行一个名为setup
的模块来收集受管主机的事实信息。这些信息包含如下内容:
- 主机名称
- 内核版本
- 网络接口
- IP地址
- 操作系统版本
- 各种环境变量
- CPU数量
- 提供的或可用的内存
- 可用磁盘空间
查看详细信息
[root@localhost ansible]# ansible-playbook -i hosts 02.facts.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [print host msg] **************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": {"all_ipv4_addresses": ["172.19.91.7"],"all_ipv6_addresses": ["fe80::216:3eff:fe34:19c2"],"ansible_local": {},"apparmor": {"status": "disabled"},"architecture": "x86_64","bios_date": "04/01/2014","bios_version": "449e491","cmdline": {"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-1160.119.1.el7.x86_64","console": "ttyS0,115200n8","crashkernel": "auto","net.ifnames": "0","noibrs": true,"nvme_core.admin_timeout": "4294967295","nvme_core.io_timeout": "4294967295","quiet": true,"rhgb": true,"ro": true,"root": "UUID=c8b5b2da-5565-4dc1-b002-2a8b07573e22","spectre_v2": "retpoline"},"date_time": {"date": "2025-01-08","day": "08","epoch": "1736304161","hour": "10","iso8601": "2025-01-08T02:42:41Z","iso8601_basic": "20250108T104241255861","iso8601_basic_short": "20250108T104241","iso8601_micro": "2025-01-08T02:42:41.255861Z","minute": "42","month": "01","second": "41","time": "10:42:41","tz": "CST","tz_offset": "+0800","weekday": "Wednesday","weekday_number": "3","weeknumber": "01","year": "2025"},"default_ipv4": {"address": "172.19.91.7","alias": "eth0","broadcast": "172.19.95.255","gateway": "172.19.95.253","interface": "eth0","macaddress": "00:16:3e:34:19:c2","mtu": 1500,"netmask": "255.255.240.0","network": "172.19.80.0","type": "ether"},"default_ipv6": {},"device_links": {"ids": {"vda": ["virtio-2zea4qo6616yh2wqh6ia"],"vda1": ["virtio-2zea4qo6616yh2wqh6ia-part1"]},"labels": {},"masters": {},"uuids": {"vda1": ["c8b5b2da-5565-4dc1-b002-2a8b07573e22"]}},"devices": {"vda": {"holders": [],"host": "SCSI storage controller: Red Hat, Inc. Virtio block device","links": {"ids": ["virtio-2zea4qo6616yh2wqh6ia"],"labels": [],"masters": [],"uuids": []},"model": null,"partitions": {"vda1": {"holders": [],"links": {"ids": ["virtio-2zea4qo6616yh2wqh6ia-part1"],"labels": [],"masters": [],"uuids": ["c8b5b2da-5565-4dc1-b002-2a8b07573e22"]},"sectors": "83883999","sectorsize": 512,"size": "40.00 GB","start": "2048","uuid": "c8b5b2da-5565-4dc1-b002-2a8b07573e22"}},"removable": "0","rotational": "1","sas_address": null,"sas_device_handle": null,"scheduler_mode": "mq-deadline","sectors": "83886080","sectorsize": "512","size": "40.00 GB","support_discard": "0","vendor": "0x1af4","virtual": 1}},"discovered_interpreter_python": "/usr/bin/python","distribution": "CentOS","distribution_file_parsed": true,"distribution_file_path": "/etc/redhat-release","distribution_file_variety": "RedHat","distribution_major_version": "7","distribution_release": "Core","distribution_version": "7.9","dns": {"nameservers": ["100.100.2.136","100.100.2.138"],"options": {"attempts": "3","rotate": true,"single-request-reopen": true,"timeout": "2"}},"domain": "","effective_group_id": 0,"effective_user_id": 0,"env": {"HOME": "/root","LANG": "en_US.UTF-8","LESSOPEN": "||/usr/bin/lesspipe.sh %s","LOGNAME": "root","LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:","MAIL": "/var/mail/root","PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin","PWD": "/root","SHELL": "/bin/bash","SHLVL": "2","SSH_CLIENT": "175.168.185.6 55563 22","SSH_CONNECTION": "175.168.185.6 55563 172.19.91.7 22","SSH_TTY": "/dev/pts/2","TERM": "xterm","USER": "root","XDG_RUNTIME_DIR": "/run/user/0","XDG_SESSION_ID": "7482","_": "/usr/bin/python"},"eth0": {"active": true,"device": "eth0","features": {"busy_poll": "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": "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_gro_hw": "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","tx_checksum_ipv4": "off [fixed]","tx_checksum_ipv6": "off [fixed]","tx_checksum_sctp": "off [fixed]","tx_checksumming": "on","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_ipip_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_sit_segmentation": "off [fixed]","tx_tcp6_segmentation": "on","tx_tcp_ecn_segmentation": "on","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": "on","vlan_challenged": "off [fixed]"},"hw_timestamp_filters": [],"ipv4": {"address": "172.19.91.7","broadcast": "172.19.95.255","netmask": "255.255.240.0","network": "172.19.80.0"},"ipv6": [{"address": "fe80::216:3eff:fe34:19c2","prefix": "64","scope": "link"}],"macaddress": "00:16:3e:34:19:c2","module": "virtio_net","mtu": 1500,"pciid": "virtio2","promisc": false,"timestamping": ["rx_software","software"],"type": "ether"},"fibre_channel_wwn": [],"fips": false,"form_factor": "Other","fqdn": "ali01","gather_subset": ["all"],"hostname": "ali01","hostnqn": "","interfaces": ["lo","eth0"],"is_chroot": false,"iscsi_iqn": "","kernel": "3.10.0-1160.119.1.el7.x86_64","kernel_version": "#1 SMP Tue Jun 4 14:43:51 UTC 2024","lo": {"active": true,"device": "lo","features": {"busy_poll": "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_gro_hw": "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_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_ipip_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_sit_segmentation": "off [fixed]","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": "on","vlan_challenged": "on [fixed]"},"hw_timestamp_filters": [],"ipv4": {"address": "127.0.0.1","broadcast": "","netmask": "255.0.0.0","network": "127.0.0.0"},"ipv6": [{"address": "::1","prefix": "128","scope": "host"}],"mtu": 65536,"promisc": false,"timestamping": ["rx_software","software"],"type": "loopback"},"lsb": {"codename": "Core","description": "CentOS Linux release 7.9.2009 (Core)","id": "CentOS","major_release": "7","release": "7.9.2009"},"machine": "x86_64","machine_id": "88b247814be64fbf8fa045566b89ce3e","memfree_mb": 259,"memory_mb": {"nocache": {"free": 1512,"used": 244},"real": {"free": 259,"total": 1756,"used": 1497},"swap": {"cached": 0,"free": 0,"total": 0,"used": 0}},"memtotal_mb": 1756,"module_setup": true,"mounts": [{"block_available": 8998392,"block_size": 4096,"block_total": 10288203,"block_used": 1289811,"device": "/dev/vda1","fstype": "ext4","inode_available": 2556564,"inode_total": 2621440,"inode_used": 64876,"mount": "/","options": "rw,relatime,data=ordered","size_available": 36857413632,"size_total": 42140479488,"uuid": "c8b5b2da-5565-4dc1-b002-2a8b07573e22"}],"nodename": "ali01","os_family": "RedHat","pkg_mgr": "yum","proc_cmdline": {"BOOT_IMAGE": "/boot/vmlinuz-3.10.0-1160.119.1.el7.x86_64","console": ["tty0","ttyS0,115200n8"],"crashkernel": "auto","net.ifnames": "0","noibrs": true,"nvme_core.admin_timeout": "4294967295","nvme_core.io_timeout": "4294967295","quiet": true,"rhgb": true,"ro": true,"root": "UUID=c8b5b2da-5565-4dc1-b002-2a8b07573e22","spectre_v2": "retpoline"},"processor": ["0","GenuineIntel","Intel(R) Xeon(R) Platinum","1","GenuineIntel","Intel(R) Xeon(R) Platinum"],"processor_cores": 1,"processor_count": 1,"processor_threads_per_core": 2,"processor_vcpus": 2,"product_name": "Alibaba Cloud ECS","product_serial": "33a7cfe4-534e-418a-adbe-783fb05884e8","product_uuid": "33A7CFE4-534E-418A-ADBE-783FB05884E8","product_version": "pc-i440fx-2.1","python": {"executable": "/usr/bin/python","has_sslcontext": true,"type": "CPython","version": {"major": 2,"micro": 5,"minor": 7,"releaselevel": "final","serial": 0},"version_info": [2,7,5,"final",0]},"python_version": "2.7.5","real_group_id": 0,"real_user_id": 0,"selinux": {"status": "disabled"},"selinux_python_present": true,"service_mgr": "systemd","ssh_host_key_dsa_public": "AAAAB3NzaC1kc3MAAACBAPoheUF1Sp83cZqdmAbfPqAEkBCLnvAB0b06r8wJE7y9nck2s4BLhChHPK+DYPlpmJOFJzhfA3TDiQqGBw6f3tmtWwtaej65Cnb1jg03EldfzXUZjOWaSBAAv20uWjjHLLB9epezwgpYfXI6lH8J5kcHBQAJr6ReQjVnid4H4T4pAAAAFQDBuMSFQWXhqlqLhdRzdd1WbMbrUQAAAIEA0BdoMMTrcc9QdqI0N2RevOrsiSUCaAcs2BwXGIvN1bCA/D/Juvy7L8YKN7TqD2wHxOEe6bd7YtQlg4mm9XxKnaGpO9/DRRDfjv/ZePrxU2bONHlYTG3yIiuhrlbTkp8Apl6fJpEPeGP/tqOv0T9Yx8BPhRgEuCkmmQ+S7An2hFAAAACBAN0QTG1gltjcqWjVW8OK+u1ih9YkLiciD873rG7LVfpN3X7DgiuxFUmcFBqBbKOObMU1vsqbkfHmGDseWeTvOZlQfjmffU56bRWEHMt1JAvwwkwGFKwGjYzBCy8vsqlzGik559yIQxPF6xijqXDrtH4zSgtvgZE+QRhmZl3tPp7E","ssh_host_key_ecdsa_public": "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBE9BHIH3QSoFRbL7br23p3N7rz5FRq19rKEqqucK21bD8bQn4a7O5slXleeGjZQtHMUaTNF4MqyGzFCrcdxw9mQ=","ssh_host_key_ed25519_public": "AAAAC3NzaC1lZDI1NTE5AAAAIHnPv/S9xAofLvaR7cs1hpSXVg8rP36LED54L5m96kH5","ssh_host_key_rsa_public": "AAAAB3NzaC1yc2EAAAADAQABAAABAQC+pOYVVQ5JR7F4i2DM7Lu3CkQDuyJ4OMDA40V8vAFdMKQonrCb/TTUdkBXjwhSet8ucpPIj3UcRrYn0znPFhyCVfPZTCRDREy8pbF+mV9Tby4fTjvk2RDXHf2OihmUIeCKjZmYsNe2zV1fBWp/7Sb+9qP2U5znM3DfmGbrkUfordQEPiyfunQPIUkLGJuJhuWJl6KygE1ZOWPYaZtlR4jK4rvCKmayVUsWXHePVSGXuC5+Fn9D8vXgALb5GENNok45xjkEDyHfmyIm6MCf13r4+hnhPNEJJVfhbv//63R6R/l4al+G7AduZBP91+f1b41p2pVQ5cfqdX1Fow+ZO5Cp","swapfree_mb": 0,"swaptotal_mb": 0,"system": "Linux","system_capabilities": ["cap_chown","cap_dac_override","cap_dac_read_search","cap_fowner","cap_fsetid","cap_kill","cap_setgid","cap_setuid","cap_setpcap","cap_linux_immutable","cap_net_bind_service","cap_net_broadcast","cap_net_admin","cap_net_raw","cap_ipc_lock","cap_ipc_owner","cap_sys_module","cap_sys_rawio","cap_sys_chroot","cap_sys_ptrace","cap_sys_pacct","cap_sys_admin","cap_sys_boot","cap_sys_nice","cap_sys_resource","cap_sys_time","cap_sys_tty_config","cap_mknod","cap_lease","cap_audit_write","cap_audit_control","cap_setfcap","cap_mac_override","cap_mac_admin","cap_syslog","35","36+ep"],"system_capabilities_enforced": "True","system_vendor": "Alibaba Cloud","uptime_seconds": 3786285,"user_dir": "/root","user_gecos": "root","user_gid": 0,"user_id": "root","user_shell": "/bin/bash","user_uid": 0,"userspace_architecture": "x86_64","userspace_bits": "64","virtualization_role": "guest","virtualization_type": "kvm"}
}PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
实际上,我们大概率只会选取经常使用的变量,如下表
事实 | 方式1 | 方式2 | 方式3 |
---|---|---|---|
短主机名 | ansible_facts.hostname | ansible_facts[‘hostname’] | ansible_hostname |
完全限定域名 | ansible_facts.fqdn | ansible_facts[‘fqdn’] | ansible_fqdn |
IPv4地址 | ansible_facts.default_ipv4.address | ansible_facts[‘default_ipv4’][‘address’] | ansible_default_ipv4 |
所有网络接口的名称列表 | ansible_facts.interfaces | ansible_facts['interfaces '] | ansible_interfaces |
DNS服务器列表 | ansible_facts.dns | ansible_facts[‘dns’] | ansible_dns |
当前运行的内核版本 | ansible_facts.kernel | ansible_facts[‘kernel’] | ansible_kernel |
三种格式都可以使用,看自己喜好
[root@localhost ansible]# cat 02.facts.yml
---
- hosts: dbtasks:- name: print ipv4 1debug:msg: "{{ ansible_facts.default_ipv4.address }}"- name: print ipv4 2debug:msg: "{{ ansible_facts['default_ipv4']['address'] }}"- name: print ipv4 3debug:msg: "{{ ansible_default_ipv4.address }}"
[root@localhost ansible]# ansible-playbook -i hosts 02.facts.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [print ipv4 1] ****************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": "172.19.91.7"
}TASK [print ipv4 2] ****************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": "172.19.91.7"
}TASK [print ipv4 3] ****************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": "172.19.91.7"
}PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3. register变量
在Ansible中,可以通过register
关键字将任务的输出结果注册为变量,以便在后续任务中使用。
- 注册变量的基本用法
在Ansible playbook中,可以使用register
关键字来捕获任务的输出并将其保存为一个变量。例如:
[root@localhost ansible]# cat 03.register.yml
---
- hosts: dbtasks:- name: define a var1shell: "whoami"register: whoami- debug: "msg={{ whoami }}"- debug: "msg={{ whoami.stdout }}"
[root@localhost ansible]# ansible-playbook -i hosts 03.register.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [define a var1] ***************************************************************************************************************************************************
changed: [182.92.85.212]TASK [debug] ***********************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": {"changed": true,"cmd": "whoami","delta": "0:00:00.046106","end": "2025-01-09 10:37:55.151360","failed": false,"rc": 0,"start": "2025-01-09 10:37:55.105254","stderr": "","stderr_lines": [],"stdout": "root","stdout_lines": ["root"]}
}TASK [debug] ***********************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": "root"
}PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4. include功能
Ansible的include
功能主要用于在Ansible playbook中提取和重用公共的逻辑代码段,使结构更加清晰,方便阅读和维护。通过使用include
,可以将重复的任务、变量或handlers等代码片段提取到一个单独的文件中,然后在主playbook中通过include
指令引入这些代码片段。
[root@localhost ansible]# cat 04.useradd.yml
---
- name: add useruser:name: "{{ username }}"state: presentcreate_home: no
[root@localhost ansible]# cat 04.include.yml
---
- hosts: dbvars:username: lisitasks:- include: 04.useradd.yml- shell: "tail /etc/passwd"register: content- debug: "msg={{content}}"
注意:提取的代码片段yml只配任务内容,不需要配置hosts
[root@localhost ansible]# ansible-playbook -i hosts 04.include.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [add user] ********************************************************************************************************************************************************
ok: [182.92.85.212]TASK [shell] ***********************************************************************************************************************************************************
changed: [182.92.85.212]TASK [debug] ***********************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": {"changed": true,"cmd": "tail /etc/passwd","delta": "0:00:00.041112","end": "2025-01-09 10:58:22.351314","failed": false,"rc": 0,"start": "2025-01-09 10:58:22.310202","stderr": "","stderr_lines": [],"stdout": "postfix:x:89:89::/var/spool/postfix:/sbin/nologin\nchrony:x:998:996::/var/lib/chrony:/sbin/nologin\nnscd:x:28:28:NSCD Daemon:/:/sbin/nologin\ntcpdump:x:72:72::/:/sbin/nologin\nrpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin\nrpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin\nnfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin\necs-assist-user:x:1000:1000::/home/ecs-assist-user:/sbin/nologin\nnginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin\nlisi:x:1001:1001::/home/lisi:/bin/bash","stdout_lines": ["postfix:x:89:89::/var/spool/postfix:/sbin/nologin","chrony:x:998:996::/var/lib/chrony:/sbin/nologin","nscd:x:28:28:NSCD Daemon:/:/sbin/nologin","tcpdump:x:72:72::/:/sbin/nologin","rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin","rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin","nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin","ecs-assist-user:x:1000:1000::/home/ecs-assist-user:/sbin/nologin","nginx:x:997:995:Nginx web server:/var/lib/nginx:/sbin/nologin","lisi:x:1001:1001::/home/lisi:/bin/bash"]}
}PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
5. handlers
Handlers是Ansible Playbooks中的一种特殊任务类型。它们类似于事件处理程序,用于在特定条件下触发和执行任务。Handlers通常与任务关联,当任务的状态发生变化时,Handlers会被触发执行。Handlers可以用于执行各种操作,如重启服务、重新加载配置文件等。
[root@localhost ansible]# cat 05.handlers.yml
---
- hosts: dbtasks:- copy:src: ./exportsdest: /etc/exportsnotify: restart nfshandlers:- name: restart nfssystemd:name: nfsstate: restarted
[root@localhost ansible]# ansible-playbook -i hosts 05.handlers.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [copy] ************************************************************************************************************************************************************
changed: [182.92.85.212]RUNNING HANDLER [restart nfs] ******************************************************************************************************************************************
changed: [182.92.85.212]PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
当我们未对文件进行修改,再次执行,handlers不会被触发
[root@localhost ansible]# ansible-playbook -i hosts 05.handlers.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [copy] ************************************************************************************************************************************************************
ok: [182.92.85.212]PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6. when 条件
Ansible中的when
语句用于条件判断,根据特定的条件来决定是否执行某个任务。当条件为真时,任务将会执行;当条件为假时,任务将被跳过。when
语句的使用非常灵活,可以基于变量、事实、先前任务的输出或其他表达式的结果来决定是否执行某个任务
[root@localhost ansible]# cat 06.when.yml
---
- hosts: dbtasks:- name: CentOS Install httpdyum: name=httpd state=presentwhen: (ansible_distribution=="CentOS")- name: Ubuntu Install httpdyum: name=httpd state=presentwhen: (ansible_distribution=="Ubuntu")- name: start httpdsystemd:name: httpdstate: startedenabled: no- shell: "systemctl status httpd"register: state_httpd- debug: "msg={{state_httpd}}"
[root@localhost ansible]# ansible-playbook -i hosts 06.when.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.85.212]TASK [CentOS Install httpd] ********************************************************************************************************************************************
ok: [182.92.85.212]TASK [Ubuntu Install httpd] ********************************************************************************************************************************************
skipping: [182.92.85.212]TASK [start httpd] *****************************************************************************************************************************************************
ok: [182.92.85.212]TASK [shell] ***********************************************************************************************************************************************************
changed: [182.92.85.212]TASK [debug] ***********************************************************************************************************************************************************
ok: [182.92.85.212] => {"msg": {"changed": true,"cmd": "systemctl status httpd","delta": "0:00:00.044066","end": "2025-01-09 12:34:02.429361","failed": false,"rc": 0,"start": "2025-01-09 12:34:02.385295","stderr": "","stderr_lines": [],"stdout": "● httpd.service - The Apache HTTP Server\n Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)\n Active: active (running) since Thu 2025-01-09 12:32:34 CST; 1min 27s ago\n Docs: man:httpd(8)\n man:apachectl(8)\n Main PID: 8474 (httpd)\n Status: \"Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec\"\n CGroup: /system.slice/httpd.service\n ├─8474 /usr/sbin/httpd -DFOREGROUND\n ├─8475 /usr/sbin/httpd -DFOREGROUND\n ├─8476 /usr/sbin/httpd -DFOREGROUND\n ├─8477 /usr/sbin/httpd -DFOREGROUND\n ├─8478 /usr/sbin/httpd -DFOREGROUND\n └─8479 /usr/sbin/httpd -DFOREGROUND\n\nJan 09 12:32:34 ali01 systemd[1]: Starting The Apache HTTP Server...\nJan 09 12:32:34 ali01 httpd[8474]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::216:3eff:fe34:19c2. Set the 'ServerName' directive globally to suppress this message\nJan 09 12:32:34 ali01 systemd[1]: Started The Apache HTTP Server.","stdout_lines": ["● httpd.service - The Apache HTTP Server"," Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)"," Active: active (running) since Thu 2025-01-09 12:32:34 CST; 1min 27s ago"," Docs: man:httpd(8)"," man:apachectl(8)"," Main PID: 8474 (httpd)"," Status: \"Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec\""," CGroup: /system.slice/httpd.service"," ├─8474 /usr/sbin/httpd -DFOREGROUND"," ├─8475 /usr/sbin/httpd -DFOREGROUND"," ├─8476 /usr/sbin/httpd -DFOREGROUND"," ├─8477 /usr/sbin/httpd -DFOREGROUND"," ├─8478 /usr/sbin/httpd -DFOREGROUND"," └─8479 /usr/sbin/httpd -DFOREGROUND","","Jan 09 12:32:34 ali01 systemd[1]: Starting The Apache HTTP Server...","Jan 09 12:32:34 ali01 httpd[8474]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using fe80::216:3eff:fe34:19c2. Set the 'ServerName' directive globally to suppress this message","Jan 09 12:32:34 ali01 systemd[1]: Started The Apache HTTP Server."]}
}PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=5 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
语法和逻辑运算符
when
语句的语法与Python的语法非常相似,支持多种条件表达式和逻辑运算符:
- 比较运算符:
==、!=、>、<、>=、<=
- 逻辑运算符:
and、or、not
- 组合条件:可以使用括号
()
来组合多个条件,改变运算的优先级
7. with_items 循环
在Ansible Playbook中,with_items
用于遍历列表或字典,并对每个元素执行任务。其基本语法如下:
tasks:- command: some_command "{{ item }}"with_items:- item1- item2- item3
使用场景包括:创建多个用户,安装多个软件包,启动多个服务,拷贝多个文件等等
[root@localhost ansible]# cat 07.with_items.yml
---
- hosts: dbgather_facts: notasks:- name: useradduser:name: "{{item}}"state: presentcreate_home: nowith_items:- yurq1- yurq2- yurq3
[root@localhost ansible]# ansible-playbook -i hosts 07.with_items.ymlPLAY [db] **************************************************************************************************************************************************************TASK [useradd] *********************************************************************************************************************************************************
changed: [182.92.85.212] => (item=yurq1)
changed: [182.92.85.212] => (item=yurq2)
changed: [182.92.85.212] => (item=yurq3)PLAY RECAP *************************************************************************************************************************************************************
182.92.85.212 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0[root@localhost ansible]# ansible -i hosts db -m shell -a "tail -3 /etc/passwd"
182.92.85.212 | CHANGED | rc=0 >>
yurq1:x:1002:1002::/home/yurq1:/bin/bash
yurq2:x:1003:1003::/home/yurq2:/bin/bash
yurq3:x:1004:1004::/home/yurq3:/bin/bash
8. Jinja2模板
Jinja2 是 Python 的全功能模板引擎
Ansible 需要使用 Jinja2 模板来修改被管理主机的配置文件。
ansible 使用 jinja2 模板需要借助 template 模块实现,那 template 模块是用来做什么的?
template 模块和 copy 模块完全一样,都是拷贝文件至远程主机,区别在于template 模块会解析要拷贝的文件中变量的值,而 copy 则是原封不动的将文件拷贝至被控端。
[root@localhost ansible]# cat exports.j2
#{{ansible_hostname}}
/data/ *(rw,sync,all_squash)
[root@localhost ansible]# cat 08.jinja2.yml
---
- hosts: dbtasks:- template:src: ./exports.j2dest: /etc/exportsnotify: restart nfs- shell: "cat /etc/exports"register: content- debug: "msg={{content}}"handlers:- name: restart nfssystemd:name: nfsstate: restarted
[root@localhost ansible]# ansible-playbook -i hosts 08.jinja2.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.84.211]TASK [template] ********************************************************************************************************************************************************
changed: [182.92.84.211]TASK [shell] ***********************************************************************************************************************************************************
changed: [182.92.84.211]TASK [debug] ***********************************************************************************************************************************************************
ok: [182.92.84.211] => {"msg": {"changed": true,"cmd": "cat /etc/exports","delta": "0:00:00.039831","end": "2025-01-09 13:03:56.418589","failed": false,"rc": 0,"start": "2025-01-09 13:03:56.378758","stderr": "","stderr_lines": [],"stdout": "#ali01\n/data/ *(rw,sync,all_squash) ","stdout_lines": ["#ali01","/data/ *(rw,sync,all_squash) "]}
}RUNNING HANDLER [restart nfs] ******************************************************************************************************************************************
changed: [182.92.84.211]PLAY RECAP *************************************************************************************************************************************************************
182.92.84.211 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
9. group_vars
ansible中变量有很多种,包括:
- 资产变量,即我们配置在hosts文件中的变量
- facts变量,即ansible为我们收集的主机信息变量
- 注册变量,即register注册的变量,在脚本内为后续使用
- 剧本变量,如vars定义在文件前部,供后续使用
- 全局变量,一般是ansible命令行使用的
group_vars
下的文件名应该与 Ansible inventory 中定义的组名匹配,文件名无需添加任何扩展名,内容为该组下所有主机共有的变量。一般用于定义剧本变量。
例如,假设你有一个名为 webservers
的组,group_vars/webservers
文件内容可能是:
http_port: 80
max_connections: 1024
不过,一般我们都只定义一个all的文件,供所有组使用
[root@localhost ansible]# tree
.
├── 01.nfs_install.yml
├── 02.facts.yml
├── 03.register.yml
├── 04.include.yml
├── 04.useradd.yml
├── 05.handlers.yml
├── 06.when.yml
├── 07.with_items.yml
├── 08.jinja2.yml
├── 09.group_vars.yml
├── exports
├── exports.j2
├── group_vars
│ └── all
└── hosts1 directory, 14 files
[root@localhost ansible]# cat group_vars/all
user4: yurq4
[root@localhost ansible]# ansible-playbook -i hosts 09.group_vars.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.84.211]TASK [useradd 2] *******************************************************************************************************************************************************
changed: [182.92.84.211]PLAY RECAP *************************************************************************************************************************************************************
182.92.84.211 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0[root@localhost ansible]# ansible -i hosts all -m shell -a "tail -1 /etc/passwd"
182.92.84.211 | CHANGED | rc=0 >>
yurq4:x:1005:1005::/home/yurq4:/bin/bash
看到了吗?我们未做任何导入工作,就可以直接调用user4
,非常方便
10. roles ⭐️⭐️⭐️
Ansible roles是Ansible的一个组织结构,它允许你将配置任务封装为可重用的单元,这样你可以在多个playbook中使用它们。
一个Ansible role通常包含以下目录结构:
defaults/
:设定变量的默认值。files/
:存放由copy或script模块等调用的文件。handlers/
:包含处理器的定义,处理器可以在特定的条件下触发。meta/
:定义role的依赖关系。tasks/
:包含主要的任务集。templates/
:包含Jinja2模板文件,这些模板文件可以根据变量渲染内容。vars/
:定义变量,这些变量会覆盖defaults中的同名变量。
文件:
-
README.md
:对role的简要说明。 -
meta/main.yml
:定义role的特定行为。 -
tasks/main.yml
:列出role要执行的任务。 -
handlers/main.yml
:列出可由任务触发的处理器。 -
vars/main.yml
:定义role使用的变量。
上面的目录并不是每个项目都需要的,一般常用的有:
-
files/
-
handlers/
-
tasks/
-
templates/
-
vars/
我们把08.jinja2.yml
拆分为roles格式,帮助大家理解
[root@localhost ansible]# cat 08.jinja2.yml
---
- hosts: dbtasks:- template:src: ./exports.j2dest: /etc/exportsnotify: restart nfs- shell: "cat /etc/exports"register: content- debug: "msg={{content}}"handlers:- name: restart nfssystemd:name: nfsstate: restarted
如下:
[root@localhost roles]# tree
.
├── 10.roles.yml
├── db
│ ├── handlers
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ └── templates
│ └── exports.j2
└── hosts4 directories, 5 files
tasks/
[root@localhost roles]# cat db/tasks/main.yml
- template:src: ./exports.j2dest: /etc/exportsnotify: restart nfs
- shell: "cat /etc/exports"register: content
- debug: "msg={{content}}"
handlers/
[root@localhost roles]# cat db/handlers/main.yml
- name: restart nfssystemd:name: nfsstate: restarted
templates/
[root@localhost roles]# cat db/templates/exports.j2
#{{ansible_hostname}}
/data/ *(rw,sync,all_squash)
10.roles.yml
[root@localhost roles]# cat 10.roles.yml
---
- hosts: dbroles:- db
执行
[root@localhost roles]# ansible-playbook -i hosts 10.roles.ymlPLAY [db] **************************************************************************************************************************************************************TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [182.92.84.211]TASK [db : template] ***************************************************************************************************************************************************
ok: [182.92.84.211]TASK [db : shell] ******************************************************************************************************************************************************
changed: [182.92.84.211]TASK [db : debug] ******************************************************************************************************************************************************
ok: [182.92.84.211] => {"msg": {"changed": true,"cmd": "cat /etc/exports","delta": "0:00:00.039530","end": "2025-01-09 13:35:27.995178","failed": false,"rc": 0,"start": "2025-01-09 13:35:27.955648","stderr": "","stderr_lines": [],"stdout": "#ali01\n/data/ *(rw,sync,all_squash) ","stdout_lines": ["#ali01","/data/ *(rw,sync,all_squash) "]}
}PLAY RECAP *************************************************************************************************************************************************************
182.92.84.211 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
其实执行起来和08的剧本本质是一样的,不过改变了目录结构,方便管理