不废话,让我们直接开始!
什么需求?
- 操作对象是3台服务器SRV01~03,都有Python环境
- 需要在每台服务器上跑一个收集服务信息的脚本
- 在Ansible控制台打印脚本输出
- 登陆服务器使用一般用户“my_work”,但脚本需要sudo执行
本例中涉及到的知识点
- Ansible Playbook标准目录结构
- 主机清单的基本写法和使用
- 远程执行命令并获取输出结果的Playbook写法(包括使用root权限)
开始整活
1. 创建工作目录
带“!”的目录,目录名请与下述保持一致。Ansible会自动从中读取所需内容。
pj/ (主目录)
|- site.yml
|- inventory (!)/
|- servers.ini
|- roles (!)
|- get_service_status
|- tasks (!)/
|- main.yml
2. 编辑inventory
Inventory(主机清单)就是执行Ansible脚本的对象。将以下内容写入inventory/servers.ini
。假设三个服务器的IP地址为192.168.0.1
~192.168.0.3
。
[my_servers]
SRV01 ansible_host=192.168.0.1 ansible_user=my_work ansible_become=yes ansible_become_password="你的sudo密码"
SRV02 ansible_host=192.168.0.2 ansible_user=my_work ansible_become=yes ansible_become_password="你的sudo密码"
SRV03 ansible_host=192.168.0.3 ansible_user=my_work ansible_become=yes ansible_become_password="你的sudo密码"
能够sudo执行的关键在于ansible_become
和ansible_become_password
这两个参数。没sudo需求的时候可以不写。
※ 这时候你的老板突然产生了一些大胆的想法
- 主机列表非得这么写吗?👴偏不。 👉用其他语言动态生成主机清单
- Root权限的用户名不是“root”怎么办? 👉主机清单的其他参数
3. 编辑site.yml
site.yml
一般作为脚本执行的入口。
---
- name: 获取服务器信息
hosts: my_servers
gather_facts: no # 没用就no
tasks:
roles:
- role: get_service_status
这里稍微说明一下:
hosts
:pj/inventory/servers.ini
中定义的主机。可以是一个组(这里的“my_servers”),也可以是某个主机(如servers.ini
里的“SRV01”)。role
:名称应与pj/roles
中的文件夹名一致。- 关于格式:如果
tasks
中没有内容,tasks
和roles
之间的换行是必须的。不然YAML的语法会将它们视为从属关系。
4. 编辑Role
将以下内容写入pj/roles/get_service_status/tasks/main.yml
。这里假设需要执行的脚本储存在服务器的/home/my_work/collect.sh
文件中。
- name: 执行脚本
become: yes # 因为要sudo执行
become_method: sudo
command: "bash /home/my_work/collect.sh"
# 如果远程主机没有Python环境则可以用raw代替command
register: service_status
- name: 打印结果
debug:
msg: "{{ service_status.stdout }}"
# 如果要打印整个变量,用“var:”。可查看变量结构
# var: service_status.stdout
※ 这时候你的老板又产生了一些大胆的想法
- 我想执行多条命令。 👉列表遍历
- 我想执行多条命令,不用列表遍历。 👉Ansible命令执行模块
- 我想把输出结果保存到文件里。 👉文件读写
- 我想把输出结果保存到预设了格式的文件里。 👉模板渲染
5. 执行脚本🎉
至此,实现需求所需要的条件都已具备。现在切回主目录pj/
中,执行以下命令执行Ansible Playbook。
ansible-playbook -i ./inventory/servers.ini ./site.yml
# -i用于指定主机清单定义文件。不写的话会使用默认文件
※ 这时候你的老板依然有一些大胆的想法
- 我想先验证远程主机的hostname,要是错了就不要继续执行了。 👉assert的使用