Ansible题目全解析与答案
一、安装和配置 ansible 环境
题目要求
-
安装所需软件包;
-
在
/home/student/ansible/inventory
文件中设置主机清单, -
要求:
node1 属于 test01 主机组,
node2 属于 test02 主机组,
node3 和 node4 属于 web 主机组,
node5 属于 test05 主机组,
web 组属于 webtest 主机组;
-
在
/home/student/ansible
目录中创建 ansible.cfg,满足以下需求:主机清单文件为/home/student/ansible/inventory
,playbook 中角色位置为/home/student/ansible/roles
,collection 位置为/home/student/ansible/collections
。
1. 安装所需软件包(控制机 master 操作)
2. 创建主机清单(/home/student/ansible/inventory
)
mkdir ansible
vim inventory
mkdir collections
ansible all -m ping
答案
yaml
[test01]
node1
[test02]
node2
[web]
node3
node4
[test05]
node5
[webtest:children]
web
3. 创建 ansible.cfg 配置文件(/home/student/ansible/ansible.cfg
)
答案
yaml
cd /etc/ansible/ansible.cfg
ansible-config init --disabled > ansible.cfg
##复制到/home/student/ansible/
# /home/student/ansible/ansible.cfg
[defaults]
# 文档要求:主机清单文件路径
inventory = /home/student/ansible/inventory
# 文档要求:角色存放路径
roles_path = /home/student/ansible/roles
# 文档要求:Collection 存放路径
collections_paths = /home/student/ansible/collections
# 补充配置:远程执行用户(文档预设受管机 sudo 用户为 student)
remote_user = student
host_key_checking=False
# 补充配置:开启 sudo 提权(系统操作需 root 权限)
become = yes
become_ask_pass=False
become_method=sudo
# 补充配置:sudo 目标用户(默认 root,满足系统配置需求)
become_user = root
# 补充配置:简化输出格式(便于查看任务执行结果)
stdout_callback = yaml
说明
- 核心配置项(inventory、roles_path、collections_paths)完全按文档路径设置,确保 Ansible 能正确加载资源;
- 补充
remote_user
和become
配置:适配文档"受管机预设 sudo 用户 student"的环境,通过student
远程登录后提权为root
,既符合权限规范,又能执行系统级任务。
二、创建和运行 Ansible 任务(编写yum.yml
)
题目要求
编写脚本/home/student/ansible/yum.yml
,为所有受管机配置 yum 仓库:
- 仓库 1:名称为 BASEOS,描述为 software base,URL 为
http://ansible.example.com/rhel9/BaseOS
,GPG 签名启用,GPG 密钥 URL 为http://ansible.example.com/rhel9/RPM-GPG-KEY-redhat-release
,仓库为启用状态; - 仓库 2:名称为 APPSTREAM,描述为 software stream,URL 为
http://ansible.example.com/rhel9/AppStream
,GPG 签名启用,GPG 密钥 URL 为http://ansible.example.com/rhel9/RPM-GPG-KEY-redhat-release
,仓库为启用状态。
答案
yaml
# /home/student/ansible/yum.yml
---
- name: 为所有受管机配置 BASEOS 和 APPSTREAM 仓库(文档要求)
hosts: all # 目标:所有受管机
tasks:
# 配置仓库 1:BASEOS(完全匹配文档参数)
- name: 配置 BASEOS Yum 仓库
yum_repository:
file: rhel9_repos # 统一存储到 /etc/yum.repos.d/rhel9_repos.repo
name: BASEOS # 文档要求:仓库名称
description: software base # 文档要求:仓库描述
baseurl: http://ansible.example.com/rhel9/BaseOS # 文档要求:仓库 URL
enabled: yes # 文档要求:启用仓库
gpgcheck: yes # 文档要求:启用 GPG 签名验证
gpgkey: http://ansible.example.com/rhel9/RPM-GPG-KEY-redhat-release
state: present # 确保仓库配置存在
# 配置仓库 2:APPSTREAM(完全匹配文档参数)
- name: 配置 APPSTREAM Yum 仓库
yum_repository:
file: rhel9_repos # 与 BASEOS 共用配置文件,减少冗余
name: APPSTREAM # 文档要求:仓库名称
description: software stream # 文档要求:仓库描述
baseurl: http://ansible.example.com/rhel9/AppStream # 文档要求:仓库 URL
enabled: yes # 文档要求:启用仓库
gpgcheck: yes # 文档要求:启用 GPG 签名验证
gpgkey: http://ansible.example.com/rhel9/RPM-GPG-KEY-redhat-release
state: present # 确保仓库配置存在
# 补充任务:清理并更新 Yum 缓存(确保新仓库立即生效)
- name: 清理 Yum 旧缓存并更新新缓存
yum:
clean: all
update_cache: yes
说明
- 两个仓库的所有参数(名称、描述、URL、GPG 配置)均严格按文档填写,无任何偏差;
- 共用
rhel9_repos.repo
文件,避免生成多个独立配置文件,便于后续统一管理; - 补充"清理缓存"任务:新仓库配置后需更新缓存,否则 Yum 无法识别新仓库的软件包,确保后续安装任务正常执行。
三、编写剧本远程安装软件(创建tools.yml
)
题目要求
创建名为/home/student/ansible/tools.yml
的 playbook,能够实现以下目的:
- 将 php 和 tftp 软件包安装到 test01、test02 和 web 主机组中的主机上;
- 将 RPM Development Tools 软件包组安装到 test01 主机组中的主机上;
- 将 test01 主机组中的主机上所有软件包升级到最新版本。
答案
yaml
# /home/student/ansible/tools.yml
---
# Play 1:为 test01、test02、web 组安装 php 和 tftp(文档要求 1)
- name: 安装 php 和 tftp 到目标主机组
hosts: test01:test02:web # 多组并集,匹配文档指定范围
tasks:
- name: 确保 php 和 tftp 已安装
yum:
name:
- php
- tftp
state: present
# Play 2:为 test01 组安装软件包组并升级(文档要求 2、3)
- name: 为 test01 组安装软件包组并升级所有软件
hosts: test01 # 仅针对 test01 组
tasks:
# 文档要求 2:安装 RPM Development Tools 软件包组
- name: 安装 RPM Development Tools 软件包组
yum:
name: "@RPM Development Tools" # 软件包组需加 @ 前缀
state: present
# 文档要求 3:升级 test01 组所有软件包到最新版
- name: 升级所有软件包到最新版本
yum:
name: '*' # 匹配所有已安装软件包
state: latest
说明
- 拆分两个 Play 逻辑:Play 1 处理多组的基础软件安装,Play 2 处理 test01 组的特殊需求(软件包组+全量升级),边界清晰,便于排查问题;
- 软件包组安装需加
@
前缀:这是 Yum 识别软件包组的专用语法,不加会导致"找不到软件包"错误; - 全量升级用
name: '*'
:确保 test01 组所有软件包均升级到最新版,完全满足"所有软件包升级"的要求。
四、配置计划任务(编写jihua.yml
)
题目要求
编写剧本/home/student/ansible/jihua.yml
:
- 在 test02 组中的被管理主机运行;
- 为用户 student 创建计划任务:student 用户每隔 5 分钟执行
echo "hello tarena"
。
答案
yaml
# /home/student/ansible/jihua.yml
---
- name: 为 test02 组 student 用户配置计划任务(文档要求)
hosts: test02 # 文档要求 1:仅在 test02 组执行
tasks:
- name: 创建 5 分钟执行一次的 cron 任务(文档要求 2)
cron:
name: "student-echo-task" # 任务名称,便于识别
user: student # 文档要求:任务归属 student 用户
minute: "*/5" # 文档要求:每隔 5 分钟执行(cron 表达式)
job: 'echo "hello tarena"' # 文档要求:执行的命令
state: present # 确保任务存在
说明
hosts: test02
严格限定执行范围,避免任务在其他组误执行;minute: "*/5"
是 cron 标准表达式,表示"每 5 分钟",完全匹配"每隔 5 分钟"的需求;- 命令用单引号包裹:防止双引号内的空格被解析为语法分隔符,确保命令原样执行。
五、安装并使用系统角色(timesync)(创建timesync.yml
)
题目要求
安装 RHEL 角色软件包,并创建剧本/home/student/ansible/timesync.yml
,满足以下要求:
- 在 test01 组中的被管理主机运行;
- 使用 timesync 角色;
- 配置该角色,使用时间服务器
ansible.example.com
,并启用 iburst 参数。
答案
步骤 1:安装 RHEL 系统角色(控制机操作)
bash
# 1. 切换 root 用户(安装系统软件包需 root 权限)
su - root
# 2. 安装含 timesync 角色的 rhel-system-roles 包
sudo yum -y install rhel-system-roles
# 3. 复制 timesync 角色到文档指定路径(确保 Ansible 能找到)
cp -r /usr/share/ansible/roles/rhel-system-roles.timesync -p /home/student/ansible/roles/timesync
步骤 2:编写timesync.yml
剧本
yaml
# /home/student/ansible/timesync.yml
#/home/student/ansible/roles/timesync/README.md可以找模板
---
- name: 为 test01 组配置时间同步(文档要求)
hosts: test01 # 文档要求 1:仅在 test01 组运行
vars:
# 文档要求 3:配置时间服务器及 iburst 参数
timesync_ntp_servers:
- hostname: ansible.example.com # 文档指定的时间服务器
iburst: yes # 文档要求:启用 iburst(加速初始同步)
# 补充配置:自动选择 NTP 服务(chronyd/ntpd)
timesync_ntp_provider: auto
roles:
- timesync # 文档要求 2:使用 timesync 角色
说明
- 系统角色默认路径为
/usr/share/ansible/roles
,需复制到文档指定的/home/student/ansible/roles
,否则 Ansible 无法加载角色; iburst: yes
的作用:初始同步时发送多个 NTP 请求,缩短时间同步耗时,完全满足文档要求;timesync_ntp_provider: auto
:让角色自动适配系统默认的 NTP 服务(RHEL9 默认 chronyd),无需手动指定,提升兼容性。
六、通过 galaxy 安装角色与 collection
题目要求
- 创建剧本
/home/student/ansible/roles/down.yml
,用来从以下 URL 下载角色,并安装到/home/student/ansible/roles
目录下:http://ansible.example.com/roles/haproxy.tar
(角色名为 haproxy)、http://ansible.example.com/roles/myphp.tar
(角色名为 myphp); - 从
http://ansible.example.com/materials/
下载如下 collection 并安装到/home/student/ansible/collections
目录下:ansible-posix-1.5.1.tar.gz
、community-general-6.3.0.tar.gz
。
答案
1. 安装角色(创建down.yml
并执行)
步骤 1:创建角色安装清单(down.yml
)
yaml
# /home/student/ansible/roles/down.yml
---
# 文档要求:安装 haproxy 角色
- name: haproxy # 文档指定角色名
src: http://ansible.example.com/roles/haproxy.tar # 文档指定角色 URL
# 文档要求:安装 myphp 角色
- name: myphp # 文档指定角色名
src: http://ansible.example.com/roles/myphp.tar # 文档指定角色 URL
步骤 2:执行角色安装
bash
# 在控制机执行,从清单文件安装角色
ansible-galaxy install -r roles/down.yml -p roles/
2. 安装 Collection
yaml
# 步骤 1:下载 Collection 到控制机指定目录
cd /home/student/ansible/
wget http://ansible.example.com/materials/ansible-posix-1.5.1.tar.gz
wget http://ansible.example.com/materials/community-general-6.3.0.tar.gz
# 步骤 2:安装 Collection 到文档指定路径
ansible-galaxy collection install ansible-posix-1.5.1.tar.gz -p /home/student/ansible/collections/
ansible-galaxy collection install community-general-6.3.0.tar.gz -p /home/student/ansible/collections/
# 验证安装结果
ansible-galaxy collection list -p /home/student/ansible/collections/
方法二:
cd /home/student/ansible/
ansible-galaxy collection install http://ansible.example.com/materials/ansible-posix-1.5.1.tar.gz -p collections/
ansible-galaxy collection install http://ansible.example.com/materials/community-general-6.3.0.tar.gz -p collections/
说明
- 角色安装通过
ansible-galaxy install -r
实现:从down.yml
清单读取角色信息,自动下载并安装到指定路径; - Collection 安装用
-p
指定路径:确保安装到文档要求的/home/student/ansible/collections
,而非默认路径; - 验证步骤必不可少:通过
ansible-galaxy collection list
确认 Collection 已正确安装。
七、创建及使用自定义角色(httpd 角色与myrole.yml
)
题目要求
根据下列要求,在/home/student/ansible/roles
中创建名为 httpd 的角色:
- 安装 httpd 软件,并能够开机自动运行;
- 开启防火墙,并允许 httpd 通过;
- 使用模板
index.html.j2
,用来创建/var/www/html/index.html
网页,内容如下(HOSTNAME 是受管理节点的完全域名,IPADDRESS 是 IP 地址):Welcome to HOSTNAME on IPADDRESS
;
然后创建剧本/home/student/ansible/myrole.yml
,为 webtest 主机组启用 httpd 角色。
答案
步骤 1:创建 httpd 角色目录结构(控制机操作)
bash
# 切换到角色目录,用 ansible-galaxy 自动生成标准化结构
cd /home/student/ansible/roles/
ansible-galaxy init httpd
步骤 2:编写角色核心文件
(1)任务文件(httpd/tasks/main.yml
)------ 实现核心功能
yaml
# /home/student/ansible/roles/httpd/tasks/main.yml
---
# 任务 1:安装 httpd 软件(文档要求 1)
- name: 安装 httpd 软件包
yum:
name:
- httpd
- firewalld
state: present # 确保软件已安装
# 任务 2:设置 httpd 开机自启并启动(文档要求 1)
- name: 启动 httpd 服务并设置开机自启
service:
name: "{{ item }}"
state: started # 确保服务运行中
enabled: yes # 确保开机自启
loop:
- httpd
- firewalld
- name: 允许 http 服务通过防火墙
firewalld:
service: http # 对应 httpd 的默认服务名
state: enabled
permanent: yes # 永久生效(重启防火墙不失效)
immediate: yes # 立即生效(无需重启防火墙)
# 任务 4:使用模板生成首页(文档要求 3)
- name: 从模板生成 /var/www/html/index.html
template:
src: index.html.j2 # 模板文件(存放在 roles/httpd/templates/ 下)
dest: /var/www/html/index.html # 目标文件路径
(2)模板文件(httpd/templates/index.html.j2
)------ 动态生成网页
jinja2
# /home/student/ansible/roles/httpd/templates/index.html.j2
# 文档要求:显示完全域名(HOSTNAME)和 IP 地址(IPADDRESS)
Welcome to {{ ansible_fqdn }} on {{ ansible_default_ipv4.address }}
- 说明:
ansible_fqdn
是 Ansible 内置 Facts 变量,自动获取受管机完全域名;ansible_default_ipv4.address
自动获取默认网卡的 IP 地址,完全匹配"HOSTNAME"和"IPADDRESS"的需求。
步骤 3:创建调用角色的剧本(myrole.yml
)
yaml
# /home/student/ansible/myrole.yml
---
- name: 为 webtest 主机组启用 httpd 角色(文档要求)
hosts: webtest # 目标主机组(文档指定)
roles:
- httpd # 调用自定义的 httpd 角色
执行与验证
bash
# 1. 执行剧本,为 webtest 组部署 httpd 服务
ansible-playbook /home/student/ansible/myrole.yml
# 2. 验证(在控制机访问 webtest 组节点,如 node3)
curl http://node3.example.com
# 预期输出:Welcome to node3.example.com on 192.168.122.30(与节点实际信息匹配)
说明
- 角色目录结构通过
ansible-galaxy init
生成,确保符合 Ansible 标准化规范,避免手动创建目录遗漏; - 模板文件中直接使用 Ansible 内置 Facts 变量,无需额外定义,实现"动态获取主机信息"的需求;
- 剧本中
hosts: webtest
严格匹配文档"为 webtest 主机组启用角色"的要求,确保任务仅在目标组执行。
八、使用之前通过 galaxy 下载的角色(创建web.yml
)
题目要求
创建剧本/home/student/ansible/web.yml
,满足下列需求:
- 该剧本中包含一个 play,可以在 test05 主机组运行 haproxy 角色(此角色已经配置好网站的负载均衡服务);
- 多次访问
http://node5.example.com
可以输出不同主机的欢迎页面; - 该剧本中包含另一个 play,可以在 webtest 主机组运行 myphp 角色(此角色已经配置好网站的 php 页面);
- 多次访问
http://node5.example.com/index.php
也输出不同主机的欢迎页面。
答案
yaml
# /home/student/ansible/web.yml
---
# Play 1:在 test05 组运行 haproxy 角色(文档要求 1)
- name: get fact
hosts: webtest
- name: 为 test05 主机组部署 haproxy 负载均衡(文档要求 1)
hosts: test05 # 文档指定目标组:test05
become: yes
roles:
- haproxy # 调用之前通过 Galaxy 下载的 haproxy 角色
# 说明:haproxy 角色已预设负载均衡配置,指向 webtest 组节点,满足"访问 node5 输出不同页面"(文档要求 2)
# Play 2:在 webtest 组运行 myphp 角色(文档要求 3)
- name: 为 webtest 主机组部署 myphp 服务(文档要求 3)
hosts: webtest # 文档指定目标组:webtest
roles:
- myphp # 调用之前通过 Galaxy 下载的 myphp 角色
# 说明:myphp 角色已配置 PHP 页面,结合 haproxy 负载均衡,满足"访问 index.php 输出不同页面"(文档要求 4)
执行与验证
bash
# 1. 执行剧本,部署 haproxy 和 myphp 角色
ansible-playbook /home/student/ansible/web.yml
# 2. 验证文档要求 2:访问 http://node5.example.com 输出不同页面
curl http://node5.example.com
# 预期输出:交替显示 node3 和 node4 的欢迎页面(haproxy 负载均衡生效)
# 3. 验证文档要求 4:访问 http://node5.example.com/index.php 输出不同页面
curl http://node5.example.com/index.php\
# 预期输出:交替显示 node3 和 node4 的 PHP 欢迎页面(myphp 角色+负载均衡生效)
说明
- 两个 Play 严格按文档要求拆分:Play 1 处理 test05 组的 haproxy 负载均衡,Play 2 处理 webtest 组的 myphp 服务,逻辑边界清晰;
- 负载均衡效果依赖 haproxy 角色预设配置(默认指向 webtest 组节点),无需额外编写负载均衡规则,符合文档"角色已配置好"的前提;
- 多次访问验证是关键:通过循环访问确认负载均衡生效,满足"输出不同主机页面"的需求。
九、编写剧本远程管理逻辑卷(创建lvm.yml
)
题目要求
创建剧本 /home/student/ansible/lvm.yml
,用来为所有受管机完成以下部署:
- 在卷组 search 中创建名为 mylv 的逻辑卷,大小为 1000MiB;
- 使用 ext4 文件系统格式化该逻辑卷;
- 如果无法创建要求的大小,应显示错误信息 insufficient free space,并改为 500MiB;
- 如果卷组 search 不存在,应显示错误信息 VG not found;
- 不需要挂载逻辑卷。
答案
yaml
# /home/student/ansible/lvm.yml
---
- name: 管理逻辑卷(在 search 卷组创建 mylv)(文档要求)
hosts: all # 目标:所有受管机
tasks:
# 任务 1:检查卷组 search 是否存在(文档要求 4)
- name: 检查卷组 search 的存在性
command: vgdisplay search
register: vg_check_result
ignore_errors: yes # 忽略卷组不存在的错误,避免剧本中断
# 任务 2:卷组不存在时显示错误信息(文档要求 4)
- name: 卷组 search 不存在,输出错误信息
debug:
msg: "ERROR: VG not found" # 文档要求的错误信息
when: vg_check_result.rc != 0 # 命令返回码非 0 表示卷组不存在
# 任务 3:卷组存在时,尝试创建 1000MiB 的逻辑卷(文档要求 1)
- name: 尝试在 search 卷组创建 1000MiB 的 mylv
lvol:
vg: search
lv: mylv
size: 1000MiB
state: present
register: lv_create_result
ignore_errors: yes # 忽略空间不足的错误
when: vg_check_result.rc == 0 # 仅卷组存在时执行
# 任务 4:空间不足时,显示错误并创建 500MiB 逻辑卷(文档要求 3)
- name: 空间不足,显示错误并创建 500MiB 的 mylv
block:
# 显示空间不足错误
- name: 输出空间不足错误信息
debug:
msg: "ERROR: insufficient free space" # 文档要求的错误信息
# 创建 500MiB 逻辑卷
- name: 创建 500MiB 的 mylv 逻辑卷
lvol:
vg: search
lv: mylv
size: 500MiB
state: present
when:
- vg_check_result.rc == 0 # 卷组存在
- lv_create_result.rc != 0 # 1000MiB 创建失败(空间不足)
# 任务 5:格式化逻辑卷为 ext4(文档要求 2)
- name: 用 ext4 格式化 mylv 逻辑卷
filesystem:
fstype: ext4
dev: /dev/search/mylv # 逻辑卷设备路径
when:
- vg_check_result.rc == 0 # 卷组存在
- (lv_create_result.rc == 0 or "created" in lv_create_result.msg) # 逻辑卷已创建
说明
- 用
vgdisplay search
检查卷组存在性:通过命令返回码判断,而非依赖 Facts,避免 Facts 未更新导致误判; - 分条件处理逻辑:卷组不存在→输出"VG not found";空间不足→输出"insufficient free space"并创建 500MiB 卷;正常情况→创建 1000MiB 卷,完全匹配文档要求;
block
模块用于批量执行任务:将"显示错误+创建小卷"打包,避免重复写when
条件,简化代码。
yaml
---
- name: cerate lv
hosts: all
tasks:
- name: create lv1
block:
- name: create 1000 lv
lvol:
vg: search
lv: mylv
size: 1000
rescue:
- name: print message
debug:
msg: insufficient free space
- name: create 500 lv
lvol:
vg: search
lv: mylv
size: 500
always:
- name: format lv
filesystem:
dev: /dev/search/mylv
fstype: ext4
when: "'search' in ansible_lvm.vgs"
- name: print failed message
debug:
msg: VG not found
when: "'search' not in ansible_lvm.vgs "
十、根据模板部署主机文件(创建newhosts.yml
)
题目要求
从 http://ansible.example.com/materials/newhosts.j2
下载模板文件,完成该模板文件,用来生成新主机清单(主机的显示顺序没有要求),结构如下:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.122.10 node1.example.com node1
192.168.122.20 node2.example.com node2
192.168.122.30 node3.example.com node3
192.168.122.40 node4.example.com node4
192.168.122.50 node5.example.com node5
创建剧本/home/student/ansible/newhosts.yml
,它将使用上述模板在 test01 主机组的主机上生成文件/etc/newhosts
。
答案
步骤 1:下载并完善模板文件(控制机操作)
bash
# 1. 下载模板到指定目录
cd /home/student/ansible/
curl -O http://ansible.example.com/materials/newhosts.j2
vim newhost.j2
{% for i in groups.all %}
{{ hostvars[i].ansible_default_ipv4.address }} {{ hostvars[i].ansible_fqdn }} {{ hostvars[i].ansible_hostname }}
{% endfor %}
步骤 2:编写剧本(newhosts.yml
)
yaml
# /home/student/ansible/newhosts.yml
---
- name: get fact
hosts: all
- name: 为 test01 组生成 /etc/newhosts 文件(文档要求)
hosts: test01 # 文档要求:仅在 test01 组运行
gather_facts: no # 模板为固定内容,无需收集主机信息,加快执行速度
tasks:
- name: 使用 newhosts.j2 模板生成 /etc/newhosts
template:
src: /home/student/ansible/newhosts.j2 # 本地模板路径
dest: /etc/newhosts # 文档要求的目标文件路径
执行与验证
bash
# 1. 执行剧本
ansible-playbook /home/student/ansible/newhosts.yml
# 2. 验证(在 test01 组节点 node1 执行)
cat /etc/newhosts
# 预期输出与模板内容完全一致,包含所有主机的 IP 与主机名映射
说明
- 模板为固定内容:因文档要求的主机清单结构是静态的(IP 和主机名已明确),无需使用 Jinja2 变量,直接写入固定内容即可;
gather_facts: no
优化执行效率:避免收集不必要的主机信息,减少剧本执行时间;- 权限设置符合系统规范:
/etc/newhosts
作为系统配置文件,权限设为0644
,确保root可修改、其他用户可读取。
十一、编写剧本修改远程文件内容(创建newissue.yml
)
题目要求
创建剧本 /home/student/ansible/newissue.yml
,满足下列要求:
- 在所有清单主机上运行,替换
/etc/issue
的内容; - 对于 test01 主机组中的主机,
/etc/issue
文件内容为 test01; - 对于 test02 主机组中的主机,
/etc/issue
文件内容为 test02; - 对于 web 主机组中的主机,
/etc/issue
文件内容为 Webserver。
答案
yaml
# /home/student/ansible/newissue.yml
---
- name: Configure /etc/issue based on host group
hosts: all # 在所有清单主机上执行
tasks:
- name: Set /etc/issue content by host group
copy:
content: |
{% if 'test01' in group_names %}
test01
{% elif 'test02' in group_names %}
test02
{% elif 'web' in group_names %}
Webserver
{% endif %}
dest: /etc/issue # 目标文件路径
yaml
[student@master ansible]$ ansible node1 -m shell -a "cat /etc/issue"
node1 | CHANGED | rc=0 >>
test01
十二、编写剧本部署远程 Web 目录(创建webdev.yml
)
题目要求
创建剧本/home/student/ansible/webdev.yml
,满足下列要求:
- 在 test01 主机组运行;
- 创建目录
/webdev
,属于 webdev 组,权限为 rwxrwxr-x,具有 SetGID 特殊权限; - 使用符号链接
/var/www/html/webdev
链接到/webdev
目录; - 创建文件
/webdev/index.html
,内容是 It's works!; - 查看 test01 主机组的 web 页面
http://node1/webdev/
将显示 It's works!。
答案
yaml
# /home/student/ansible/webdev.yml
---
- name: 为 test01 组部署 Web 目录(文档要求)
hosts: test01 # 文档要求 1:仅在test01组运行
tasks:
- name: install httpd
yum:
name:
- httpd
- firewalld
state: present
- name: 创建 webdev 用户组
group:
name: webdev
state: present
- name: 创建 /webdev 目录(rwxrwxr-x + SetGID)
file:
path: /webdev
state: directory
group: webdev
mode: '2775' # 2=SetGID,775=rwxrwxr-x,完全匹配权限要求
setype: httpd_sys_content_t
- name: 创建符号链接 /var/www/html/webdev
file:
src: /webdev
dest: /var/www/html/webdev
state: link
- name: 创建 /webdev/index.html,写入内容 It's works!
copy:
content: "It's works!\n"
dest: /webdev/index.html
mode: '0644'
setype: httpd_sys_content_t
- name: 启动 httpd 服务并设置开机自启
service:
name: "{{ item }}"
state: restarted
enabled: yes
loop:
- httpd
- firewalld
- name: set firewalld
firewalld:
service: http
state: enabled
permanent: yes
immediate: yes
执行与验证
bash
# 1. 执行剧本部署Web目录
ansible-playbook /home/student/ansible/webdev.yml
curl http://node1/webdev/ # 预期输出:It's works!
说明
- 目录权限
2775
的含义:2
代表SetGID(确保后续在该目录创建的文件自动继承目录组权限),775
对应rwxrwxr-x
,完全匹配文档权限要求; - 符号链接用
state: link
创建:Ansiblefile
模块的link
类型专门用于创建符号链接,需明确src
(源路径)和dest
(目标路径); - 补充
httpd
服务启动任务:若之前未部署httpd,需确保服务运行才能访问Web页面,满足文档"查看web页面"的最终需求。
十三、编写剧本为受管机生成硬件报告(创建hardware.yml
)
题目要求
创建名为/home/student/ansible/hardware.yml
的 playbook,满足下列要求:
- 使所有受管理节点从以下 URL 下载文件:
http://ansible.example.com/materials/hardware.empty
; - 并用来生成以下硬件报告信息,存储在各自的
/root/hardware.txt
文件中:清单主机名称inventory_hostname
、以 MB 表示的总内存大小ansible_memtotal_mb
、BIOS 版本ansible_bios_version
、硬盘 vda 的大小ansible_devices.vda.size
、硬盘 vdb 的大小ansible_devices.vdb.size
;如果这些硬件信息不存在的话,则改成 NONE 字符串。
答案
yaml
# /home/student/ansible/hardware.yml
---
- name: 为所有受管机下载文件并生成硬件报告(文档要求)
hosts: all # 目标:所有受管机
become: yes
tasks:
# 任务 1:下载 hardware.empty 文件(文档要求 1)
- name: 从远程 URL 下载 hardware.empty 到 /tmp
get_url:
url: http://ansible.example.com/materials/hardware.empty # 文档指定URL
dest: /tmp/hardware.empty # 下载到临时目录
mode: '0644'
owner: root
group: root
force: yes # 若文件已存在,强制覆盖
# 任务 2:生成硬件报告 /root/hardware.txt(文档要求 2)
- name: 生成硬件报告到 /root/hardware.txt
copy:
content: |
清单主机名称: {{ inventory_hostname | default('NONE') }}
总内存大小(MB): {{ ansible_memtotal_mb | default('NONE') }}
BIOS版本: {{ ansible_bios_version | default('NONE') }}
硬盘vda大小: {{ ansible_devices.vda.size | default('NONE') if 'vda' in ansible_devices else 'NONE' }}
硬盘vdb大小: {{ ansible_devices.vdb.size | default('NONE') if 'vdb' in ansible_devices else 'NONE' }}
dest: /root/hardware.txt # 文档指定的报告路径
mode: '0600' # 仅root可读写,保护硬件信息
owner: root
group: root
执行与验证
bash
# 1. 执行剧本(需收集Facts,默认开启)
ansible-playbook /home/student/ansible/hardware.yml
# 2. 验证硬件报告(在任意受管机执行,如node1)
ssh student@node1 "sudo cat /root/hardware.txt"
# 预期输出示例:
# 清单主机名称: node1.example.com
# 总内存大小(MB): 1982
# BIOS版本: 1.16.0
# 硬盘vda大小: 20.00 GB
# 硬盘vdb大小: NONE(若vdb不存在)
说明
- 用
default('NONE')
处理变量缺失:对于inventory_hostname
、ansible_memtotal_mb
等简单变量,直接用default
过滤器指定默认值为NONE
; - 用
if 'vda' in ansible_devices
处理设备不存在:ansible_devices
是存储设备信息的字典,需先判断vda
/vdb
是否在字典中,再获取大小,避免"键不存在"报错; - 报告权限设为
0600
:/root/hardware.txt
存储硬件敏感信息,仅允许root读写,符合安全规范; get_url
模块下载文件:自动处理HTTP下载,force: yes
确保下载最新文件,避免旧文件干扰。
方法二:
创建名为/home/student/ansible/hardware.yml
的 playbook,满足下列要求:
-
使所有受管理节点从以下 URL 下载文件:
http://ansible.example.com/materials/hardware.empty
; -
并用来生成以下硬件报告信息,存储在各自的
/root/hardware.txt
文件中:清单主机名称
inventory_hostname
、以 MB 表示的总内存大小
ansible_memtotal_mb
、BIOS 版本
ansible_bios_version
、硬盘 vda 的大小
ansible_devices.vda.size
、硬盘 vdb 的大小
ansible_devices.vdb.size
;如果这些硬件信息不存在的话,则改成 NONE 字符串。
yaml
curl -O http://ansible.example.com/materials/hardware.empty
vim hardware.empty
hostname=inventoryhostname
mem=memory_in_MB
bios=BIOS_version
vdasize=disk_vda_size
vdbsize=disk_vdb_size
## 查看信息的事实变量
ansible node1 -m setup > a
vim a
vim hardware.yml
---
- name: test
hosts: all
tasks:
- name: test2
get_url:
url: http://ansible.example.com/materials/hardware.empty
dest: /root/hardware.txt
- name: hostname
replace:
path: /root/hardware.txt
regexp: inventoryhostname
replace: "{{ inventory_hostname }}"
- name: men
replace:
path: /root/hardware.txt
regexp: memory_in_MB
replace: "{{ ansible_memtotal_mb }}"
- name: bios
replace:
path: /root/hardware.txt
regexp: BIOS_version
replace: "{{ ansible_bios_version }}"
- name: vda
replace:
path: /root/hardware.txt
regexp: disk_vda_size
replace: "{{ ansible_devices.vda.size if ansible_devices.vda is defined else 'NONE' }}"
- name: vdb
replace:
path: /root/hardware.txt
regexp: disk_vdb_size
replace: "{{ ansible_devices.vdb.size if ansible_devices.vdb is defined else 'NONE'}}"
十四、创建保险库文件(passdb.yml
)
题目要求
创建 ansible 保险库 /home/student/ansible/passdb.yml
,其中有 2 个变量:
pw_dev
,值为 ab1234;pw_man
,值为 cd5678;
加密和解密该库的密码是 pwd@1234,密码存在/home/student/ansible/secret.txt
中。
答案
步骤 1:创建密码文件(存储保险库密码)
bash
# 在控制机创建 secret.txt,写入保险库密码
echo "pwd@1234" > /home/student/ansible/secret.txt
# 设置权限为 0600,仅student可读写(避免密码泄露)
chmod 0600 /home/student/ansible/secret.txt
步骤 2:创建未加密的变量文件
bash
# 创建 passdb.yml,写入 2 个变量(文档要求)
---
pw_dev: ab1234
pw_man: cd5678
步骤 3:用密码文件加密保险库
bash
# 使用 secret.txt 中的密码加密 passdb.yml
ansible-vault encrypt passdb.yml --vault-id secret.txt
# 验证加密状态(尝试查看文件,需解密)
ansible-vault view passdb.yml --vault-id secret.txt
# 预期输出:解密后的变量内容(pw_dev: ab1234;pw_man: cd5678)
- 密码文件权限
0600
:确保只有student
用户能读取密码,避免其他用户获取保险库解密权限; ansible-vault encrypt
加密文件:加密后文件内容变为乱码,需通过--vault-password-file
指定密码文件才能解密;ansible-vault view
验证加密:解密查看文件内容,确认变量正确且加密生效,避免后续使用时因变量错误或加密失败导致问题。
十五、编写剧本为受管机批量创建用户(创建users.yml
)
题目要求
从以下 URL 下载用户列表,保存到/home/student/ansible
目录下:http://ansible.example.com/materials/name_list.yml
;
创建剧本/home/student/ansible/users.yml
的 playbook,满足下列要求:
- 使用之前题目中的 passdb.yml 保险库文件提供的密码做用户密码;
- 职位描述为 dev 的用户应在 test01、test02 主机组的受管机上创建,使用 pw_dev 变量分配密码,是补充组 devops 的成员;
- 职位描述为 man 的用户应在 web 主机组的受管机上创建,使用 pw_man 变量分配密码,是补充组 opsmgr 的成员;
- 密码应采用 SHA512 哈希格式,这几个用户的密码最大有效时间为30天;
- 该 playbook 可以使用之前题目创建的 secret.txt 密码文件运行。
答案
步骤 1:下载用户列表(控制机操作)
bash
# 下载 name_list.yml 到指定目录
cd /home/student/ansible/
curl -O http://ansible.example.com/materials/name_list.yml
vim name_list.yml
users:
- name: tom
job: dev
- name: jerry
job: man
步骤 2:编写users.yml
剧本
yaml
vim users.yml
---
- name: test1
hosts: test01:test02
vars_files:
- /home/student/ansible/passdb.yml
- /home/student/ansible/name_list.yml
tasks:
- name: test2
group:
name: devops
state: present
- name: create user
user:
name: "{{ item.name }}"
state: present
groups: devops
password: "{{ pw_dev | password_hash('sha512') }}"
password_expire_max: 30
loop: "{{ users }}"
when: item.job == 'dev'
- name: test2
hosts: web
vars_files:
- /home/student/ansible/passdb.yml
- /home/student/ansible/name_list.yml
tasks:
- name: test3
group:
name: opsmgr
state: present
- name: create user1
user:
name: "{{ item.name }}"
state: present
groups: opsmgr
password: "{{ pw_man | password_hash('sha512') }}"
password_expire_max: 30
loop: "{{ users }}"
when: item.job == 'man'
##执行
ansible-playbook users.yml --vault-id secret.txt
##验证
ssh root@node1
vi /etc/shadow
yaml
# vim users.yml
---
# Play 1:为 test01、test02 组创建 dev 职位用户(文档要求 2)
- name: 为 test01/test02 组创建 dev 职位用户
hosts: test01:test02 # 文档指定的目标组
become: yes
# 引用保险库文件和用户列表(文档要求 1、5)
vars_files:
- /home/student/ansible/passdb.yml # 保险库文件(含pw_dev)
- /home/student/ansible/name_list.yml # 用户列表(含职位描述)
tasks:
# 先创建补充组 devops(文档要求 2)
- name: 创建 devops 补充组
group:
name: devops
state: present
# 批量创建 dev 职位用户
- name: 创建 dev 职位用户(补充组 devops)
user:
name: "{{ item.name }}" # 从用户列表获取用户名
comment: "{{ item.desc | default('Dev User') }}" # 职位描述(默认值)
# 文档要求 4:SHA512 哈希密码(pw_dev 来自保险库)
password: "{{ pw_dev | password_hash('sha512') }}"
groups: devops # 文档要求 2:补充组 devops
append: yes # 不覆盖用户原有补充组
# 文档要求 4:密码最大有效时间 30 天
password_expire_max: 30
state: present
loop: "{{ user_list }}" # 假设用户列表变量名为 user_list(需与 name_list.yml 一致)
when: item.job == "dev" # 文档要求 2:仅职位为 dev 的用户
# Play 2:为 web 组创建 man 职位用户(文档要求 3)
- name: 为 web 组创建 man 职位用户
hosts: web # 文档指定的目标组
become: yes
vars_files:
- /home/student/ansible/passdb.yml # 保险库文件(含pw_man)
- /home/student/ansible/name_list.yml # 用户列表
tasks:
# 先创建补充组 opsmgr(文档要求 3)
- name: 创建 opsmgr 补充组
group:
name: opsmgr
state: present
# 批量创建 man 职位用户
- name: 创建 man 职位用户(补充组 opsmgr)
user:
name: "{{ item.name }}"
comment: "{{ item.desc | default('Man User') }}"
# 文档要求 4
十六、重设保险库密码
从以下 URL 下载保险库文件到/home/student/ansible 目录:
http://ansible.example.com/materials/topsec.yml
当前的库密码是 banana,新密码是 big_banana,请更新该库密码
yaml
curl -O http://ansible.example.com/materials/topsec.yml
ansible-vault rekey topsec.yml
ansible-vault view topsec.yml