Ansible剧本与变量实战全攻略

Ansible剧本与变量实战全攻略

一、概述

本文聚焦Ansible核心进阶功能,全面讲解Playbook剧本的编写规范、实操案例、流程控制(handlers/when/loop)、剧本调试技巧、Jinja2模板高级用法、文件包含(include)、模块化部署(Roles)、敏感信息加密(Vault)、第三方Roles共享(Galaxy) 及Ansible性能与安全优化,覆盖Ansible从基础到高阶的全量核心知识点。所有内容均结合实际运维场景设计案例,适配运维日常应急响应、项目维护、架构巡检、服务标准化部署等核心工作场景。本文从基础语法到实战部署层层递进,知识点全覆盖且实操性强,助力快速掌握集群批量部署的剧本化、变量化、模块化、安全化管理能力,完成Ansible自动化运维的全技能闭环。

二、核心知识点

2.1 Ansible Playbook剧本核心知识点

  1. 核心概念:Playbook(剧本)是Ansible用于持久化保存批量管理、部署、维护操作的YAML格式文件,存放模块与操作步骤,可重复调用,是Ansible实现自动化部署的核心。
  2. 与Ad-hoc模式的对比:二者均基于Ansible模块实现批量管理,核心差异在于复用性和应用场景,具体对比如下:
特性 Ansible Playbook Ansible Ad-hoc
复用性 可重复调用、持久化保存 临时执行,不易重复使用
操作类型 多步骤、复杂服务部署 单步骤、临时测试/操作
应用场景 集群服务部署、标准化运维 模块测试、临时批量执行命令
  1. YAML格式规范:Playbook的核心书写规则,直接决定剧本是否能正常执行:
    • .yml.yaml为后缀;
    • 同一层级内容左对齐,不同层级通过2个空格缩进区分;
    • 禁止使用Tab键缩进;
    • 键值对以键: 值形式书写,冒号后需加1个空格。
  2. 核心结构:单个Playbook由一个或多个Play组成,每个Play包含核心要素:
    • hosts:指定要管理的主机/主机组(对应主机清单);
    • vars/vars_files:定义/加载变量(可选);
    • tasks:任务列表,由多个task组成,每个task对应一个Ansible模块的执行操作;
    • handlers:触发器任务,由普通任务触发执行;
    • roles:加载模块化Roles(新增);
    • gather_facts:是否收集主机Facts信息(默认开启,可选关闭)。
  3. 剧本执行核心流程:先收集主机Facts信息(默认),再按tasks中的顺序依次执行每个任务,若任务触发handlers则在当前Play的所有任务执行完成后运行触发器,所有操作完成后返回执行结果(成功/失败/跳过)。

2.2 Ansible变量核心知识点

  1. 核心作用:类似于Shell脚本中的变量,用于统一管理剧本中的可变参数(如路径、IP、用户名),提升剧本的通用性和可维护性,支持在剧本多位置定义、多场景调用。
  2. 定义与加载位置:按使用场景和生效范围划分,常用定义位置及说明如下,星标为运维高频使用
定义位置 生效范围 适用场景 优先级
剧本内vars⭐⭐ 仅当前Play 单剧本、少量可变参数
独立变量文件vars_files 仅当前Play 单剧本、多可变参数
主机组变量group_vars⭐⭐⭐⭐⭐ 指定主机组/所有主机 多剧本共用参数、标准化部署
Roles内置变量(新增) 仅当前Role 模块化部署中Role专属参数
Facts变量⭐⭐ 所有Play(对应主机) 获取主机基础信息(IP、CPU、系统) 内置
Register注册变量⭐⭐ 仅当前Play 捕获命令执行结果、实现脚本反引号功能
主机清单中定义 指定主机/主机组 批量修改主机参数(极少用)
命令行定义 单次剧本执行 临时修改参数(几乎不用) 最高
  1. 变量引用规则:使用{{ 变量名 }}引用,若变量为选项开头,必须加双引号;变量非开头,可省略引号。
  2. 核心变量工具
    • setup模块:手动获取主机Facts变量信息;
    • template模块:解析Jinja2模板文件中的变量并分发(区别于仅做文件拷贝的copy模块);
    • debug模块:测试/输出变量内容,是变量调试的核心模块。

2.3 Ansible流程控制核心知识点⭐⭐⭐⭐

流程控制是Ansible实现条件化执行、批量执行、触发式执行的核心,包含handlers(触发器)、when(条件判断)、loop/with_items(循环)三类核心功能,是提升剧本灵活性的关键,核心信息如下:

流程控制功能 核心概念 核心应用场景 关键规则
handlers触发器 由普通任务触发执行的特殊任务,仅当触发任务的状态为changed时才运行 分发配置文件后,配置变化则重启服务,无变化则不执行 1. 需通过notify指定触发名称;2. 需写在剧本最后;3. 触发名称与handlers任务名一致
when条件判断 为任务设置执行条件,满足条件则执行,不满足则跳过 1. 按系统版本(CentOS/Ubuntu)执行不同安装命令;2. 按主机名/IP执行指定操作;3. 结合变量做逻辑判断 1. 与Facts/Register变量配合使用;2. 支持and/or/is match/!=等逻辑/匹配符号;3. 多条件需用括号包裹
loop/with_items循环 实现任务的批量迭代执行,替代重复书写相同任务 1. 批量启动/重启服务;2. 批量创建用户/目录;3. 批量分发文件 1. loop为官方推荐用法,与with_items功能一致;2. 用{{ item }}引用循环变量;3. 支持单变量/键值对多变量循环

2.4 Ansible剧本调试核心知识点⭐⭐⭐

剧本调试是解决Playbook执行失败、优化剧本的关键,Ansible提供语法检查、单步执行、tag标签、忽略错误四类核心调试技巧,适配不同调试场景,核心信息如下:

调试技巧 核心命令/参数 应用场景 关键说明
语法检查 ansible-playbook --syntax-check 剧本.yml 检查剧本YAML语法、模块参数错误 仅检查语法,不实际执行任务
模拟运行 ansible-playbook -C 剧本.yml 预览任务执行结果,不修改被控端文件/配置 部分变量可能报错,因未实际执行任务
单步执行 无专属命令,执行时手动选择y/n/c 逐任务调试,定位具体失败的任务 y执行当前任务,n跳过,c自动执行后续所有任务
tag标签 任务中定义tags: 标签名,执行时-t 标签名/--skip-tags 标签名 1. 仅执行剧本中的指定任务;2. 跳过剧本中的指定任务 多标签用逗号分隔,支持查看剧本所有标签
忽略错误 任务中添加ignore_errors: true 忽略任务执行的非致命错误(如目录已存在、用户已创建),保证剧本继续运行 仅适用于重复执行导致的非真实错误,不可全局使用

2.5 Jinja2模板核心知识点⭐⭐⭐⭐

Jinja2是Ansible的模板引擎,与template模块配合使用,可在文件中实现变量引用、条件判断、循环迭代,是实现配置文件动态生成的核心,适配Nginx/Keepalived/NFS等服务的个性化配置分发,核心规则如下:

  1. 模板文件后缀:必须以.j2为后缀,template模块默认解析该格式文件;
  2. 核心语法标签
    • {{ 变量名 }}:变量引用标签,与Ansible变量引用规则一致;
    • {% 逻辑语句 %}:逻辑控制标签,用于书写if判断、for循环,需以{% endif %}/{% endfor %}结尾;
    • {# 注释内容 #}:注释标签,模板渲染时会忽略该内容,区别于文件原生注释;
  3. 核心功能:支持变量解析多条件判断多类型循环(列表/数字范围/键值对),渲染后再分发至被控端;
  4. 与copy模块的区别copy仅做文件纯拷贝,不解析任何内容;template渲染模板(解析变量/逻辑),再将渲染后的文件分发至被控端。

2.6 Ansible文件包含(include_tasks)核心知识点⭐⭐

  1. 核心概念include_tasks是Ansible用于拆分大型Playbook的功能,将一个复杂的多Play/多任务剧本拆分为多个小型子剧本,通过include_tasks在主剧本中加载,实现剧本的模块化拆分与合并。
  2. 核心应用场景
    • 大型服务部署剧本(如同时包含服务端、客户端、监控配置),拆分后便于维护和调试;
    • 多个剧本共用相同的任务序列(如环境初始化任务),抽离为子剧本后重复引用;
  3. 关键规则
    • 子剧本需遵循标准YAML格式,仅包含tasks列表(无需hosts等Play级配置);
    • 主剧本通过- include_tasks: 子剧本.yml加载子任务,加载后与主剧本的tasks按顺序执行;
    • 子剧本中可使用主剧本定义的变量,变量作用域贯通。

2.7 Ansible Roles核心知识点⭐⭐⭐⭐⭐(运维高频)

  1. 核心概念:Roles是Ansible对剧本目录结构的标准化规范,本质是按功能模块划分的目录集合,将剧本、变量、配置文件、模板、触发器等按固定目录分类存储,实现剧本的高度模块化、可复用、易维护,是企业级Ansible自动化运维的核心方式。
  2. 核心目录结构:Roles的目录规范为固定格式,新建Role时需按以下结构创建,Ansible会自动识别加载对应目录下的文件:
role名称/          # Role核心目录(如nfs-server/、rsync-server/)
├── files/         # 存放无需解析的静态文件(如普通配置文件、脚本),copy模块直接引用
├── templates/     # 存放Jinja2模板文件(.j2后缀),template模块自动读取
├── tasks/         # 核心任务目录,必须包含main.yml(任务入口文件),按顺序执行
├── handlers/      # 触发器目录,必须包含main.yml(触发器入口文件)
├── vars/          # Role专属变量目录,main.yml中定义变量,仅当前Role生效
└── defaults/      # 默认变量目录(可选),优先级低于vars,用于定义默认参数
  1. 核心执行逻辑
    • 通过入口剧本(如top.yml)指定roles: - role: Role名称,加载对应的Role;
    • Ansible自动按tasks/main.ymlhandlers/main.yml的顺序执行,自动读取files/templates/目录下的文件;
    • Role变量可通过group_vars/vars/或命令行传入,实现参数灵活配置。
  2. 核心优势
    • 目录结构标准化,团队协作时无需熟悉整体剧本,仅关注单个Role的功能;
    • 可复用性极强,一个Role可在多个项目、多个环境中直接引用;
    • 变量与代码分离,通过变量文件即可适配不同环境(开发/测试/生产)。

2.8 Ansible Vault核心知识点⭐⭐⭐(安全必备)

  1. 核心概念:Vault是Ansible用于加密敏感信息的工具,可对变量文件、主机清单、剧本中的敏感数据(如密码、密钥、端口)进行加密,避免敏感信息明文存储,提升Ansible运维的安全性。
  2. 支持加密的文件类型
    • 变量文件(如vars.yml、group_vars/all/vars.yml);
    • 主机清单文件(hosts);
    • 包含敏感信息的Playbook剧本文件;
  3. 核心操作命令
操作类型 命令 说明
加密文件 ansible-vault encrypt 文件名 对指定文件进行加密,需设置加密密码
解密文件 ansible-vault decrypt 文件名 对加密文件彻底解密,需输入加密密码
查看加密文件 ansible-vault view 文件名 不解密文件,直接查看内容,需输入密码
编辑加密文件 ansible-vault edit 文件名 临时解密并编辑文件,保存后自动重新加密
批量加密 ansible-vault encrypt 文件1 文件2 同时加密多个文件,共用一个加密密码
  1. 执行加密剧本:加密后的文件无法直接执行,需在执行时通过以下方式提供密码:
    • 交互式输入:ansible-playbook --ask-vault-pass 加密剧本.yml,执行时手动输入密码;
    • 密码文件:ansible-playbook --vault-password-file 密码文件 加密剧本.yml,密码文件需设置600权限。

2.9 Ansible Galaxy核心知识点⭐⭐

  1. 核心概念:Galaxy是Ansible的第三方Roles共享平台,类似于Python的PyPI、JavaScript的npm,提供海量现成的Roles(如Nginx、MySQL、Docker部署),用户可直接下载使用,无需从零编写剧本,大幅提升运维效率。
  2. 核心操作命令
    • 安装第三方Role:ansible-galaxy collection install 作者.角色名(如ansible-galaxy collection install nginxinc.nginx_core,安装Nginx官方Role);
    • 搜索Role:ansible-galaxy search 关键词(如ansible-galaxy search nginx,搜索Nginx相关Role);
    • 列出已安装Role:ansible-galaxy collection list
    • 删除Role:ansible-galaxy collection remove 作者.角色名
  3. 核心应用场景:标准化服务部署(如Nginx、MySQL、K8s),直接复用成熟Role,减少重复开发,降低脚本编写错误风险。

2.10 Ansible优化核心知识点⭐⭐⭐

Ansible优化聚焦性能提升安全加固,通过配置调整、环境优化等方式,适配大规模集群管理和高安全需求场景,核心优化方向如下:

优化方向 核心措施 优化效果 关键配置/命令
SSH连接速度 关闭被控端UseDNS、GSSAPIAuthentication 减少SSH连接耗时,提升批量执行速度 被控端/etc/ssh/sshd_configUseDNS noGSSAPIAuthentication no,重启sshd
并发执行数量 调整Ansible并发数(forks) 支持大规模集群批量执行,提升效率 配置文件ansible.cfgforks=20(默认5,根据主控端性能调整),执行时-f 20临时调整
Facts收集优化 关闭无需的Facts收集 减少主机信息收集耗时,加速剧本执行 剧本中gather_facts: no,配置文件gathering = explicit
本地YUM源 搭建本地YUM仓库,批量安装时优先使用 避免外网依赖,提升软件安装速度 被控端配置本地YUM源,剧本中yum模块正常使用
安全加固 配置sudo免密用户、关闭主机密钥检查 提升运维安全性,避免root直接登录 被控端/etc/sudoersans ALL=(ALL) NOPASSWD: ALL;主控端ansible.cfghost_key_checking = False
缓存优化 缓存Facts变量(如Redis) 重复执行剧本时无需重新收集Facts 配置文件启用Facts缓存,指定Redis地址

三、步骤/命令

3.1 Ansible Playbook剧本基础操作与实战案例

通用执行命令:⭐️ansible-playbook 剧本名.yml(使用默认主机清单);⭐️ansible-playbook -i 自定义主机清单 剧本名.yml(使用自定义主机清单)
效果验证:执行后会输出每个Play、Task的执行结果,最终通过PLAY RECAP汇总各主机执行状态(ok/changed/failed/unreachable)。

场景1:剧本基础语法示例(入门必学)

操作场景:编写基础剧本,实现多步骤简单命令执行,熟悉Playbook核心结构与YAML格式。

# 编写剧本:01.show.yml
- hosts: all  # 管理所有主机
  tasks:      # 任务列表
    - name: 01 打开冰箱门  # 任务名称,便于排查
      shell: echo 01 >> /tmp/bingxiang.log
    - name: 02 把大象放入冰箱
      shell: echo 02 >> /tmp/bingxiang.log
    - name: 03 关上冰箱的门
      shell: echo 03 >> /tmp/bingxiang.log
# 执行剧本
ansible-playbook 01.show.yml
# 效果验证:查看被控端文件
ansible all -a 'cat /tmp/bingxiang.log'

注释:执行后若出现奶牛图标,可修改/etc/ansible/ansible.cfg,将nocows = 1取消注释关闭。

场景2:创建目录并分发文件(基础运维操作)

操作场景:通过剧本实现批量创建目录+分发/etc/hosts文件,掌握file/copy模块在剧本中的两种书写格式。

# 编写剧本:02.dist_file.yml(专业键值对格式,推荐)
- hosts: all
  tasks:
    - name: 01 创建目录
      file:
        path: /server/files/
        state: directory
    - name: 02 分发文件
      copy:
        src: /etc/hosts
        dest: /server/files/
# 执行剧本
ansible-playbook 02.dist_file.yml
# 效果验证:检查目录和文件是否存在
ansible all -a 'ls -l /server/files/'

补充:模块也可使用单行简写格式(file: path=/server/files/ state=directory),适合简单操作,复杂操作推荐专业键值对格式。

场景3:分发并安装zabbix-agent(软件部署实战)

操作场景:通过剧本实现批量下载zabbix-agent包、安装、启动并设置开机自启,掌握get_url/yum/systemd模块的剧本组合使用。

# 编写剧本:03.install_zabbix-agent.yml
- hosts: centos  # 管理centos主机组
  tasks:
    - name: 01 下载zabbix-agent包到/tmp
      get_url:
        url: https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/6.0/rhel/7/x86_64/zabbix-agent-6.0.7-1.el7.x86_64.rpm
        validate_certs: no  # 关闭证书验证
        dest: /tmp/
    - name: 02 安装zabbix-agent包
      yum:
        name: /tmp/zabbix-agent-6.0.7-1.el7.x86_64.rpm
        state: present
    - name: 03 启动zabbix-agent并开机自启
      systemd:
        name: zabbix-agent
        enabled: yes
        state: started
# 执行剧本
ansible-playbook 03.install_zabbix-agent.yml
# 效果验证:检查服务状态
ansible centos -a 'systemctl status zabbix-agent'

场景4:部署NFS服务端+客户端(集群服务部署实战)

操作场景:通过单剧本实现NFS服务端(backup组)和客户端(web组)的全量部署,服务端共享/backup-nfs目录,客户端永久挂载至/ans-upload,掌握多Play剧本编写、lineinfile/mount模块的实战用法。

# 编写剧本:04.deploy_nfs.yml
# Play1:部署NFS服务端(backup组)
- hosts: backup
  tasks:
    - name: 01 安装nfs-utils和rpcbind
      yum:
        name: nfs-utils,rpcbind
        state: present
    - name: 02 修改NFS配置文件/etc/exports
      lineinfile:
        path: /etc/exports
        line: "/backup-nfs 172.16.1.0/24(rw,all_squash)"
        create: true  # 配置文件不存在则创建
    - name: 03 创建共享目录并修改属主为nfsnobody
      file:
        path: /backup-nfs
        owner: nfsnobody
        group: nfsnobody
        state: directory
    - name: 04 启动rpcbind并开机自启(先启动)
      systemd:
        name: rpcbind
        enabled: yes
        state: started
    - name: 05 启动nfs并开机自启(后启动)
      systemd:
        name: nfs
        enabled: yes
        state: started

# Play2:部署NFS客户端(web组)
- hosts: web
  tasks:
    - name: 01 安装nfs-utils客户端
      yum:
        name: nfs-utils
        state: present
    - name: 02 永久挂载NFS共享目录
      mount:
        src: 172.16.1.41:/backup-nfs
        path: /ans-upload
        fstype: nfs
        state: mounted  # 挂载并修改/etc/fstab
# 执行剧本
ansible-playbook 04.deploy_nfs.yml
# 效果验证:服务端检查共享,客户端检查挂载
ansible backup -a 'showmount -e'
ansible web -a 'df -h /ans-upload/'

3.2 Ansible各类变量的定义与使用

通用调试命令:⭐️debug: msg="{{ 变量名 }}"(输出单个变量);⭐️debug: msg="变量内容 {{ 变量1 }} {{ 变量2 }}"(输出多个变量)
核心前提:变量引用遵循{{ 变量名 }}规则,变量开头必加双引号

类型1:剧本内变量(vars)

操作场景:在剧本内直接定义变量,用于单剧本的可变参数管理,如统一定义目录路径。

# 编写剧本:05.vars_inside.yml
- hosts: all
  vars:  # 定义剧本内变量
    dir: /oldboy/lidao/upload/  # 变量名:dir,变量值:路径
  tasks:
    - name: 批量创建目录(引用变量)
      file:
        path: "{{ dir }}"  # 变量为开头,加双引号
        state: directory
# 执行剧本
ansible-playbook 05.vars_inside.yml
# 效果验证:检查目录是否创建
ansible all -a 'ls -ld /oldboy/lidao/upload/'

类型2:独立变量文件(vars_files)

操作场景:将变量单独写在独立YAML文件中,通过vars_files加载,适用于单剧本多变量的场景,便于统一管理。

# 1. 创建独立变量文件:vars.yml
cat > vars.yml << EOF
dir: /tmp/
user: lidao996
file: lidao.txt
EOF
# 2. 编写剧本:06.vars_file.yml(加载变量文件)
- hosts: all
  vars_files: ./vars.yml  # 加载当前目录的vars.yml
  tasks:
    - name: 批量创建文件(引用多个变量)
      file:
        path: "{{ dir }}/{{ user }}-{{ file }}"  # 组合变量
        state: touch
# 执行剧本
ansible-playbook 06.vars_file.yml
# 效果验证:检查文件是否创建
ansible all -a 'ls -l /tmp/lidao996-lidao.txt'

类型3:主机组变量(group_vars)高频使用

操作场景:按主机清单的分组创建变量目录和文件,实现多剧本共用变量,是标准化运维的核心方式,默认加载group_vars目录下的变量文件。

# 1. 创建group_vars目录及全机组变量文件(推荐使用all组,所有主机共用)
mkdir -p group_vars/all
cat > group_vars/all/vars.yml << EOF
user: www
nfs_dir: /nfs_backup
web_mount_dir: /web_nfs
nfs_server: 172.16.1.41
rsync_pass: 1
EOF
# 2. 编写剧本:07.group_vars.yml(测试组变量)
- hosts: all
  tasks:
    - name: 测试所有主机的组变量
      debug:
        msg: "全机组变量:{{ user }} {{ rsync_pass }} {{ nfs_server }}"
- hosts: web
  tasks:
    - name: 测试web组的组变量
      debug:
        msg: "web组识别的变量:{{ user }} {{ web_mount_dir }}"
# 执行剧本(自动加载group_vars目录下的变量)
ansible-playbook 07.group_vars.yml
# 效果验证:执行后直接输出变量内容,确认加载成功

注释:可按主机组创建子目录(如group_vars/web/group_vars/backup),实现不同主机组的专属变量。

类型4:Facts变量(内置主机信息)

操作场景:使用Ansible内置的Facts变量获取主机基础信息(IP、CPU、主机名、系统版本),通过template模块解析变量并修改系统文件/etc/motd,掌握templatecopy的核心区别。

# 1. 创建templates目录(template模块默认读取该目录)及模板文件:motd.j2
mkdir -p templates
cat > templates/motd.j2 << EOF
welcome to oldboy linux system
操作需谨慎,删根弹指间!
主机名:{{ ansible_hostname }}
IP地址:{{ ansible_default_ipv4.address }}
内存大小:{{ ansible_memtotal_mb }} MB
CPU数量:{{ ansible_processor_vcpus }}
发行版本:{{ ansible_distribution }}
EOF
# 2. 编写剧本:08.facts_vars.yml(分发模板文件)
- hosts: all
  # gather_facts: no  # 若不需要Facts变量,可关闭加速执行
  tasks:
    - name: 分发模板文件并解析变量(备份原文件)
      template:
        src: templates/motd.j2
        dest: /etc/motd
        backup: yes
# 执行剧本
ansible-playbook 08.facts_vars.yml
# 效果验证:远程登录被控端,直接查看motd输出
ssh [email protected]
# 手动获取Facts变量(调试用)
ansible all -m setup

类型5:Register注册变量(捕获命令输出)

操作场景:使用register捕获命令执行结果,实现Shell脚本的反引号/$(command) 功能,掌握从注册变量中提取有效输出(stdout)的方法。

# 编写剧本:09.register_vars.yml
- hosts: all
  tasks:
    - name: 执行date命令并捕获结果
      shell: date +%F
      register: result  # 将命令结果注册到变量result中
    - name: 输出注册变量的内容(调试)
      debug:
        msg: |  # | 表示多行输出
          命令执行的标准输出:{{ result.stdout }}
          命令执行的返回码:{{ result.rc }}
          命令执行的错误输出:{{ result.stderr }}
# 执行剧本
ansible-playbook 09.register_vars.yml
# 效果验证:执行后输出注册变量的各项内容,核心取result.stdout

核心说明:注册变量为JSON格式,核心有效字段:

  • stdout:命令标准输出(最常用);
  • rc:命令返回码(0为成功,非0为失败);
  • stderr:命令错误输出;
  • stdout_lines:按行分割的标准输出。

3.3 Ansible流程控制实操核心进阶

场景1:handlers触发器(NFS配置分发后重启服务)

操作场景:分发NFS配置文件/etc/exports仅当配置文件变化时重启NFS服务,无变化则不执行重启,掌握notifyhandlers的配合使用。

# 编写剧本:10.handlers_nfs.yml
- hosts: backup
  gather_facts: no
  tasks:
    - name: 01 分发NFS配置文件
      copy:
        src: files/exports
        dest: /etc/exports
        backup: yes
      notify: 重启NFS服务  # 触发handlers,名称需与handlers任务一致
  handlers:  # 写在剧本最后,特殊任务列表
    - name: 重启NFS服务  # 触发名称与notify一致
      systemd:
        name: nfs
        state: reloaded
# 首次执行(配置文件新增,触发重启)
ansible-playbook 10.handlers_nfs.yml
# 再次执行(配置文件无变化,不触发重启)
ansible-playbook 10.handlers_nfs.yml
# 效果验证:查看NFS服务状态
ansible backup -a 'systemctl status nfs'

场景2:when条件判断(按系统版本安装不同软件)

操作场景:为所有主机执行安装操作,CentOS系统安装sl、cowsay,Ubuntu系统安装cmatrix,结合Facts变量ansible_distribution实现条件判断。

# 编写剧本:11.when_sys.yml
- hosts: all
  tasks:
    - name: CentOS系统安装sl、cowsay
      yum:
        name: sl,cowsay
        state: installed
      when: ansible_distribution == "CentOS"  # 条件判断:系统为CentOS
    - name: Ubuntu系统安装cmatrix
      apt:
        name: cmatrix
        state: present
      when: ansible_distribution == "Ubuntu"  # 条件判断:系统为Ubuntu
# 执行剧本
ansible-playbook 11.when_sys.yml
# 效果验证:CentOS查看安装包,Ubuntu查看安装包
ansible centos -a 'rpm -qa sl cowsay'
ansible ubuntu -a 'dpkg -l cmatrix'

补充:多条件判断示例(CentOS且主机名为web/backup)

- name: CentOS+web/backup安装tree
  yum:
    name: tree
    state: present
  when:
    - ansible_distribution == "CentOS"
    - ansible_hostname is match("web|backup")  # 正则匹配主机名

场景3:loop循环(批量启动服务+批量创建用户)

操作场景1:批量重启NFS相关服务(rpcbind→nfs),使用单变量循环,掌握{{ item }}的基本使用。

# 编写剧本:12.loop_service.yml
- hosts: backup
  gather_facts: no
  tasks:
    - name: 批量重启rpcbind、nfs服务
      systemd:
        name: "{{ item }}"  # 引用循环变量
        state: restarted
      loop:  # 循环列表
        - rpcbind
        - nfs

操作场景2:批量创建用户(指定用户名+UID),使用键值对多变量循环,掌握复杂循环的写法。

# 编写剧本:13.loop_user.yml
- hosts: all
  gather_facts: no
  tasks:
    - name: 批量创建用户(指定UID)
      user:
        name: "{{ item.name }}"  # 引用键值对变量name
        uid: "{{ item.uid }}"    # 引用键值对变量uid
        state: present
      loop:  # 键值对循环列表
        - { name: 'oldboy', uid: 2020 }
        - { name: 'lidao', uid: 2021 }
        - { name: 'lidao996', uid: 2022 }
# 执行两个循环剧本
ansible-playbook 12.loop_service.yml
ansible-playbook 13.loop_user.yml
# 效果验证:检查服务状态、检查用户
ansible backup -a 'systemctl status rpcbind nfs'
ansible all -a 'id oldboy lidao lidao996'

3.4 Ansible剧本调试实操实战必备

NFS部署剧本为例,结合tag标签、语法检查、模拟运行、忽略错误实现全流程调试。

# 编写带tag标签的NFS部署剧本:14.deploy_nfs_tag.yml
- hosts: backup
  tasks:
    - name: 01 安装nfs-utils、rpcbind
      yum:
        name: nfs-utils,rpcbind
        state: present
      tags: 01.install  # 定义标签
    - name: 02 修改NFS配置文件
      lineinfile:
        path: /etc/exports
        line: "/backup-nfs 172.16.1.0/24(rw,all_squash)"
        create: true
      tags: 02.conf  # 定义标签
      notify: 重启NFS服务
    - name: 03 创建共享目录
      file:
        path: /backup-nfs
        owner: nfsnobody
        group: nfsnobody
        state: directory
      tags: 03.dir  # 定义标签
      ignore_errors: true  # 忽略目录已存在的错误
    - name: 04 批量启动服务
      systemd:
        name: "{{ item }}"
        enabled: yes
        state: started
      loop:
        - rpcbind
        - nfs
      tags: 04.start_srv  # 定义标签
  handlers:
    - name: 重启NFS服务
      systemd:
        name: nfs
        state: reloaded
# 1. 语法检查(核心第一步)
⭐️ansible-playbook --syntax-check 14.deploy_nfs_tag.yml
# 2. 模拟运行(预览结果,不修改被控端)
⭐️ansible-playbook -C 14.deploy_nfs_tag.yml
# 3. 仅执行指定标签的任务(仅启动服务)
⭐️ansible-playbook -t 04.start_srv 14.deploy_nfs_tag.yml
# 4. 跳过指定标签的任务(跳过安装)
ansible-playbook --skip-tags 01.install 14.deploy_nfs_tag.yml
# 5. 查看剧本所有标签
ansible-playbook --list-tags 14.deploy_nfs_tag.yml

3.5 Jinja2模板实操动态配置核心

场景1:Jinja2基本使用(分发带变量的motd文件)

已在3.2 类型4 Facts变量中实现,核心为template模块解析motd.j2中的Facts变量,此处不再赘述。

场景2:Jinja2条件判断(动态生成Keepalived配置)

操作场景:根据主机名动态生成Keepalived配置文件,web01为主节点(MASTER),backup为备节点(BACKUP),实现个性化配置分发。

# 1. 创建Jinja2模板文件:templates/keepalived.conf.j2
cat > templates/keepalived.conf.j2 << EOF
# Keepalived动态配置文件 - 由Jinja2生成
global_defs {
   router_id {{ ansible_hostname }}  # 引用主机名变量
}
vrrp_instance VI_1 {
{% if ansible_hostname == "web01" %}  # 条件判断:主机名为web01
    state MASTER  # 主节点
{% elif ansible_hostname == "backup" %}  # 条件判断:主机名为backup
    state BACKUP  # 备节点
{% endif %}  # 结束判断
    interface eth0
    virtual_router_id 51
}
EOF
# 2. 编写剧本:15.jinja2_if.yml
- hosts: all
  tasks:
    - name: 分发Keepalived动态配置文件
      template:
        src: templates/keepalived.conf.j2
        dest: /tmp/keepalived.conf
# 执行剧本
ansible-playbook 15.jinja2_if.yml
# 效果验证:查看web01和backup的配置文件差异
ansible web01 -a 'cat /tmp/keepalived.conf'
ansible backup -a 'cat /tmp/keepalived.conf'

场景3:Jinja2循环(批量生成IP列表配置)

操作场景:通过Jinja2的for循环,在/tmp/server.conf中批量生成10.0.0.2~10.0.0.10的IP列表,掌握数字范围、列表循环的写法。

# 1. 创建Jinja2模板文件:templates/server.conf.j2
cat > templates/server.conf.j2 << EOF
# 批量生成IP列表 - 数字范围循环(2-10)
{% for ip in range(2,11) %}
10.0.0.{{ ip }}
{% endfor %}

# 批量生成主机名 - 列表循环
{% for name in ["web01","web02","backup01","nfs01"] %}
{{ name }}
{% endfor %}
EOF
# 2. 编写剧本:16.jinja2_for.yml
- hosts: all
  tasks:
    - name: 分发批量IP列表配置文件
      template:
        src: templates/server.conf.j2
        dest: /tmp/server.conf
# 执行剧本
ansible-playbook 16.jinja2_for.yml
# 效果验证:查看生成的配置文件
ansible all -a 'cat /tmp/server.conf'

3.6 Ansible文件包含(include_tasks)实操

操作场景:将NFS部署剧本拆分为服务端子剧本、客户端子剧本,通过主剧本加载合并,实现剧本模块化拆分。

# 1. 创建子剧本:nfs_server_tasks.yml(服务端任务)
cat > nfs_server_tasks.yml << EOF
- name: 01 安装nfs-utils、rpcbind
  yum:
    name: nfs-utils,rpcbind
    state: present
- name: 02 修改NFS配置文件
  copy:
    src: files/exports
    dest: /etc/exports
    backup: yes
  notify: 重启NFS服务
- name: 03 创建共享目录
  file:
    path: /backup-nfs
    owner: nfsnobody
    group: nfsnobody
    state: directory
EOF

# 2. 创建子剧本:nfs_client_tasks.yml(客户端任务)
cat > nfs_client_tasks.yml << EOF
- name: 01 安装nfs-utils
  yum:
    name: nfs-utils
    state: present
- name: 02 永久挂载NFS
  mount:
    src: 172.16.1.41:/backup-nfs
    path: /ans-upload
    fstype: nfs
    state: mounted
EOF

# 3. 创建主剧本:nfs_main.yml(加载子剧本)
cat > nfs_main.yml << EOF
- hosts: backup
  tasks:
    - include_tasks: nfs_server_tasks.yml  # 加载服务端子剧本
  handlers:
    - name: 重启NFS服务
      systemd:
        name: nfs
        state: reloaded

- hosts: web
  tasks:
    - include_tasks: nfs_client_tasks.yml  # 加载客户端子剧本
EOF
# 执行主剧本
ansible-playbook nfs_main.yml
# 效果验证:检查服务端共享和客户端挂载
ansible backup -a 'showmount -e'
ansible web -a 'df -h /ans-upload/'

3.7 Ansible Roles实操(NFS服务端部署)高频实战

场景1:创建Roles目录结构与核心文件

# 1. 创建Roles项目目录结构
mkdir -p /server/ansible/roles-project/{group_vars/all,nfs-server/{files,templates,tasks,handlers},roles}
cd /server/ansible/roles-project

# 2. 创建主机清单文件:hosts
cat > hosts << EOF
[backup]
172.16.1.41
[web]
172.16.1.7
EOF

# 3. 创建group_vars全局变量文件:group_vars/all/main.yml
cat > group_vars/all/main.yml << EOF
nfs_share_dir: /backup-nfs-v3  # NFS共享目录
nfs_user: nfsnobody            # 共享目录属主
nfs_user_id: 65534             # 匿名用户UID/GID
nfs_network: 172.16.1.0/24     # 允许访问的网段
EOF

# 4. 创建nfs-server Role的files目录静态文件:nfs-server/files/exports(备用,后续用模板替代)
cat > nfs-server/files/exports << EOF
/backup-nfs 172.16.1.0/24(rw,all_squash)
EOF

# 5. 创建nfs-server Role的templates目录模板文件:nfs-server/templates/exports.j2(动态配置)
cat > nfs-server/templates/exports.j2 << EOF
{{ nfs_share_dir }} {{ nfs_network }}(rw,all_squash,anonuid={{ nfs_user_id }},anongid={{ nfs_user_id }})
EOF

# 6. 创建nfs-server Role的tasks任务文件:nfs-server/tasks/main.yml(核心入口)
cat > nfs-server/tasks/main.yml << EOF
- name: 01 安装nfs-utils和rpcbind
  yum:
    name: nfs-utils,rpcbind
    state: installed
  tags: 01-install-nfs

- name: 02 分发NFS动态配置文件(模板)
  template:
    src: exports.j2
    dest: /etc/exports
    backup: yes
  tags: 02-conf
  notify: restart nfs server

- name: 03 创建NFS共享目录
  file:
    path: "{{ nfs_share_dir }}"
    owner: "{{ nfs_user }}"
    group: "{{ nfs_user }}"
    state: directory
  tags: 03-mkdir

- name: 04 批量启动rpcbind和nfs服务
  systemd:
    name: "{{ item }}"
    enabled: yes
    state: started
  loop:
    - rpcbind
    - nfs
  tags: 04-start-service

- name: 05 分发motd模板文件(示例)
  template:
    src: motd.j2
    dest: /etc/motd
    backup: yes
  tags: 05-motd
EOF

# 7. 创建nfs-server Role的handlers触发器文件:nfs-server/handlers/main.yml
cat > nfs-server/handlers/main.yml << EOF
- name: restart nfs server
  systemd:
    name: nfs
    state: reloaded
EOF

# 8. 创建Roles入口剧本:top.yml(加载nfs-server Role)
cat > top.yml << EOF
- hosts: backup
  roles:
    - role: nfs-server  # 加载nfs-server Role
EOF

场景2:执行Roles并验证

# 1. 语法检查
ansible-playbook -i hosts --syntax-check top.yml

# 2. 执行Roles剧本(指定主机清单和入口剧本)
ansible-playbook -i hosts top.yml

# 3. 仅执行指定tag的任务(如仅启动服务)
ansible-playbook -i hosts -t 04-start-service top.yml

# 4. 效果验证
# 检查NFS配置文件(是否为动态变量生成)
ansible backup -a 'cat /etc/exports'
# 检查共享目录
ansible backup -a 'ls -ld {{ nfs_share_dir }}'
# 检查服务状态
ansible backup -a 'systemctl status rpcbind nfs'
# 检查共享
ansible backup -a 'showmount -e'

3.8 Ansible Vault实操(敏感信息加密)

场景1:加密变量文件

# 1. 创建包含敏感信息的变量文件:secrets.yml
cat > secrets.yml << EOF
db_password: "Oldboy@123"
ssh_port: 2222
root_password: "Admin@456"
EOF

# 2. 加密该文件(设置加密密码,需牢记)
⭐️ansible-vault encrypt secrets.yml
# 执行后提示输入加密密码,确认密码,文件变为加密状态

# 3. 查看加密文件内容(无需解密)
ansible-vault view secrets.yml
# 输入加密密码后即可查看明文

# 4. 编辑加密文件
ansible-vault edit secrets.yml
# 输入密码后进入编辑模式,保存后自动重新加密

# 5. 解密文件(彻底解密,谨慎使用)
ansible-vault decrypt secrets.yml
# 输入密码后文件恢复为明文

场景2:执行包含加密文件的剧本

# 1. 创建剧本:use_secrets.yml(加载加密变量文件)
cat > use_secrets.yml << EOF
- hosts: all
  vars_files: ./secrets.yml  # 加载加密的变量文件
  tasks:
    - name: 输出敏感变量(调试用)
      debug:
        msg: "数据库密码:{{ db_password }}, SSH端口:{{ ssh_port }}"
EOF

# 2. 执行剧本(需提供Vault密码)
# 方式1:交互式输入密码
⭐️ansible-playbook --ask-vault-pass use_secrets.yml

# 方式2:通过密码文件提供密码(推荐生产环境)
# 先创建密码文件(权限600)
echo "MyVaultPass123" > vault_pass.txt
chmod 600 vault_pass.txt
# 执行剧本
ansible-playbook --vault-password-file vault_pass.txt use_secrets.yml

3.9 Ansible Galaxy实操(安装第三方Roles)

# 1. 搜索Nginx相关Roles
ansible-galaxy search nginx

# 2. 安装Nginx官方Role(nginxinc.nginx_core)
⭐️ansible-galaxy collection install nginxinc.nginx_core

# 3. 列出已安装的Roles/Collections
ansible-galaxy collection list

# 4. 使用安装的Role(参考官方文档编写剧本)
cat > install_nginx.yml << EOF
- hosts: web
  collections:
    - nginxinc.nginx_core
  tasks:
    - name: Install Nginx
      nginx_core.nginx:
        state: present
EOF

# 5. 执行剧本安装Nginx
ansible-playbook install_nginx.yml

3.10 Ansible优化实操

场景1:性能优化(SSH连接+并发数)

# 1. 优化被控端SSH配置(加速连接)
ansible all -m lineinfile -a 'path=/etc/ssh/sshd_config line="UseDNS no" state=present'
ansible all -m lineinfile -a 'path=/etc/ssh/sshd_config line="GSSAPIAuthentication no" state=present'
ansible all -m systemd -a 'name=sshd state=reloaded'

# 2. 调整Ansible并发数(临时调整)
ansible-playbook -f 20 nfs_main.yml  # -f指定并发数为20(默认5)

# 3. 永久调整并发数(修改配置文件)
sed -i 's/^#forks = 5/forks = 20/' /etc/ansible/ansible.cfg

# 4. 关闭Facts收集(加速剧本执行)
# 在剧本中添加gather_facts: no
cat > fast_playbook.yml << EOF
- hosts: all
  gather_facts: no  # 关闭Facts收集
  tasks:
    - name: 批量创建目录
      file:
        path: /tmp/optimize
        state: directory
EOF

场景2:安全优化(sudo免密用户)

# 1. 主控端创建普通用户ans,并配置密钥认证
useradd ans
echo "ans:123456" | chpasswd
ssh-keygen -t rsa -f /home/ans/.ssh/id_rsa -P ''
chown -R ans:ans /home/ans/.ssh/

# 2. 批量在被控端创建ans用户,并配置sudo免密
ansible all -m user -a 'name=ans password={{ "123456" | password_hash("sha512", "salt") }} state=present'
ansible all -m lineinfile -a 'path=/etc/sudoers line="ans ALL=(ALL) NOPASSWD: ALL" state=present'

# 3. 主控端ans用户分发密钥到被控端
su - ans
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

# 4. 修改主控端Ansible配置文件(使用ans用户登录)
cat >> /etc/ansible/ansible.cfg << EOF
[defaults]
remote_user = ans  # 被控端登录用户
remote_port = 22
host_key_checking = False
log_path = /var/log/ansible.log

[privilege_escalation]
become = True  # 开启sudo
become_method = sudo  # 使用sudo
become_user = root  # 切换为root
EOF

# 5. 测试(无需root用户,通过ans用户sudo执行)
ansible all -m command -a 'whoami'  # 输出root

四、原理说明

4.1 Ansible Playbook执行原理

Playbook是Ansible将多个Ad-hoc操作按业务流程封装后的YAML文件,其底层执行仍基于SSH协议,核心执行流程为:

  1. 加载配置与主机清单:Ansible读取ansible.cfg配置文件,加载指定的主机清单,解析Playbook中的hosts字段,确定待管理的主机/主机组;
  2. 收集Facts信息(默认):执行内置的setup模块,收集待管理主机的基础信息(生成Facts变量),并将信息缓存至主控端;
  3. 解析Play与Task:按Playbook中的顺序解析每个Play,再按从上到下的顺序解析Play中的每个Task,将每个Task转换为对应的模块调用指令;
  4. 批量执行模块:通过SSH连接插件与被控端建立连接,将模块指令发送至被控端临时目录,依次执行每个Task的模块指令,若任务状态为changed则记录触发的handlers
  5. 执行触发器任务:当前Play的所有普通任务执行完成后,若有已记录的handlers,则按顺序执行触发器任务;
  6. 结果收集与反馈:实时收集每个被控端的模块执行结果(成功/失败/改变/跳过),执行完成后按Play主机进行汇总,通过PLAY RECAP输出最终执行状态。

补充Roles执行逻辑:

  • 若Play中包含roles,Ansible会先加载Role的tasks/main.yml,按顺序执行所有任务;任务执行过程中若触发notify,则记录对应的触发器;
  • 所有Role任务执行完成后,执行Role的handlers/main.yml中的触发器任务;
  • Role中的files/templates/目录由对应模块自动识别,无需指定路径,仅需填写文件名即可。

4.2 Ansible变量生效与加载原理

Ansible变量采用按场景加载、按优先级覆盖的生效规则,底层通过变量解析引擎实现引用替换,核心原理为:

  1. 变量加载顺序:按「内置Facts变量→主机清单变量→组变量group_vars→变量文件vars_files→剧本内vars→命令行变量」的顺序加载,后加载的变量会覆盖先加载的同名变量
  2. 变量引用解析:剧本执行时,解析引擎会扫描所有{{ 变量名 }}的内容,从已加载的变量池中匹配对应的变量值,完成替换后再执行模块指令;若变量为选项开头,需加双引号避免YAML格式解析错误;
  3. 特殊变量生效
    • Facts变量:由setup模块收集主机信息后动态生成,与对应主机绑定,仅对该主机生效;
    • Register变量:执行命令模块后,将命令的执行结果(返回码、输出、错误)封装为JSON格式存入指定变量,仅在当前Play中生效;
    • 组变量:Ansible会自动扫描当前执行目录下的group_vars目录,按主机组名匹配加载对应的变量文件,all组的变量对所有主机生效。

补充Roles变量优先级:

  • Roles变量的加载顺序:group_vars/allRole的vars/main.ymlRole的defaults/main.yml后加载的变量覆盖先加载的同名变量
  • 命令行传入的变量优先级最高,可覆盖所有Role和全局变量。

4.3 Ansible流程控制执行原理

Ansible流程控制基于任务执行状态条件解析引擎实现,底层与Playbook执行流程深度融合,核心原理为:

  1. handlers触发器原理handlers是特殊的任务列表,默认不执行,仅当普通任务中notify指定的名称与handlers任务名一致,且普通任务的执行状态为changed 时,才会在当前Play的所有普通任务执行完成后触发;若任务状态为ok(无变化),则不会触发。
  2. when条件判断原理:Ansible通过条件解析引擎解析when后的逻辑语句,先从变量池中获取语句中的变量值,再执行逻辑判断(等于/匹配/与/或);判断结果为True则执行当前任务,结果为False则跳过任务,标记为skipped
  3. loop循环执行原理:Ansible将loop后的列表/键值对视为迭代数据源,对当前任务进行批量复制,每次迭代将item变量替换为数据源中的一个值,依次执行迭代后的任务;loopwith_items底层迭代引擎一致,loop为官方推荐的新一代语法。

4.4 Jinja2模板解析原理

Jinja2模板是Ansible实现动态配置的核心,其解析过程分为模板渲染文件分发两步,底层基于Jinja2引擎与Ansible变量池联动,核心原理为:

  1. 模板加载template模块读取指定路径的.j2模板文件,加载至主控端的内存中;
  2. 变量与逻辑解析:Jinja2引擎扫描模板中的{{ 变量 }}{% 逻辑 %}标签,从Ansible的变量池中获取变量值,执行条件判断/循环迭代等逻辑,生成无模板标签的纯文本文件(该过程称为渲染);
  3. 文件分发:将渲染后的纯文本文件通过SSH协议分发至被控端的指定路径,完成动态配置文件的部署;
  4. 核心特性:模板渲染过程在主控端完成,仅将最终的纯文本文件发送至被控端,减少被控端的资源消耗。

4.5 Ansible Roles执行原理

Roles的核心是目录规范驱动的自动化加载,底层执行逻辑与Playbook一致,但增加了目录解析步骤:

  1. 入口剧本top.yml指定hostsrole后,Ansible先定位Role目录(如nfs-server/);
  2. 自动读取tasks/main.yml,按顺序解析每个任务,转换为模块调用指令;
  3. 任务中使用copy模块时,自动从files/目录查找文件;使用template模块时,自动从templates/目录查找.j2文件;
  4. 任务执行过程中若触发notify,则从handlers/main.yml中匹配对应的触发器任务,待所有任务执行完成后执行;
  5. 变量从group_vars/Role的vars/等位置加载,按优先级替换任务和模板中的{{ 变量名 }}

4.6 Ansible Vault加密原理

Vault基于对称加密算法实现,核心原理为:

  1. 加密时,用户输入的密码作为密钥,通过AES算法对文件内容进行加密,加密后的文件仅包含密文和加密元数据(无明文信息);
  2. 解密/执行时,用户提供的密码被用于生成密钥,对密文进行解密,解密过程在内存中完成,不写入磁盘,避免敏感信息泄露;
  3. 加密文件的扩展名不变,但文件头部会添加$ANSIBLE_VAULT;1.1;AES256标识,Ansible通过该标识识别加密文件。

4.7 Ansible优化原理

  1. SSH连接优化:关闭UseDNS可避免SSH连接时的DNS反向解析耗时,关闭GSSAPIAuthentication可禁用Kerberos认证,减少连接握手步骤;
  2. 并发数优化forks参数控制Ansible同时与多少个被控端建立连接,默认5个,调整为20-50(根据主控端CPU/内存性能)可大幅提升大规模集群的执行效率;
  3. Facts收集优化:Facts收集需执行setup模块,获取主机CPU、内存、网络等信息,关闭后可减少一次SSH连接和模块执行的耗时;
  4. 安全优化:配置sudo免密用户可避免root用户直接暴露,关闭host_key_checking可避免首次连接时的交互确认,提升自动化程度。

五、注意事项

5.1 Playbook剧本编写注意事项

  1. 剧本文件必须以.yml/.yaml为后缀,Ansible仅识别该格式的Playbook文件;
  2. YAML格式对空格缩进严格敏感,同一层级必须左对齐,不同层级用2个空格缩进,绝对禁止使用Tab键,否则会直接执行失败;
  3. 编写多步骤服务部署剧本时,需严格遵循服务启动顺序(如NFS需先启动rpcbind,再启动nfs),否则会导致服务部署失败;
  4. 剧本中每个Task建议添加有意义的name,便于执行失败后快速定位问题节点;
  5. 执行服务部署剧本前,建议对被控端拍摄快照,分步测试每个Task,测试通过后再整体执行,避免批量部署故障;
  6. 使用get_url模块下载外网文件时,若目标站点无有效证书,需添加validate_certs: no关闭证书验证,否则下载失败;
  7. handlers触发器需写在剧本最后,若写在tasks中间,会导致后续普通任务被识别为触发器任务,无法正常执行。

5.2 Ansible变量使用注意事项

  1. 变量引用必须使用{{ 变量名 }},若变量为模块选项的开头字符,必须加双引号,非开头可省略引号;
  2. 组变量建议统一放在group_vars/all目录下,实现所有剧本、所有主机的变量共用,减少重复定义;
  3. 若剧本中不需要使用Facts变量,需在Play中添加gather_facts: no,关闭主机信息收集,大幅提升剧本执行速度
  4. template模块仅能解析.j2后缀的模板文件,且默认读取当前执行目录下的templates目录,需按规范创建目录和文件;
  5. Register注册变量仅能捕获命令类模块(shell/command/script)的执行结果,无法捕获文件/服务类模块的结果;
  6. 多剧本共用变量时,优先使用组变量而非独立变量文件,避免变量文件分散,提升可维护性。

5.3 通用运维注意事项

  1. 剧本中执行删除/修改系统配置的操作时,需添加backup: yes参数(支持的模块),对原文件进行备份,便于故障回滚;
  2. 批量部署软件时,优先使用本地下载包+yum本地安装,避免被控端因网络问题导致下载失败;
  3. 剧本执行完成后,通过ansible <主机组> -a <验证命令>批量验证执行结果,确保所有被控端操作一致;
  4. 标准化运维中,建议将Playbook、变量文件、模板文件按目录规范管理(如playbook//group_vars//templates//files/),便于团队协作;
  5. Ubuntu系统默认禁用root远程登录,若需管理Ubuntu主机,需先修改/etc/ssh/sshd_config,设置PermitRootLogin yes,并重启sshd服务、设置root密码。

5.4 流程控制使用注意事项

  1. handlersnotify名称与handlers任务名必须完全一致(大小写敏感),否则无法触发;且一个任务可通过notify触发多个handlers任务,用逗号分隔即可;
  2. when条件判断中,使用正则匹配时需用is match("正则表达式"),取反用is not match,匹配多个值用|分隔;
  3. when多条件判断时,每个条件需单独一行并以-开头,默认是and关系;or关系需写在同一行;
  4. loop循环中,键值对变量的键名必须与模块参数一致(如item.name对应user模块的name参数),否则会提示变量未定义;
  5. 避免在loop中执行高风险操作(如state=absent删除目录),防止批量误操作;
  6. with_items为旧版循环语法,官方推荐使用loop,二者功能一致,可相互替换。

5.5 剧本调试与Jinja2模板注意事项

剧本调试

  1. 语法检查是剧本执行的核心第一步,所有剧本在实际执行前必须先做语法检查,排除基础语法错误;
  2. tag标签建议按任务步骤/功能命名(如01.install/02.conf),便于识别和调用;
  3. ignore_errors: true仅适用于重复执行导致的非致命错误(如目录已存在、用户已创建),不可全局使用,否则会掩盖真实的执行错误;
  4. 模拟运行(-C)无法解决所有问题,部分依赖任务执行结果的变量会报错,需结合单步执行调试。

Jinja2模板

  1. Jinja2的逻辑标签{% %})必须成对出现(如{% if %}对应{% endif %}{% for %}对应{% endfor %}),缺少结束标签会导致模板渲染失败;
  2. 模板中的变量引用与Ansible剧本中的变量引用规则一致,若变量为路径/端口等开头,需注意引号使用;
  3. 避免在模板中书写过于复杂的逻辑(如多层嵌套if/for),否则会降低剧本的可维护性,复杂逻辑建议在剧本中用when实现;
  4. 模板中的注释建议使用{# 注释 #},而非文件原生注释,避免渲染后的文件出现无用注释,影响服务配置;
  5. copytemplate模块不可混用,若文件中包含Jinja2标签,必须使用template模块,否则会将标签直接写入文件,导致服务配置错误。

5.6 文件包含(include_tasks)注意事项

  1. 子剧本仅需包含tasks列表,无需hostsvars等Play级配置,避免与主剧本冲突;
  2. 子剧本的路径需正确,主剧本与子剧本在同一目录时直接写文件名,否则需写绝对路径或相对路径;
  3. 多个子剧本加载时,变量作用域贯通,主剧本的变量可在子剧本中直接使用,子剧本间也可共享变量;
  4. 子剧本中若触发handlers,触发器需定义在主剧本中,子剧本无法单独定义handlers

5.7 Ansible Roles注意事项高频重点

  1. Role目录结构必须严格遵循规范,tasks/main.ymlhandlers/main.yml必填文件,其他目录可选;
  2. files/目录存放静态文件,templates/存放.j2模板文件,不可混淆使用,否则模块无法找到文件;
  3. Role名称建议体现功能(如nfs-serverrsync-client),目录命名统一,便于团队识别;
  4. 变量优先使用group_vars/all定义,实现多Role共用,Role专属变量放在vars/main.yml中,避免变量冲突;
  5. 编写Role时建议分步测试,先测试单个任务,再整体执行,避免批量部署故障;
  6. Role可通过版本控制工具(如Git)管理,实现版本迭代和团队共享。

5.8 Ansible Vault注意事项

  1. 加密密码必须牢记,丢失后无法恢复加密文件的内容,建议记录在安全的密码管理工具中;
  2. 生产环境中建议使用密码文件--vault-password-file)提供密码,避免交互式输入,适配自动化执行(如定时任务);
  3. 密码文件需设置600权限chmod 600 vault_pass.txt),仅允许当前用户读取,避免密码泄露;
  4. 仅加密必要的敏感信息(如密码、密钥),无需加密所有文件,避免增加执行复杂度;
  5. 加密后的文件不可直接编辑,必须通过ansible-vault edit编辑,否则会破坏加密结构。

5.9 Ansible Galaxy注意事项

  1. 安装第三方Role前,建议通过ansible-galaxy search查看Role的评分和下载量,优先选择官方或高评分Role;
  2. 第三方Role的使用需参考其官方文档,不同Role的参数和目录结构可能不同,避免盲目使用;
  3. 安装的Role默认存储在~/.ansible/collections/目录下,可通过ANSIBLE_COLLECTIONS_PATH环境变量指定自定义存储路径;
  4. 若第三方Role不符合需求,可基于其二次开发,或在本地创建同名Role覆盖(本地Role优先级高于第三方Role)。

5.10 Ansible优化注意事项

  1. 并发数(forks)不可设置过大,需根据主控端性能调整,否则会导致主控端CPU/内存占用过高,影响执行稳定性;
  2. 关闭Facts收集前需确认剧本中未使用任何Facts变量(如ansible_hostnameansible_default_ipv4.address),否则会提示变量未定义;
  3. 搭建本地YUM源时,需确保所有被控端能访问该源,且源中的软件包版本与被控端系统匹配;
  4. 安全优化中,sudo免密用户仅授权必要的命令,避免授予ALL=(ALL) NOPASSWD: ALL权限(生产环境根据需求最小化授权);
  5. 调整SSH端口后,需在Ansible配置文件中指定remote_port,否则会连接失败。

六、结尾

总结

本文核心覆盖Ansible自动化运维的十大核心模块,构建了从基础到高阶、从功能到安全的完整知识体系,是Ansible学习与实战的终极指南:

  1. Playbook剧本:掌握YAML规范、多Play编写,实现自动化部署的基础;
  2. Ansible变量:精通多场景变量定义与引用,提升剧本通用性;
  3. 流程控制:通过handlers/when/loop实现灵活执行逻辑,适配复杂场景;
  4. 剧本调试:掌握语法检查、tag标签等技巧,快速解决执行问题;
  5. Jinja2模板:实现动态配置文件生成,适配个性化部署;
  6. 文件包含:拆分大型剧本,提升可维护性;
  7. Roles模块化:标准化目录结构,实现剧本的高度复用与团队协作,是企业级运维的核心;
  8. Vault加密:保护敏感信息,提升运维安全性;
  9. Galaxy共享:复用第三方Role,减少重复开发;
  10. 性能与安全优化:适配大规模集群与高安全需求,提升运维效率与稳定性。

这十大模块贯穿Ansible自动化运维的全流程,从简单的批量命令执行到复杂的集群服务部署,从单人运维到团队协作,从功能实现到安全合规,均可通过Ansible高效完成,是运维工程师从初级晋升到中级、高级的必备核心技能。

避坑指南(坑点+解决方案)

基础剧本与变量类

  1. 坑点:Playbook执行提示YAML syntax error语法错误;解决方案:① 检查是否使用Tab键缩进,替换为2个空格;② 检查键: 值冒号后是否加空格;③ 用ansible-playbook --syntax-check 剧本.yml做语法检查。
  2. 坑点:变量引用后执行失败,提示undefined variable解决方案:① 检查变量名是否拼写错误;② 检查变量是否在当前Play的生效范围内;③ 组变量确认group_vars目录与剧本同目录。

流程控制与模板类

  1. 坑点handlers触发器不执行;解决方案:① 检查notify名称与handlers任务名是否完全一致;② 检查触发任务的执行状态是否为changed;③ 确认handlers写在剧本最后。
  2. 坑点:Jinja2模板渲染失败,提示template error解决方案:① 检查逻辑标签是否成对出现;② 确认模板文件后缀为.j2;③ 检查变量引用格式是否正确。

Roles与文件包含类

  1. 坑点:Roles执行提示“文件找不到”;解决方案:① 检查文件是否放在对应目录(静态文件→files/,模板→templates/);② 确认文件名称与剧本中引用的名称一致(大小写敏感);③ 检查Role目录结构是否符合规范。
  2. 坑点:include_tasks加载子剧本失败;解决方案:① 检查子剧本路径是否正确;② 子剧本仅包含tasks列表,无hosts等Play级配置;③ 主剧本与子剧本的变量是否贯通。

Vault与Galaxy类

  1. 坑点:Vault加密后剧本执行失败,提示“需要Vault密码”;解决方案:① 执行时添加--ask-vault-pass--vault-password-file参数;② 确认密码文件权限为600;③ 确认密码输入正确。
  2. 坑点:第三方Role安装后无法使用;解决方案:① 检查Role名称是否正确(区分大小写);② 参考Role官方文档编写剧本参数;③ 确认Role存储路径在Ansible的搜索路径中。

优化与安全类

  1. 坑点:调整并发数后执行卡顿;解决方案:① 降低forks参数(如从50调整为20);② 检查主控端CPU/内存占用,避免资源耗尽;③ 分批执行大规模集群(按主机组拆分)。
  2. 坑点:sudo免密用户执行剧本提示“权限不足”;解决方案:① 检查被控端sudoers配置是否正确(ans ALL=(ALL) NOPASSWD: ALL);② 主控端Ansible配置文件开启become: True;③ 测试su - ans -c "sudo whoami"是否能切换为root。
  3. 坑点:关闭Facts后剧本提示“变量未定义”;解决方案:① 重新开启gather_facts: yes;② 手动定义缺失的变量(如在group_vars中定义ansible_hostname);③ 替换Facts变量为固定值(适用于简单场景)。
posted @ 2026-03-13 23:43  gzjwo  阅读(3)  评论(0)    收藏  举报