Ansible基础
# Ansible基础
Ansible是一个非常强大的自动化运维工具,它基于SSH,Ansible 不需要在目标主机上安装任何客户端代理,它直接利用 SSH 来远程执行命令和配置管理。
# 安装
apt update -y
apt install ansible -y
apt install sshpass
2
3
验证是否安装成功
ansible --version
ansible [core 2.14.18]
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.11.2 (main, Mar 13 2023, 12:18:29) [GCC 12.2.0] (/usr/bin/python3)
jinja version = 3.1.2
libyaml = True
2
3
4
5
6
7
8
9
默认配置文件
/etc/ansible/ansible.cfg
编辑/etc/ansible/hosts, 如果没有则创建。
vim /etc/ansible/hosts
如果配置免密后还要输入密码认证,可以查看/etc/ssh/sshd_config文件以下参数是否设置为:yes
PubkeyAuthentication yes
ansible all -i inventory.ini -m ping # 参数可以指定自定义文件
hosts 文件内容如下———因为ansible基于ssh,所以可以使用密码或密钥,我这里使用密码
先安装
apt install sshpass -y
[nodes]
ip ansible_user=root ansible_ssh_pass=pass ansible_port=2222
[web]
ip ansible_user=root ansible_ssh_pass=pass ansible_port=2222
[db]
ip ansible_user=root ansible_ssh_pass=pass ansible_port=2222
2
3
4
5
6
密钥
ssh-keygen -t rsa #中间一路按enter键即可
ssh-copy-id root@IP
2
[nodes]
ip ansible_user=root
[web]
ip ansible_user=root
[db]
ip ansible_user=root
2
3
4
5
6
all 指所有主机,当然你可以指定部分主机
ansible all -m ping
ansible web,db -m ping
2
成功执行后应有这样的提示
node02 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
node01 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
node03 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 模块
ansible:ad-hoc命令结构如下:
ansible 主机 -m 模块名 -a 操作
ansible-doc -s 模块名 # 可以列出模块的具体用法和参数
ansible-doc -l # 列出所有模块
ansible-playbook --syntax-check site.yml #语法检测
# Command
Command:不会通过 shell 解释器运行命令,只能执行一些简单的指令。默认模块不指定默认command。
ansible nodes -m command -a "uptime"
ip | CHANGED | rc=0 >>
20:51:34 up 26 days, 17:49, 3 users, load average: 0.01, 0.08, 0.06
2
# Shell
Shell:通过 shell 解释器运行命令,可以使用 shell 特性,如管道、重定向、环境变量等。
从以下列子可以明显看出command 不支持管道。
root@master:/etc/ansible# ansible nodes -m shell -a "netstat -tunlp | grep 22"
IP | CHANGED | rc=0 >>
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 16355/sshd: /usr/sb
tcp6 0 0 :::22 :::* LISTEN 16355/sshd: /usr/sb
root@master:/etc/ansible# ansible nodes -m command -a "netstat -tunlp | grep 22"
IP | CHANGED | rc=0 >>
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 16355/sshd: /usr/sb
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 61011/docker-proxy
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 61025/docker-proxy
tcp 0 0 127.0.0.1:1514 0.0.0.0:* LISTEN 60398/docker-proxy
tcp6 0 0 :::22 :::* LISTEN 16355/sshd: /usr/sb
tcp6 0 0 :::80 :::* LISTEN 61018/docker-proxy
tcp6 0 0 :::443 :::* LISTEN 61034/docker-proxy
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# File
File: 用于管理文件和目录的属性,可以创建、删除文件或目录,设置文件或目录的权限、拥有者和组等属性
文件/目录操作常用参数:
- owner: 定义文件/目录的属主
- group: 定义文件/目录的属组
- mode: 定义文件/目录的权限
- path: 必选项,定义文件/目录的路径
- recurse: 递归的设置文件的属性,只对目录有效
- src: 要被链接(软/硬)的源文件的路径,只应用于state=link的情况
- dest: 被链接到的路径,只应用于state=link的情况
- state:
- directory: 如果目录不存在,创建目录
- file: 文件不存在,则不会被创建,存在则返回文件的信息,常用于检查文件是否存在。
- link: 创建软链接
- hard: 创建硬链接
- touch: 如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
- absent: 删除目录、文件或者取消链接文件
创建目录并设置权限
ansible nodes -m file -a "path=/etc/ansible/test state=directory mode=0755"
root@master:/etc/ansible# ls -l
total 4
-rw-r--r-- 1 root root 78 Mar 18 21:29 hosts
drwxr-xr-x 2 root root 39 Mar 18 21:38 playbook
drwxr-xr-x 2 root root 6 Mar 27 21:10 test
2
3
4
5
ansible nodes -m file -a "path=/etc/ansible/test state=touch" # 创建文件
ansible nodes -m file -a "path=/etc/ansible/test state=absent" # 删除文件或目录
2
更多操作可以通过以下命令查看
ansible-doc -s 模块名
# Cron
Cron:用于在远程主机上管理定时任务
注意:使用 Ansible 创建的计划任务,是不能使用本地 crontab -e 去编辑,否则 Ansible 无法再次操作他。
常用参数:
- name: 指定一个 cron job 的名字。一定要指定,便于日后删除。
- minute: 指定分钟,可以设置成 (0-59,,/2 等) 格式。默认是 *,也就是每分钟。
- hour: 指定小时,可以设置成 (0-23,,/2 等) 格式。默认是 *,也就是每小时。
- day: 指定天,可以设置成 (1-31,,/2 等) 格式。默认是 *,也就是每天。
- month: 指定月份,可以设置成 (1-12,,/2 等) 格式。默认是 *,也就是每月。
- weekday: 指定星期,可以设置成 (0-6 for Sunday-Saturday,* 等) 格式。默认是 *,也就是每星期。
- job: 指定要执行的内容,通常可以写个脚本,或者一段内容。
- state: 指定这个 job 的状态,可以是新增 (present) 或者是删除 (absent)。默认为新增 (present)。
创建一个每5分钟执行一次的任务
ansible all -m cron -a "name='job1' job='/usr/local/bin/check_service.sh' minute='*/5' state=present"
删除一个任务
ansible all -m cron -a "name='job1' state=absent"
查看创建的任务
ansible all -m shell -a "crontab -l"
# Script
Script:允许你在远程主机上执行本地脚本
创建一个简单的shell 脚本
vim test_script.sh
#!/bin/bash
echo "Current hostname: $(hostname)"
echo "Current date: $(date)"
echo "Script arguments: $@"
2
3
4
chmod +x test_script.sh
ansible nodes -m script -a "./test_script.sh hello ansible"
IP | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 154.23.243.49 closed.\r\n",
"stderr_lines": [
"Shared connection to 154.23.243.49 closed."
],
"stdout": "Current hostname: master\r\nCurrent date: Sun Mar 30 08:55:14 PM CST 2025\r\nScript arguments: hello ansible\r\n",
"stdout_lines": [
"Current hostname: master",
"Current date: Sun Mar 30 08:55:14 PM CST 2025",
"Script arguments: hello ansible"
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# Copy
常用参数:
- src: 指定拷贝文件的源地址
- dest: 指定拷贝文件的目标地址
- backup: 拷贝文件前,若原始文件发生变化,则对目标文件进行备份
- owner: 指定新拷贝文件的所有者
- group: 指定新拷贝文件的所有组
- mode: 指定新拷贝文件的权限
root@node01:~# ansible web -m copy -a "src=./get_helm.sh dest=/root/"
node02 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": true,
"checksum": "3b4ee4bce486825ac1e35c595b676296d1892677",
"dest": "/root/get_helm.sh",
"gid": 0,
"group": "root",
"md5sum": "6b90dff0367e198cd2e46bd569114557",
"mode": "0644",
"owner": "root",
"size": 11913,
"src": "/root/.ansible/tmp/ansible-tmp-1760083316.1165833-3219920-162983002986822/source",
"state": "file",
"uid": 0
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
root@node02:~# ls -l
total 504856
-rwxr-xr-x 1 root root 5332 Jun 8 20:44 agent.sh
-rw-r--r-- 1 root root 10562552 Apr 1 2025 cri-dockerd_0.3.17.3-0.debian-bookworm_amd64.deb
-rw-r--r-- 1 root root 11913 Oct 10 16:01 get_helm.sh
-rw-r--r-- 1 root root 505623040 Feb 19 2025 hpav1.tar
-rw-r--r-- 1 root root 254 Sep 21 15:17 nginx.conf
-rw-r--r-- 1 root root 754176 Feb 19 2025 pause.tar
2
3
4
5
6
7
8
# Apt/Yum
常用参数: name: 要安装的软件包名,多个软件包以逗号(,)隔开。 state: 对当前指定的软件进行安装或移除操作。 state参数支持的值:
- present: 确认已经安装,但不升级。
- installed: 确认已经安装。
- latest: 确保安装,且升级为最新。
- absent: 确认已移除。
- removed: 确认已移除。
Apt/Yum:系统上管理软件包
安装软件包
ansible all -m apt -a "name=vim,curl state=present"
删除软件包
ansible all -m apt -a "name=curl state=absent"
# Systemd
常用参数:
- daemon_reload: 重新载入 systemd,扫描新的或有变动的单元。
- enabled: 是否开机自启动 (yes/no)。
- name: 必选项,服务名称,例如 httpd, vsftpd。
- state: 对当前服务执行启动、停止、重启、重新加载等操作 (started, stopped, restarted, reloaded)。
服务状态管理:
ansible all -m systemd -a "name=nginx state=started"
启用/禁用服务开机自启:
ansible all -m systemd -a "name=nginx enabled=yes"
ansible all -m systemd -a "name=nginx enabled=no"
2
3
重新加载 systemd 配置:
ansible all -m systemd -a "daemon_reload=yes" # systemctl daemon-reload
# Mount
Mount:用于管理文件系统的挂载点
挂载一个标准的 ext4 文件系统
ansible all -m mount -a "path=/mnt/data src=/dev/sdb1 fstype=ext4 state=mounted"
完全移除挂载(卸载并从 fstab 中删除)
ansible all -m mount -a "path=/mnt/data state=absent"
# Archive/Unarchive
Archive/Unarchive:用于处理文件的压缩和解压缩操作
压缩多个文件/目录
ansible all -m archive -a "path=/path/to/dir1,/path/to/dir2 dest=/path/to/archive.tar.gz"
解压控制主机的文件到被控主机
ansible all -m unarchive -a "src=/local/path/archive.tar.gz dest=/remote/path/"
解压被控主机的文件(需要被控主机需要相同的路径和名字)
ansible all -m unarchive -a "src=/remote/path/archive.tar.gz dest=/remote/path/ remote_src=yes"
# Template
使用了 Jinja2 格式作为文件模版,可以进行文档内变量的替换。
它的每次使用都会被 Ansible 标记为 "changed" 状态。文件以 .j2结尾。
常用参数:
- src: 指定 Ansible 控制端的文件路径。
- dest: 指定 Ansible 被控端的文件路径。
- owner: 指定文件的属主。
- group: 指定文件的属组。
- mode: 指定文件的权限。
- backup: 创建一个包含时间戳信息的备份文件,这样如果您以某种方式错误地破坏了原始文件,就可以将其恢复原状。(yes/no)
vim hello_ansible.j2
hello {{ name }}!!!!!
ansible db -m template -a "src=./hello_ansible.j2 dest=/tmp/hello_ansible.txt" -e "name=ansible"
root@node03:/etc# cat /tmp/hello_ansible.txt
hello ansible!!!!!
2
3
4
5
# playbook
常见属性:
- name属性:每个play的名字。
- hosts属性:每个play涉及的被管理服务器,同ad-hoc中的资产选择器。
- tasks属性:每个play中具体要完成的任务,以列表的形式表达。
- become属性:如果需要提权,则加上become相关属性。
- become_user属性:若提权的话,提权到哪个用户上。
- remote_user属性:指定连接用户。若不指定,则默认使用当前执行ansible Playbook的用户。
hosts: 可以写一个主机组,也可以写IP--------hosts: 192.168.1.12,192.168.1.13
---
- name: Here is a playbook to install node_exporter.
hosts: nodes # 指定要安装的主机组
#become: yes # 相当于sudo
#become_user: zsan # 指定用户运行
vars:
node_exporter_url: "https://github.com/prometheus/node_exporter/releases/download/v1.9.0/node_exporter-1.9.0.linux-amd64.tar.gz"
tasks:
- name: Download node_exporter
get_url:
url: "{{ node_exporter_url }}"
dest: "/opt/node_exporter.tar.gz"
mode: "0644"
2
3
4
5
6
7
8
9
10
11
12
13
14
测试一个playbook 是否正确,并不会真正执行
ansible-playbook -C install_node-exporter.yml
检查剧本
ansible-playbook install_node-exporter.yml --syntax-check
运行一个剧本
ansible-playbook install_node-exporter.yml
# 变量
变量优先级:命令行 > Playbook > Inventory > Role 默认
# 全局变量
全局变量,是我们使用 ansible 或使用 ansible-playbook 时,手动通过 -e 参数传递给 Ansible 的变量。
ansible db -m template -a "src=./hello_ansible.j2 dest=/tmp/hello_ansible.txt" -e "name=ansible"
# 剧本变量
此种变量和 PlayBook 有关,定义在 PlayBook 中。它的定义方式有多种,我们这里介绍两种最常用的定义方式。
通过PLAY属性vars定义
- name: Here is a playbook to install node_exporter.
hosts: nodes # 指定要安装的主机组
#become: yes # 相当于sudo
#become_user: zsan # 指定用户运行
vars:
node_exporter_url: "https://github.com/prometheus/node_exporter/releases/download/v1.9.0/node_exporter-1.9.0.linux-amd64.tar.gz"
tasks:
- name: Download node_exporter
get_url:
url: "{{ node_exporter_url }}"
dest: "/opt/node_exporter.tar.gz"
mode: "0644"
2
3
4
5
6
7
8
9
10
11
12
13
通过PLAY属性vars_files定义
- name: Here is a playbook to install node_exporter.
hosts: nodes # 指定要安装的主机组
#become: yes # 相当于sudo
#become_user: zsan # 指定用户运行
vars:
- vars/url.yaml
tasks:
- name: Download node_exporter
get_url:
url: "{{ node_exporter_url }}"
dest: "/opt/node_exporter.tar.gz"
mode: "0644"
2
3
4
5
6
7
8
9
10
11
12
13
# cat vars/url.yaml
node_exporter_url: "https://github.com/prometheus/node_exporter/releases/download/v1.9.0/node_exporter-1.9.0.linux-amd64.tar.gz"
2
引用变量使用**""**
# 资产变量
root@node01:/opt/ansible# cat /etc/ansible/hosts
[nodes]
node01 ansible_user=root age=18
node02 ansible_user=root
node03 ansible_user=root
[web]
node02 ansible_user=root
[db]
node03 ansible_user=root
2
3
4
5
6
7
8
9
此时age就是node01的变量只有node01能访问
root@node01:/opt/ansible# ansible node01 -m debug -a "msg='{{age}}'"
node01 | SUCCESS => {
"msg": 18
}
2
3
4
此时,node02访问会提示未定义
root@node01:/opt/ansible# ansible node02 -m debug -a "msg='{{age}}'"
node02 | FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'age' is undefined. 'age' is undefined. 'age' is undefined. 'age' is undefined"
}
2
3
4
# 主机组变量
如果主机组变量与主机变量重复,优先使用主机变量
[nodes]
node01 ansible_user=root age=18
node02 ansible_user=root
node03 ansible_user=root
[web]
node02 ansible_user=root
[db]
node03 ansible_user=root
[nodes:vars]
age=20
2
3
4
5
6
7
8
9
10
root@node01:/opt/ansible# ansible nodes -m debug -a "msg='{{age}}'"
node01 | SUCCESS => {
"msg": 18
}
node02 | SUCCESS => {
"msg": 20
}
node03 | SUCCESS => {
"msg": 20
}
2
3
4
5
6
7
8
9
10
# Facts变量
Facts变量不包含在前文中介绍的全局变量、剧本变量及资产变量之内。 Facts变量不需要我们人为去声明变量名及赋值。 它的声明和赋值完全由Ansible中的setup模块帮我们完成。 它收集了有关被管理服务器的操作系统版本、服务器IP地址、主机名,磁盘的使用情况、CPU个数、内存大小等等有关被管理服务器的私有信息。 在每次PlayBook运行的时候都会发现在PlayBook执行前都会有一个Gathering Facts的过程。这个过程就是收集被管理服务器的Facts信息过程。
root@node01:/opt/ansible# ansible db -m setup -a "filter=*mem*"
node03 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 2677,
"ansible_memory_mb": {
"nocache": {
"free": 6765,
"used": 1175
},
"real": {
"free": 2677,
"total": 7940,
"used": 5263
},
"swap": {
"cached": 0,
"free": 0,
"total": 0,
"used": 0
}
},
"ansible_memtotal_mb": 7940,
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
在playblook
加上gather_facts : no关闭facts变量获取
- name: Here is a playbook to install node_exporter.
hosts: nodes # 指定要安装的主机组
gather_facts: no
#become: yes # 相当于sudo
#become_user: zsan # 指定用户运行
vars:
- vars/url.yaml
tasks:
- name: Download node_exporter
get_url:
url: "{{ node_exporter_url }}"
dest: "/opt/node_exporter.tar.gz"
mode: "0644"
2
3
4
5
6
7
8
9
10
11
12
13
14
# 循环-loop
---
- name: create users
hosts: nodes
tasks:
- name: create user
user:
name: "{{ item }}" # item 并不是必须得,可以自定义
state: present
loop:
- "user01"
- "user02"
- "user03"
2
3
4
5
6
7
8
9
10
11
12
自定义循环变量名
---
- name: create users
hosts: nodes
tasks:
- name: create user
user:
name: "{{ user_name }}" # 使用自定义的循环变量名
state: present
loop:
- "user01"
- "user02"
- "user03"
loop_control:
loop_var: user_name # 将默认的 item 改为 user_name
2
3
4
5
6
7
8
9
10
11
12
13
14
另一种list定义--------建议, 方便变量得重复利用
---
- name: create users
hosts: nodes
vars:
users_list:
- "user01"
- "user02"
- "user03"
tasks:
- name: create user
user:
name: "{{ item }}" # item 并不是必须得,可以自定义
state: present
loop: "{{ users_list }}"
2
3
4
5
6
7
8
9
10
11
12
13
14
# register
在 Ansible 中,register 用于:保存任务执行的结果到变量中,以便在后续任务中使用。
可以理解为:把任务的输出结果保存下来,供后续任务条件判断或输出使用。
---
- hosts: nodes
tasks:
- name: echo ip address
shell: "echo {{ ansible_default_ipv4.address }} >> /tmp/ip.log" #当Ansible连接目标主机执行任务时,默认会先执行一个"Gathering Facts"阶段,自动收集主机的各种系统信息
- name: cat /tmp/ip.log
shell: "cat /tmp/ip.log"
register: ip_log_result # 将上条命令执行的结果注册到这个变量中
- name: debug ip_log_result
debug:
msg: "{{ ip_log_result.stdout_lines }}"
2
3
4
5
6
7
8
9
10
11
root@node01:/opt/ansible# ansible-playbook register.yaml
PLAY [nodes] ************************************************************************************************************************************************
TASK [Gathering Facts] **************************************************************************************************************************************ok: [node02]
ok: [node01]
ok: [node03]
TASK [echo ip address] **************************************************************************************************************************************changed: [node01]
changed: [node02]
changed: [node03]
TASK [cat /tmp/ip.log] **************************************************************************************************************************************changed: [node02]
changed: [node01]
changed: [node03]
TASK [debug ip_log_result] **********************************************************************************************************************************ok: [node01] => {
"msg": [
"192.168.187.111"
]
}
ok: [node02] => {
"msg": [
"192.168.187.112"
]
}
ok: [node03] => {
"msg": [
"192.168.187.113"
]
}
PLAY RECAP **************************************************************************************************************************************************node01 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node02 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node03 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# when
---
- hosts: nodes
tasks:
- name: copy file
copy:
src: /opt/test.log
dest: /etc/
register: file_status
- name: Display success message if file was changed
debug:
msg: "File was successfully copied"
when: file_status.changed
2
3
4
5
6
7
8
9
10
11
12
13
# handlers
handlers和notify是实现任务触发机制的重要组件,通常用于管理服务的重启、配置文件重载等需要条件触发的操作。
---
- hosts: nodes
vars:
app_name: myapp
tasks:
- name: Copy nginx config
template: # 动态渲染Jinja2模板后分发文件,copy是直接复制静态文件
src: nginx.conf.j2 # 只需在主控机器上即可
dest: /etc/nginx/nginx.conf
notify: # 可以同时触发多个handler,调用相关名字即可
- Restart nginx
- Reload logs
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
- name: Reload logs
command: /usr/sbin/nginx -s reload
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
nginx.conf.j2
server {
listen 80;
server_name {{ ansible_hostname }}; # ansible 内置模块获取setup,可以用这个命令查看都有哪些内容: ansible nodes -m setup
root /var/www/{{ app_name }};
}
2
3
4
5
# Tags
---
- hosts: nodes
vars:
network_tools: ['rsync', 'iperf3'] # 使用变量管理软件列表
tasks:
- name: Install network tools
apt:
name: "{{ item }}"
state: present
update_cache: yes # 等同于 apt update 确定安装的软件为最新的
loop: "{{ network_tools }}"
tags: # 可以指定多个或多个tag,运行是满足一个即可运行
- install
- network_setup
- step_01
- name: Remove iperf3 (cleanup)
apt:
name: iperf3
state: absent
tags:
- uninstall
- cleanup
- step_02
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ansible-playbook playbook.yml --tags "install" # 执行install tag
ansible-playbook playbook.yml --tags "step_01" # 执行step_01 tag
ansible-playbook playbook.yml --skip-tags "install" # 跳过带有install tags 执行其它tags
2
3
# Roles
Role(角色) 是 Ansible 中的一种分层结构化组织 Playbook 的方式,它能让配置更清晰、可重用、易维护。
# 初始化一个roles
ansible-galaxy init network_tools
2
├── defaults
│ └── main.yml # 用于定义默认变量,这些变量的优先级低于其他变量
├── files # 存储静态文件,这些文件可以通过 copy 或 template 模块复制到目标主机
├── handlers
│ └── main.yml # 定义处理程序(handlers),这些处理程序可以由任务触发
├── meta
│ └── main.yml # 定义角色的元数据,包括依赖关系等
├── README.md # 角色的说明文档,描述角色的用途和使用方法
├── tasks
│ └── main.yml # 定义角色的主要任务列表,这是角色的核心部分
├── templates # 存储 Jinja2 模板文件,这些模板文件可以动态生成配置文件
├── tests
│ ├── inventory # 测试库存文件,用于定义测试环境中的主机
│ └── test.yml # 测试 playbook,用于测试角色的功能
└── vars
└── main.yml # 定义角色的变量,这些变量的优先级高于 defaults 变量
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
把Tags案例改为roles
network_tools/tasks/main.yml
---
- name: Install network tools
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop: "{{ network_tools }}"
tags:
- install
- network_setup
- step_01
- name: Remove iperf3 (cleanup)
apt:
name: iperf3
state: absent
tags:
- uninstall
- cleanup
- step_02
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
network_tools/vars/main.yml
---
network_tools:
- rsync
- iperf3
2
3
4
site.yml
---
- hosts: nodes
roles:
- network_tools
2
3
4
执行
ansible-playbook site.yml
调试
# 根据v数量,输出详细信息
ansible-playbook register.yaml -v
ansible-playbook register.yaml -vv
ansible-playbook register.yaml -vvv
2
3
4
# 配置文件--ansible.cfg
ANSIBLE_CONFIG(如果设置了环境变量)ansible.cfg(在当前目录中)~/.ansible.cfg(在主目录中)/etc/ansible/ansible.cfg
生成示例ansible.cfg文件 您可以生成一个完全注释掉的示例ansible.cfg文件,例如:
ansible-config init --disabled > ansible.cfg
您还可以拥有一个包含现有插件的更完整的文件:
ansible-config init --disabled -t all > ansible.cfg
# 增加forks值
forks决定了Ansible 并发执行任务的数量,即Ansible 在执行 Playbook 时,最多同时并发连接 5 台主机。
forks值默认是5个

[nodes]
node01
node02
node03
node04
node05
node06
node07
node08
node09
node10
2
3
4
5
6
7
8
9
10
11
如果,forks=5,Ansible 先启动 5 个并行进程,分别连接 node01~node05,等这些主机任务完成后,再执行 node06~node10;
值得注意的是同一批必须5个都执行完,才会执行下一批。
# 修改执行策略
上面已经说过,ansible默认执行策略是同一批必须执行完,才会执行下一批。
在配置文件中默认为 strategy=linear即顺序执行模式一步一步执行,每个 task 同步运行

修改为strategy=free即异步执行模式每台主机独立执行,不必等其他主机
但是要注意,有些场景下要小心使用free策略,特别是节点依赖时。比如,某些节点运行服务A,另一些节点运行服务B,而服务B是依赖于服务A的,那么必须不能让运行B服务的节点先执行。
# 开启ssh长连接
开启ssh长连接 ,要求ssh为5.6版本,查看版本ssh -v

ControlPersist 只影响 空闲连接的保持时间,而不会干扰 正在运行的任务即
- 当最后一个 SSH 子连接(Ansible 的任务)执行完后,主控制连接仍然保持 5 天不关闭。
- 如果 5 天内再次执行 Ansible,它会直接复用这个连接;
- 超过 5 天没用,就会关闭,下次再执行会重新建立新的连接。
修改为5天
ssh_args = -C -o ControlMaster=auto -o ControlPersist=5d
# 开启pipeling
默认为Falsen,如果需要开启修改为True即可。

# 关闭gather_facts
方法1
在 playbook 文件开头写上:
- hosts: all
gather_facts: no
tasks:
- name: Disable facts gathering
debug:
msg: "No facts gathered"
2
3
4
5
6
方法2:全局修改
修改参数gather_facts为explicit即可

# Facts缓存
默认情况下,Ansible 每次执行 Playbook 都会重新收集 facts。这在大规模集群中非常耗时。Facts 缓存(Facts Cache) 就是让 Ansible 把上次收集的 facts 保存下来,下次直接读取,不再重新扫描主机。
文件缓存
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 86400
2
3
内存缓存
fact_caching = memory
fact_caching_timeout = 3600
2
Redis缓存
fact_caching = redis
fact_caching_connection = localhost:6379:0
fact_caching_timeout = 86400
2
3
# 强制刷新缓存
ansible-playbook site.yml --flush-cache
2
# 动态资产
你可以在命令行同时指定多个 inventory 文件,比如:
ansible-playbook -i hosts01.yaml -i hosts02.yaml site.yml
待补.............................
# 统计服务器基本信息
vim basic.yaml
粘贴如下内容
---
- name: Collect system info
hosts: Test
gather_facts: yes
tasks:
- name: Save system info header to local file
delegate_to: localhost
run_once: true
copy:
dest: ./system_info.csv
content: "IP,CPU,Memory(GB),DiskTotal(GB),OS\n"
- name: Calculate total disk size (GB)
set_fact:
total_disk_gb: "{{ ansible_devices | dict2items | map(attribute='value.size') | map('regex_replace', 'GB','') | map('float') | sum | round(0) }}"
- name: Append each host's info
delegate_to: localhost
lineinfile:
path: ./system_info.csv
line: "{{ inventory_hostname }},{{ ansible_processor_vcpus }},{{ (ansible_memtotal_mb / 1024) | round(0) }},{{ total_disk_gb }},{{ ansible_distribution }} {{ ansible_distribution_version }}"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ansible-playbook basic.yaml #会在当前目录生成一个system_info.csv文件
IP,CPU,Memory(GB),DiskTotal(GB),OS
IP,10,23.0,215.0,Debian 12
IP,8,16.0,120.0,Debian 12
2
3