Ansible流程

4916 字
25 分钟
Ansible流程

Ansible流程#

[TOC]


when判断#

  • 假设服务器主机名为 web01.example.com
表达式含义结果
等于 (==)完全一样才算匹配❌️不匹配 (因为 web01.example.com 不等于 web01)
is match开头必须和你写的完全一样✅️匹配 (因为 web01.example.com 确实是以 web01 开头的)
is search主机名里面包含你写的这部分就行✅️匹配 (因为 web01.example.com 里确实包含了 web01)
  • == (等于): 最严格!要求主机名一模一样,一字不差
    • 用得少,因为实际主机名可能更复杂
  • is match: 比较严格,看开头
    • 你想让所有以 web 开头的服务器执行任务
      • 比如 web01, web02, web-db-backup
  • is search: 最宽松!适合==模糊查找==
    • 你想让所有主机名里含有 web 的服务器执行任务
    • 比如 web01, backup-web-data, web-db-server 都会匹配
Terminal window
1)主机名称为web01安装wget命令
# 这里使用的是==必须完全等于才行!
[root@m01 ansible]# vim when.yml
- hosts: webs
tasks:
- name: Install wget
yum:
name: wget
state: present
when: ansible_hostname == "web01"
# 这个when模块和上面的yum模块对齐!
# 这里内置变量不需要加"{{ }}"
# 后面web01必须加上双引号" "
[root@m01 ansible]# ansible-playbook --syntax-check when.yml
[root@m01 ansible]# ansible-playbook when.yml
skipping: [web02]
ok: [web01]
'跳过web02,只在web01上执行'
2)web01下载wget web02下载tree命令
[root@m01 ansible]# vim when.yml
- hosts: webs
tasks:
- name: Install wget
yum:
name: wget
state: present
when: ansible_hostname == "web01"
- name: Install tree
yum:
name: tree
state: present
when: ansible_hostname == "web02"
[root@m01 ansible]# ansible-playbook when.yml
TASK [Install wget]*****
skipping: [web02]
ok: [web01] # 跳过web02
TASK [Install tree] *****
skipping: [web01]
ok: [web02] # 跳过web01
3)并且关系
# 同时满足才行
[root@m01 ansible]# vim when.yml
- hosts: webs
tasks:
- name: Install wget
yum:
name: wget
state: present
when: (ansible_hostname == "web01") and (ansible_default_ipv4.address == "10.0.0.7" )
# 这个是and连接,两边用小括号连接起来!
'或者使用列表的方式'
when:
- ansible_hostname == "web01"
- ansible_default_ipv4.address == "10.0.0.7"
# 并且关系,更加的清楚
4)或者关系 or
when: (ansible_hostname == "web01") or (ansible_default_ipv4.address == "10.0.0.8")
[root@m01 ansible]# ansible-playbook when.yml
ok: [web01]
ok: [web02]

Nginx判断实战#

1️⃣阶段一#

image-20260405110842170
image-20260405110842170

- hosts: webs
tasks:
- name: Configure nginx repo
yum_repository:
name: nginx-stable
description: nginx stable repo
baseurl: https://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
enabled: yes
- name: Install nginx server
yum:
name: nginx
state: present
- name: Configure copy nginx file
copy:
src: ./nginx.conf
dest: /etc/nginx/
- name: Create group www
group:
name: www
gid: 888
- name: Create user www
user:
name: www
uid: 888
group: www
shell: /sbin/nologin
create_home: false
- name: Start nginx server
systemd:
name: nginx
state: started
enabled: yes

image-20260405111247319
image-20260405111247319

  • 重新执行一遍都是绿色的,说明没有任何的改变!!
Terminal window
[root@m01 ~]# vim nginx.conf
user nginx;
# 启动用户由www-->nginx
  • 我们改动一下配置文件!
    • 再执行一遍会怎样❓️

image-20260405111909542
image-20260405111909542

  • 我们来看一下它的启动用户是谁??
Terminal window
[root@web01 ~]#ps aux | grep nginx
www S 08:24 0:00 nginx: worker process
'依旧是www用户!'

2️⃣阶段二#

image-20260405144803358
image-20260405144803358

Handler 是什么?

你可以把 Handler 想象成一个待命的“服务兵”

  • 普通任务 (Task): 像勤劳的工人,Playbook 一运行,它们就立刻干活
  • Handler: 像是等待指令的特警队员,站在一旁待命
    • 只有收到特定的“信号”,它才会行动

  • 触发 (Notify): 在一个普通的 Task 里,比如“拷贝 nginx 配置文件”

    • 你加上一个 notify: restart nginx

    • 这个 notify 就是“信号”或“通知”


判断与执行: Ansible 执行*“拷贝 nginx 配置文件”*这个任务时

  • 它会特别留意:这次操作有没有改变什么东西?

  • 如果没有改变:

    • 比如本地的配置文件和服务器上的文件一模一样
    • 那么,notify 就像没听到一样,handler 不会被触发,服务不会重启
  • 如果有改变:

    • 比如本地的配置文件发生了改变,拷贝操作成功更新了服务器上的文件
    • 这时,Ansible 认为这个任务“状态改变了
    • 它就会立刻向*“重启 nginx”*这个 handler 发送一个==“信号”==
      • 💡 注意:此时还没重启!只是“记住了要重启”

统一执行: 所有的 Tasks 都跑完后,在 Playbook 的最后阶段

  • Ansible 会检查有哪些 handler 收到了信号

  • 它会把所有收到信号的 handlers按顺序执行一遍

    • 🎯 重点:即使同一个 handler 被多个 task 触发了
      • 只会执行一次
  • 如果没人通知它,它就一直待命,啥也不干

🌟为什么要这么设计? (好处)

  • 避免不必要的操作:
    • 盲目重启,不仅浪费资源,还可能导致短暂的服务中断
    • Handler 保证了只有在真正需要(配置变了)的时候才重启
  • 提高效率:
    • 即使你的 playbook 里有 10 个地方都修改了 nginx 配置
    • 并且都想重启 nginx
    • 使用 notify 也能确保 nginx 最终只被重启一次,而不是 10 次
- hosts: webs
tasks:
- name: Install nginx server
yum:
name: nginx
state: present
- name: Configure copy nginx file
copy:
src: ./nginx.conf
dest: /etc/nginx/
notify: Restart nginx
# 只要有改变,就给名字为Res..的handler发信号
# 和copy平级
- name: Start nginx server
systemd:
name: nginx
state: started
enabled: yes
handlers:
# 跟tasks平级,前面没有-
- name: Restart nginx
# 这个name和上面的notify保持一致
# 最后,不管收到几次信号,只重启一次
systemd:
name: nginx
state: restarted
  • 上面的配置文件少了yum仓库配置, 创建组和用户!
Terminal window
现在webs的运行用户还是www
'www nginx: worker process'
我们给配置文件首行加一个空行!
# 也算是配置文件发生了改变

image-20260405144616540
image-20260405144616540

Terminal window
[root@web01 ~]#ps aux | grep nginx
nginx nginx: worker process
'现在启动用户就是nginx了!'
Terminal window
但如果我的配置文件改错了!
那么它重启也会报错的❌️
[root@m01 ~]# head -1 nginx.conf
ser nginx;
# 少一个u
[root@m01 ~]# ansible-playbook nginx.yml
TASK [Configure copy nginx file]
changed: [web01]
changed: [web02]
'配置文件依旧改变!'
....
RUNNING HANDLER [Restart nginx]
fatal: [web02]: FAILED! => {"changed": false, "msg": "Unable to restart service nginx:"
# 重启部分直接报错了!!
'webs的nginx也停止'
[root@web01 ~]#ps aux | grep nginx|grep -v grep | wc -l
0

3️⃣阶段三#

image-20260405163346326
image-20260405163346326

- hosts: webs
gather_facts: no
tasks:
- name: Configure copy nginx file
copy:
src: ./nginx.conf
dest: /etc/nginx/
notify: Restart nginx
# 只要有改变,就给名字为Res..的handler发信号
# 和copy平级
- name: Check nginx from ng_re
command: "nginx -t"
register: ng_re
# 把这条命令的结果返回给变量ng_re
ignore_errors: yes
# 当结果错误时候忽略掉、继续向下执行
handlers:
# 跟tasks平级,前面没有-
- name: Restart nginx
# 这个name和上面的notify保持一致
# 最后,不管收到几次信号,只重启一次
systemd:
name: nginx
state: restarted
when: ng_re.stderr_lines is search "successful"
# 当返回的变量找到了successful
# 且收到了notify的信号(配置文件修改)才能重启
===============================
when: ng_re.rc is match "0"
# 我们也可以通过状态码是否为0来判断是否执行成功
# 上面是匹配以0开头的...
这个 == 0 不成立!
# 后面还有个逗号,
"rc": 0,
  • 下面是 nginx -t 正常的返回结果
    • debug模块中的 msg
Terminal window
- name: Print nginx_result
debug:
msg: "{{nginx_re}}"
===============================
"msg": {
"changed": true,
"cmd": [
"nginx",
"-t"
],
"delta": "0:00:00.004444",
"end": "2026-04-04 15:04:48.508624",
"failed": false,
"msg": "",
✅️"rc": 0,
"start": "2026-04-04 15:04:48.504180",
"stderr": "nginx: the configuration file /etc/nginx/nginx.conf syntax is ok\nnginx: configuration file /etc/nginx/nginx.conf test is successful",
✅️"stderr_lines": [
"nginx: the configuration file /etc/nginx/nginx.conf syntax is ok",
"nginx: configuration file /etc/nginx/nginx.conf test is successful"
],
"stdout": "",
"stdout_lines": []
}
}
Terminal window
1)我们再次修改配置文件,触发notify
[root@m01 ~]# vim nginx.conf
user nginx;
# 改正确!
[root@m01 ~]# ansible-playbook nginx.yml
web01 : ok=3 changed=3
web02 : ok=3 changed=3
# 三步都改变!
2)notify给handler发信号,我的配置文件修改了!请重启
# 是否真的重启,还要看when判断!
3)第二步nginx -t执行成功了-->变量里面有successful
4)handler收到信号,是否重启由when判断
5)when从变量中找到了successful,且handler收到了信号
6)重启Nginx
===============================
# 那我们试着把配置文件改错试试会怎么样!!
[root@m01 ~]# vim nginx.conf
ser nginx;
[root@m01 ~]# ansible-playbook nginx.yml

image-20260405155737147
image-20260405155737147

Terminal window
'ignore_errors: yes'
# 当nginx -t执行失败,则不中断,继续往下走!
===============================
如果没有忽略,则直接中断!
# 跳出playbook,不往下执行了

image-20260405163250438
image-20260405163250438

  • ==最终版==
- hosts: webs
tasks:
- name: Configure nginx repo
yum_repository:
name: nginx-stable
description: nginx stable repo
baseurl: https://nginx.org/packages/centos/7/$basearch/
gpgcheck: no
enabled: yes
- name: Install nginx server
yum:
name: nginx
state: present
- name: Create Group www
group:
name: www
gid: 666
state: present
- name: Create User www
user:
name: www
uid: 666
group: www
shell: /sbin/nologin
create_home: false
- name: Configure Nginx Server
copy:
src: nginx.conf
dest: /etc/nginx/
notify: Restart Nginx Server
- name: nginx -t
command: nginx -t
register: ng_re
ignore_errors: yes
- name: Start Nginx Server
# 开机启动&&自启
systemd:
name: nginx
state: started
enabled: yes
handlers:
- name: Restart Nginx Server
# 配置文件修改重启
systemd:
name: nginx
state: restarted
enabled: yes
when: ng_re.rc is match "0"

字典循环#

Terminal window
[root@m01 ansible]# vim f.yml
- hosts: web01
tasks:
- name: Create many file
file:
path:
- a.txt
- b.txt
state: touch
[root@m01 ansible]# ansible-playbook --syntax-check f.yml
playbook: f.yml
[root@m01 ansible]# ansible-playbook f.yml
changed: [web01]
# 也是执行成功了!
[root@web01 ~]#ls
'['\''a.txt'\'', '\''b.txt'\'']'
# ❌️回到web01进行验证,这是创建了个啥!
⚠️file不支持这样创建文件
[root@web01 ~]#rm -rf ./*
[root@web01 ~]#ls | wc -l
0
# 都删除了
1)创建多个文件
[root@m01 ansible]# vim f.yml
- hosts: web01
tasks:
- name: Create many file
file:
path: "{{item}}"
# 固定用法,必须是item
state: touch
loop:
# 和file对齐,loop就是循环的意思!
- a.txt
- b.txt
[root@web01 ~]#ls
a.txt b.txt
[root@web01 ~]#ls | wc -l
2
# 成功创建出来两个文件
'权限不同,属主不同'
[root@m01 ansible]# cat f.yml
- hosts: web01
tasks:
- name: Create many files
file:
path: "{{item.path}}"
state: touch
owner: "{{item.owner}}"
group: "{{item.group}}"
mode: "{{item.mode}}"
loop:
- {path: a.txt, owner: root, group: root, mode: "0644"}
- {path: b.txt, owner: www, group: www, mode: "0755"}
# 这个权限(是数字)必须要加引号
# 用大括号括起来
[root@m01 ansible]# ansible-playbook --syntax-check f.yml
playbook: f.yml
[root@m01 ansible]# ansible-playbook f.yml
changed: [web01] => (item={'path': 'a.txt', 'owner': 'root', 'group': 'root', 'mode': '0644'})
changed: [web01] => (item={'path': 'b.txt', 'owner': 'www', 'group': 'www', 'mode': '0755'})
[root@web01 ~]#ls -lh
total 0
-rw-r--r-- 1 root root 0 Apr 5 20:55 a.txt
-rwxr-xr-x 1 www www 0 Apr 5 20:55 b.txt
2)拷贝多个文件
[root@m01 ansible]# vim c.yml
- hosts: web01
tasks:
- name: Copy many files
copy:
src: "{{item.src}}"
dest: "{{item.dest}}"
mode: "{{item.mode}}"
loop:
# 使用下面这种方法也是可以的,更加清晰!
- src: rsyncd.conf
dest: /home/
mode: "0600"
- src: info.txt
dest: /home/
mode: "0644"
[root@m01 ansible]# ansible-playbook --syntax-check c.yml
playbook: c.yml
[root@m01 ansible]# ansible-playbook c.yml
changed: [web01] => (item={'src': 'rsyncd.conf', 'dest': '/home/', 'mode': '0600'})
changed: [web01] => (item={'src': 'info.txt', 'dest': '/home/', 'mode': '0644'})
[root@web01 ~]#ls -lh /home/
-rw-r--r-- 1 root root 106 Apr 5 21:16 info.txt
-rw------- 1 root root 427 Apr 5 21:16 rsyncd.conf
3)创建多个组和用户
[root@m01 ansible]# vim g.yml
- hosts: web01
tasks:
- name: Create many groups
group:
name: "{{item.name}}"
gid: "{{item.gid}}"
loop:
- name: test01
gid: "778"
- name: test02
gid: "779"
# 这些数字前面一定要加引号!
- name: Create many users
user:
name: "{{item.name}}"
uid: "{{item.uid}}"
group: "{{item.group}}"
shell: "{{item.shell}}"
create_home: "{{item.home}}"
# 后面这个点后面的东西随便写!
# 只要能够与下面的loop对应就可以
loop:
- name: test01
uid: "778"
group: test01
shell: /sbin/nologin
home: false
# 这个home与上面的item.home相对应!
- name: test02
uid: "779"
group: test02
shell: /bin/bash
home: true
[root@m01 ansible]# ansible-playbook --syntax-check g.yml
[root@m01 ansible]# ansible-playbook g.yml
'测试验证部分'
[root@web01 ~]#id test01
uid=778(test01) gid=778(test01) groups=778(test01)
[root@web01 ~]#id test02
uid=779(test02) gid=779(test02) groups=779(test02)
[root@web01 ~]#grep test /etc/passwd
test01❌778:778::/home/test01:/sbin/nologin
test02❌779:779::/home/test02:/bin/bash
[root@web01 ~]#ls -d /home/test02/
/home/test02/
4)同时重启NGINX和PHP服务
[root@m01 ansible]# vim re.yml
- hosts: web01
tasks:
- name: Restart server
systemd:
name: "{{item}}"
state: restarted
loop:
- nginx
- php-fpm
[root@m01 ansible]# ansible-playbook re.yml
changed: [web01] => (item=nginx)
changed: [web01] => (item=php-fpm)

Jinja2模版#

Jinja2 模板文件(.j2)里有两个“逻辑控制”

  • ==for循环== 和 ==if判断==

你就把 .j2 文件想象成一个**“填空题试卷”**:

  • {{ }} 是用来填答案的(变量)
    • template模块 的用法,参考 ==📚Ansible03==
      • 对比着 copy模块
  • {% %} 是用来写“解题指令”的(循环和判断)

在 Ansible 里,循环主要出现在两个地方,我们一个个来看:

🛠️ 场景一:在 ==任务playbook== 里循环(干活时用)

  • 这是最常用的, 比如你要创建 3 个用户
  • 配合 loop 关键字, 和 {{ item }} 变量
    • 就是我们上面👆的字典循环

📄 场景二:在 ==模板.j2== 里循环(生成文件时用)

  • 当你需要生成配置文件,里面有一堆重复的段落

  • 只是 IP或端口 不一样时,就用 {% for %}

特性第一组:任务级循环第二组:模板级逻辑
核心关键词loop{{ item }}{% for %}{% if %}
写在哪里?Playbook (.yml 文件)模板 (.j2 文件)
谁来配合?任何模块都能配 (如 yum, user)必须配合 template 模块使用
变量怎么传?直接用 loop 列表靠 Playbook 里的 vars 传进去

For 循环:#

Terminal window
{% for 变量名 in 列表数据 %}
这里写重复的内容,用 {{ 变量名 }} 来引用当前的数据
{% endfor %}
===============================
1)列表数据我们经常用 range
# range(7,9)--->包含7,不包含9
# 7,8
2)模板里换行了,会出现空白
'可以加减号 - '
减号 - 贴着哪边,就吸掉哪边的“空白”(换行符或空格)
⚠️这个 - 写在里面
{%- for n in range(7,9) %}
{%- endfor %}
# 把前面的空白都吸走!
===============================
🦄案例: 生成负载均衡的配置文件
[root@m01 ansible]# vim lb.conf.j2
upstream {{server_name}} {
{%- for n in range(7,9) %}
server 172.16.1.{{n}}:{{ up_port }}
{%- endfor %}
}
server {
listen 80;
server_name {{ server_name }};
location / {
root /code;
index index.html;
proxy_pass http://{{ server_name }};
proxy_set_header Host $http_host;
}
}
# 里面总共两个变量--->在剧本中定义vars变量
[root@m01 ansible]# vim l.yml
- hosts: web01
vars:
- server_name: wp.kpyun.com
- up_port: 80
# 先写vars变量,后写task任务
# tasks和vars对齐
tasks:
- name: Configure lb file
template:
src: ./lb.conf.j2
dest: /etc/nginx/conf.d/lb.conf
'测试验证!'
[root@web01 ~]#cat /etc/nginx/conf.d/lb.conf
upstream wp.kpyun.com {
server 172.16.1.7:80
server 172.16.1.8:80} # 最后的大括号在这!
server {
listen 80;
server_name wp.kpyun.com;
...

If 判断#

Terminal window
'基本语法结构:'
{% if 条件成立 %}
写这段内容
{% elif 其他条件 %}
写那段内容
{% else %}
如果上面都不对,就写这个
{% endif %}
===============================
🦄案例.将keepalived.conf.j2拷贝到两台web
routeid--->都以自身主机名称生成
# web01生成是角色master 票数150
# web02生成的角色backup 票数100
===============================
[root@m01 ansible]# vim keepalived.conf.j2
global_defs {
router_id {{ ansible_hostname }}
}
vrrp_instance VI_1 {
{% if ansible_hostname is match "web01" %}
# 实际这里面应该是lb01
state MASTER
priority 150
{% else %}
# 这里用elif再进行判断也是可以的!
state BACKUP
priority 100
{% endif %}
interface eth0
virtual_router_id 50
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}
# .j2模版文件只有if判断
[root@m01 ansible]# vim k.yml
- hosts: webs
tasks:
- name: Configure keepalived file
template:
src: ./keepalived.conf.j2
dest: /root/keepalived.conf
[root@m01 ansible]# ansible-playbook k.yml
changed: [web02]
changed: [web01]
# 两台web都改变了,我们细看配置文件
'测试验证'
[root@web01 ~]# cat keepalived.conf
global_defs {
router_id web01
}
# 主,优先级150
vrrp_instance VI_1 {
state MASTER
priority 150
.....
[root@web02 ~]# cat keepalived.conf
global_defs {
router_id web02
}
# 是备份,优先级100
vrrp_instance VI_1 {
state BACKUP
priority 100
......

📚任务标签#

Terminal window
# 默认情况:当你运行一个playbook(一堆任务的集合),Ansible就像一个忠实的机器人,会老老实实地把所有的任务都执行一遍
Ansible的标签(tag)功能可以给单独任务或者一部分任务打上标签
然后利用这些标签:
-t 🏷️ # 只做带标签的事,其他都跳过
--skip-tags 🏷️ # 跳过特定标签任务,除了它都运行
--list-tags # 查看有哪些标签
=========================================
[root@m01 ansible]# vim t.yml
- hosts: web01
tasks:
- name: Configure nginx file
copy:
src: ./nginx.conf
dest: /etc/
tags: conf
# 别忘记加s
# 标签名随便起
- name: nginx -t
command: "nginx -t"
ignore_errors: yes
tags: nt
- name: Restart nginx
systemd:
name: nginx
state: restarted
[root@m01 ansible]# ansible-playbook --syntax-check t.yml
playbook: t.yml
[root@m01 ansible]# ansible-playbook t.yml
'先正常执行一遍!'
TASK [Configure nginx file]
changed: [web01]
*****************
TASK [nginx -t]
changed: [web01]
*****************
TASK [Restart nginx]
changed: [web01]
# 三个都执行了一遍!
=========================================
1)查看有哪些标签🏷️
[root@m01 ansible]# ansible-playbook t.yml --list-tags
play #1 (web01): web01 TAGS: []
TASK TAGS: [conf, nt]
'两个标签 conf和nt '
2)运行特定标签
[root@m01 ansible]# ansible-playbook t.yml -t nt
# 后接标签名
TASK [nginx -t]
changed: [web01]
'只运行了这个nt标签'
3)跳过标签
# 后面也必须跟标签名!🏷️
[root@m01 ansible]# ansible-playbook t.yml --skip-tags conf
TASK [nginx -t]
changed: [web01]
*******************
TASK [Restart nginx]
changed: [web01]
"跳过了配置这一步,只运行了-t检测和重启"
# 我们试着后面可不可以跟多个标签!
❌️--skip-tags conf nt # 不能用空格隔开
✅️--skip-tags conf,nt # 可以用逗号隔开
[root@m01 ansible]# ansible-playbook t.yml --skip-tags conf,nt
TASK [Restart nginx]
changed: [web01]
'这样的话只执行了重启的任务'
🦄# 但其实有更简便的方法🦄
1)可以给多个不同的任务打上相同的标签
2)这样用 --skip-tags 一次性跳过所有这些打了相同标签的任务
- hosts: web01
tasks:
- name: Configure nginx file
copy:
src: ./nginx.conf
dest: /etc/nginx/
tags: test
- name: nginx -t
command: "nginx -t"
ignore_errors: yes
tags: test
- name: Restart nginx
systemd:
name: nginx
state: restarted
Terminal window
# 都打上了test标签🏷️
[root@m01 ansible]# ansible-playbook t.yml --list-tags
play #1 (web01): web01 TAGS: []
TASK TAGS: [test]
[root@m01 ansible]# ansible-playbook t.yml --skip-tags test
TASK [Restart nginx]
changed: [web01]
# 同样只运行了Restart操作

📚文件复用#

Terminal window
以前写多个playbook没有办法,一键执行
# 需要按照顺序一个个去做,这很麻烦
1)现在可以把你常用的一些任务(比如安装Nginx、配置php)写在不同的文件里
# 让每个部分更清晰、更易于维护和复用
2)最后写一个主任务清单(main playbook),把它们包含在里面
3)我们只需要执行主任务清单,它会运行被包含进来的任务
# 从而实现真正的“一键部署”
=========================================
需求: web01配置并重启Nginx, web02配置并重启php
1)准备两个tasks文件
[root@m01 ansible]# vim n.yml
'直接从- name开始写'
# 被包含在all.yml中
- name: Copy Nginx server
copy:
src: ./nginx.conf
dest: /etc/nginx/
- name: nginx -t
command: "nginx -t"
ignore_errors: yes
- name: Restart nginx server
systemd:
name: nginx
state: restarted
[root@m01 ansible]# vim p.yml
- name: Copy php configure
copy:
src: ./www.conf
dest: /etc/php-fpm.d/
- name: Restart php
systemd:
name: php-fpm
state: restarted
2)编写主任务清单
# 将上面两个文件包含引入
[root@m01 ansible]# vim all.yml
- hosts: webs
tasks:
- name: Nginx part
# 名字随便起
include_tasks: n.yml
when: ansible_hostname is match "web01"
# 只有匹配到web01时执行nginx..
- name: php part
include_tasks: p.yml
when: ansible_hostname is match "web02"
# 只有匹配到web02时执行php..
3)检测&&执行
[root@m01 ansible]# ansible-playbook --syntax-check n.yml
# 检测的时候,不能单独检测n.yml和p.yml,它们俩是子文件
'肯定有问题呀!'--->它们是以 - name开头❌️
✅️应该直接检测all.yml文件
[root@m01 ansible]# ansible-playbook --syntax-check all.yml
playbook: all.yml
[root@m01 ansible]# ansible-playbook all.yml
PLAY [webs]
********************
TASK [Nginx part] --->"主任务清单"
skipping: [web02]
included: /home/ansible/n.yml for web01
'跳过web02,只执行web01'
********************
TASK [Copy Nginx server]
ok: [web01]
********************
TASK [nginx -t]
changed: [web01]
********************
TASK [Restart nginx server]
changed: [web01]
'web01依次执行以上三步!'
********************
TASK [php part] --->"主任务清单"
skipping: [web01]
included: /home/ansible/p.yml for web02
'跳过web01'
********************
TASK [Copy php configure]
ok: [web02]
********************
TASK [Restart php]
changed: [web02]
'web02执行php部分'
********************
web01 : ok=4 changed=2
web02 : ok=3 changed=1
⚠️主任务清单只有两个任务⚠️

抑制changed#

在 Ansible 中,一个任务执行后,根据它是否真的改变了目标主机的状态,会在输出中显示不同的颜色:

  • 绿色 (OK): 表示任务执行了,但目标主机的状态没有发生改变。
  • 黄色 (Changed): 表示任务执行了,并且确实对目标主机做了修改

command 模块执行任何命令,默认情况下都会被认为是 changed 状态(黄色)

  • 即使 nginx -t 只是测试配置,它确实是在目标主机上执行了一个操作
    • 所以 Ansible 会认为这是一个“变化”(Changed)

changed_when: false

  • 强制覆盖其默认的 changed 状态,使其显示为 ok(绿色)
  • 从而让整个 playbook 的执行结果更具可读性和准确性

  • df -hlsps auxfree -mcat /etc/hostname

  • 它们的主要目的都是查询、查看或诊断系统状态,而不是去修改任何东西

  • 可以让这些执行了操作但未改变系统状态的任务,能正确地显示为绿色 (OK)

Terminal window
[root@m01 ansible]# vim c.yml
- hosts: web01
tasks:
- name: nginx -t
command: "nginx -t"
register: ng_re
ignore_errors: yes
tags: check
# 没有抑制前
[root@m01 ansible]# ansible-playbook c.yml
TASK [nginx -t]
changed: [web01]
'每运行一次都会执行一遍!'
- hosts: web01
tasks:
- name: nginx -t
command: "nginx -t"
register: ng_re
ignore_errors: yes
tags: check
changed_when: false
Terminal window
[root@m01 ansible]# ansible-playbook c.yml
TASK [nginx -t]
ok: [web01]
'现在运行都是OK✅️'
# 由changed(黄色)-->ok(绿色)

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Ansible流程
https://www.kpyun.fun/posts/automation/ansible/ansible04/
作者
久棹
发布于
2026-06-02
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录