主机条件:
192.168.88.139 安装ansible
192.168.88.140 node1
192.168.88.141 node2
🚀 第一阶段:环境搭建与初始配置(建议1天)
这是所有实践的基础,我们需要配置好Ansible的控制节点和被管理节点。
-
配置主机名与Hosts解析:为了方便管理,建议为三台机器设置清晰的主机名。
-
控制节点 (Control Node) :建议命名为
ansible,IP为192.168.88.139。 -
受管节点 (Managed Nodes) :可以命名为
node1(140) 和node2(141)。 -
在所有节点的
/etc/hosts文件中,添加三台机器的IP和主机名映射。
-
-
安装Ansible :Ansible采用无代理架构,只需在控制节点 上安装即可。在CentOS 9上,官方推荐使用
dnf包管理器。

配置SSH免密登录:Ansible通过SSH协议与受管节点通信。需要在控制节点生成SSH密钥对,并将公钥复制到两台受管节点上。
ssh-keygen -t rsa # 在控制节点生成RSA密钥对(公钥+私钥)
ssh-copy-id root@node1 # 将公钥复制到 node1,并设置免密登录
ssh-copy-id root@node2 # 将公钥复制到 node2
结果:

创建一个项目目录project
mkdir project
cd project
创建主机清单(Inventory) :Inventory文件定义了Ansible要管理的主机。创建一个项目目录,并在其中创建 inventory.ini 文件:
进入到项目文件夹下:
执行:
vi inventory.ini
[webservers]
node1 ansible_host=192.168.88.140 ansible_user=root
node2 ansible_host=192.168.88.141 ansible_user=root
# 如果需要使用非root用户,请修改 ansible_user 和 become 相关设置
运行测试命令
ansible -i inventory.ini all -m ping
如果返回 "pong",说明一切就绪,可以开始愉快的自动化之旅了!
📚 第二阶段:Ansible核心概念与实战(建议1-2周)
这个阶段是学习的核心,需要掌握Ansible的常用模块和Playbook的编写。
-
Ad-Hoc命令(快速上手):先用简单的命令测试连通性和模块用法。
ansible -i inventory.ini all -m ping
ansible -i inventory.ini webservers -m command -a "df -h"
结果:

-
常用模块学习:Ansible拥有丰富的模块库,建议优先掌握以下几个:
-
command/shell:在远程主机执行命令。 -
copy:从控制节点拷贝文件到受管节点。 -
file:管理文件和目录的属性。 -
yum/dnf:管理软件包。 -
service:管理服务状态。 -
user:管理用户账号。 -
debug:输出变量或信息,用于调试。
-
-
Playbook编写(核心技能):Playbook是Ansible的配置、部署、编排语言,使用YAML格式编写。
-
基础语法 :理解Playbook的结构:
---、- hosts、tasks、name。 -
第一个Playbook :创建一个
first_playbook.yml,包含安装nginx、启动服务、拷贝一个自定义主页的任务。
-
创建first_playbook.yml文件
vi first_playbook.yml
粘贴内容:包含安装nginx、启动服务、拷贝一个自定义主页的任务。
---
- name: My first playbook
hosts: webservers
become: yes # 使用sudo权限
tasks:
- name: Install nginx
dnf:
name: nginx
state: present
- name: Start nginx
service:
name: nginx
state: started
enabled: yes
- name: Copy index.html
copy:
src: ./index.html
dest: /usr/share/nginx/html/index.html
在 /root/poject/ 目录下,创建一个 files 子目录,并在其中放入 index.html:
mkdir -p /root/poject/files
echo "Hello from GitOps!" > /root/poject/files/index.html
运行Playbook:
ansible-playbook -i inventory.ini first_playbook.yml
结果:
[root@139 poject]# echo "Hello from GitOps!" > /root/poject/files/index.html
[root@139 poject]# ansible-playbook -i inventory.ini first_playbook.yml
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [node1]
ok: [node2]
TASK [Install nginx] ********************************************************************************************************************************************************************************************
ok: [node1]
ok: [node2]
TASK [Start nginx] **********************************************************************************************************************************************************************************************
ok: [node1]
ok: [node2]
TASK [Copy index.html] ******************************************************************************************************************************************************************************************
changed: [node1]
changed: [node2]
PLAY RECAP ******************************************************************************************************************************************************************************************************
node1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@139 poject]#
变量与事实(Facts):
-
变量(Variables):学习如何在Playbook、Inventory文件或独立的变量文件中定义和使用变量。
-
Facts:Ansible会自动收集受管节点的系统信息(如IP地址、操作系统版本等),这些信息可以作为变量使用。
- name: Show OS family
debug:
msg: "The OS is {{ ansible_facts['os_family'] }}"
- name: Show OS family
-
任务控制:
-
条件判断(when) :只在特定条件下执行任务,例如只在Debian系系统上使用
apt模块。 -
循环(loop) :使用
loop关键字重复执行任务,例如创建多个用户。
-
🏗️ 第三阶段:Playbook进阶与最佳实践(建议1周)
当基础Playbook熟练后,可以开始学习如何让代码更规范、更可复用。
-
Jinja2模板 :使用
template模块和Jinja2模板语言动态生成配置文件。例如,根据不同的主机名或IP生成不同的nginx配置。yaml
- name: Deploy nginx config from template template: src: ./nginx.conf.j2 dest: /etc/nginx/nginx.conf -
Roles(角色) :Roles是Ansible中用于组织Playbook的最佳实践,它将变量、任务、文件、模板、处理器等按规范的结构组织起来。可以使用
ansible-galaxy init <role_name>命令创建一个角色骨架。 -
Handlers:Handlers是特殊的tasks,只在被notify时触发,通常用于在配置文件变更后重启服务。
接下来我们来做一个小项目:
🎯 第四阶段实践项目:使用角色部署带动态配置的 Nginx 网站
项目目标
-
在
node1和node2上安装 Nginx。 -
利用 Jinja2模板 生成一个自定义的
index.html,页面内容显示该主机的IP地址和主机名。 -
利用 Handler 在Nginx配置文件发生变更时自动重启服务。
-
将所有任务、变量、模板、handler封装到一个 角色(Role) 中,以便将来复用。
目录结构:
~/ansible-role-nginx/
├── ansible.cfg # 可选,用于指定配置文件
├── inventory.ini # 你的主机清单
├── site.yml # 入口Playbook
└── roles/
└── nginx_role/ # 角色名
├── tasks/
│ └── main.yml
├── handlers/
│ └── main.yml
├── templates/
│ ├── nginx.conf.j2 # Nginx主配置模板
│ └── index.html.j2 # 网站首页模板
├── vars/
│ └── main.yml
└── meta/
└── main.yml # 依赖关系(可选)
🛠 第一步:创建目录和角色骨架
使用 ansible-galaxy 自动生成角色骨架(省去手动建目录的麻烦)
cd ~
mkdir ansible-role-nginx && cd ansible-role-nginx
ansible-galaxy init roles/nginx_role
这会生成完整的目录结构,你只需保留需要的目录,删除示例文件或覆盖内容。
结果:
[root@139 ~]# cd ~
mkdir ansible-role-nginx && cd ansible-role-nginx
ansible-galaxy init roles/nginx_role
- Role roles/nginx_role was created successfully
[root@139 ansible-role-nginx]#
在项目文件夹下创建:
检查并编辑 inventory.ini:
vi inventory.ini
[webservers]
node1 ansible_host=192.168.88.140 ansible_user=root
node2 ansible_host=192.168.88.141 ansible_user=root
# 可选:全局变量
[all:vars]
ansible_user=root
📝 第二步:编写模板文件
2.1 编写 index.html.j2(位于 roles/nginx_role/templates/)
这是一个Jinja2模板,它会使用Ansible的 facts 变量动态生成内容
1. 进入项目根目录
cd ~/ansible-role-nginx
2. 确认 templates 目录存在(如果不存在则创建)
mkdir -p roles/nginx_role/templates
3. 创建并编辑 index.html.j2 文件
你可以使用任何文本编辑器(如 vi、nano 或 vim):
vi roles/nginx_role/templates/index.html.j2
将模板内容粘贴进去:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to {{ ansible_facts['hostname'] }}</title>
</head>
<body>
<h1>Server: {{ ansible_facts['hostname'] }}</h1>
<p>IP Address: {{ ansible_facts['default_ipv4']['address'] }}</p>
<p>OS: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}</p>
</body>
</html>
📄 第三步:编写任务(tasks/main.yml)
打开 roles/nginx_role/tasks/main.yml,填入以下内容:
---
- name: Install Nginx
dnf:
name: nginx
state: present
notify: restart nginx # 通知handler,在任务变化时重启
- name: Ensure nginx is enabled and started
systemd:
name: nginx
state: started
enabled: yes
- name: Deploy custom index.html from template
template:
src: index.html.j2
dest: /usr/share/nginx/html/index.html
owner: root
group: root
mode: '0644'
notify: restart nginx # 内容变化时重启
- name: Deploy nginx.conf from template (optional)
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: restart nginx
when: use_custom_config | default(false) | bool # 通过变量控制是否部署自定义配置
🔔 第四步:编写 Handler(handlers/main.yml)
Handlers 只有在被 notify 触发时才会执行,这里我们定义重启Nginx:
cd ~/ansible-role-nginx
pwd # 应该显示 /root/ansible-role-nginx 或类似路径
mkdir -p roles/nginx_role/handlers
vi roles/nginx_role/handlers/main.yml
粘贴 Handler 内容
进入编辑模式(按 i 键),粘贴以下内容:
---
- name: restart nginx
systemd:
name: nginx
state: restarted
📦 第五步:定义变量(vars/main.yml)
这里可以定义角色内部的默认变量,比如控制是否使用自定义配置:
---
# 是否部署自定义 nginx.conf,默认不部署(false)
use_custom_config: false
📋 第六步:编写入口Playbook(site.yml)
在项目根目录创建 site.yml,它引用我们刚写的角色:
---
- name: Apply Nginx configuration to web servers
hosts: webservers
become: yes
roles:
- nginx_role
🚀 第七步:运行Playbook
确保你的 inventory.ini 正确(注意不要有行尾注释),然后执行
ansible-playbook -i inventory.ini site.yml
执行后,观察输出:
-
每个任务的状态(
ok或changed)。 -
如果模板内容变化,会触发
restart nginxhandler。
🧪 第八步:验证结果
在浏览器中访问 http://192.168.88.140 和 http://192.168.88.141,你应该看到显示各自主机名和IP的页面。查看响应头(用 curl -I 或浏览器开发者工具)

