当前位置: 首页 > news >正文

3.Ansible编写和运行playbook

3.Ansible编写和运行 Playbook

Playbook 介绍

如果把 Ansible 的ad-hoc命令比作 “一次性脚本”(适合临时执行单个简单任务),那么Playbook就是 “可重复执行的程序”(适合复杂、多步骤的管理流程)。

举个例子:

  • 用 ad-hoc 创建一个用户可以这样写(临时执行一次):

    # 在node1上创建用户newbie,UID为4000
    [bq@controller web]$ ansible -m user -a "name=newbie uid=4000 state=present" node1
    
  • 但如果需要在多台主机上重复这个操作,或者后续还要修改用户属性,用 Playbook 更合适。把上述操作写成 Playbook(保存为create_user.yml):

    ---
    - name: 统一配置用户(描述这个Play的作用)hosts: node1  # 目标主机(从清单中选)tasks:- name: 确保newbie用户存在且UID为4000(描述这个任务的作用)user:  # 使用user模块name: newbie  # 用户名uid: 4000     # UIDstate: present  # 状态:存在(present)或删除(absent)
    ...
    

Playbook 本质是一个YAML格式的文本文件(通常以.yaml.yml为扩展名),核心作用是:

  1. 按顺序定义多个Play(每个 Play 是一组针对特定主机的操作);
  2. 每个 Play 包含多个任务(按顺序执行的具体操作,如安装软件、修改配置等);
  3. 可重复执行,结果可预测(第二次执行相同 Playbook 时,未变更的任务会显示 “OK”)。

Vim 编辑器设置

用 Vim 编辑 Playbook 时,建议配置自动缩进和 Tab 转换,避免格式错误。

在用户家目录的.vimrc文件中添加配置:

# 方法1:全局生效(所有文件都用2个空格缩进,显示行号)
set ai ts=2 number# 方法2:仅YAML文件生效(更推荐)
autocmd FileType yaml set ai ts=2  # 打开YAML文件时,自动启用2个空格缩进

配置说明:

  • ai:自动缩进(新行继承上一行的缩进);
  • ts=2:Tab 键自动转换为 2 个空格;
  • number:显示行号(方便定位错误)。

YAML 格式基础

基本格式:

---  # YAML 文件起始标识(建议添加)
- name: 第一个Play(描述该Play的作用,如"部署Web服务")hosts: web_servers  # 目标主机/主机组(来自inventory)remote_user: devops  # 远程执行用户become: yes  # 是否提权(yes/no)become_method: sudo  # 提权方式(默认sudo)become_user: root  # 提权后的目标用户(通常为root)vars:  # 定义变量(可在任务中引用)app_name: "myapp"app_port: 8080tasks:  # 任务列表(按顺序执行)- name: 任务1描述(如"安装依赖包")yum:  # 模块名称(根据操作选择,如yum/apt/copy等)name: "{{ item }}"  # 引用变量或列表项state: presentloop:  # 循环执行(可选)- package1- package2- name: 任务2描述(如"复制配置文件")copy:src: ./local_config.conf  # 本地文件路径dest: /etc/remote_config.conf  # 目标路径mode: '0644'  # 文件权限notify:  # 触发处理器(配置变更时执行,可选)- 重启服务handlers:  # 处理器(仅在被notify触发时执行)- name: 重启服务systemd:name: "{{ app_name }}"state: restarted- name: 第二个Play(可定义多个Play,按顺序执行)hosts: db_serverstasks:- name: 数据库相关任务# 具体模块和参数...

核心结构说明

  1. Play 定义:每个 - name: ... 开头的块是一个 Play,包含对特定主机的操作
  2. 主机与用户配置hosts 指定目标,remote_userbecome 控制执行权限
  3. 变量(vars):集中定义可复用的值,通过 {{ 变量名 }} 引用
  4. 任务(tasks):具体操作列表,每个任务包含 name(描述)、模块和参数
  5. 处理器(handlers):用于响应任务通知的操作(如配置变更后重启服务)

编写时需注意

  • 严格使用空格缩进(推荐 2 个空格),同一层级缩进必须一致

  • 注释用##后面的内容会被忽略,建议多写注释提高可读性)

  • 模块参数需符合对应模块的语法要求(可通过 ansible-doc 模块名 查看文档)

  • 可通过 ansible-playbook --syntax-check 剧本名.yml 检查语法正确性

  • 冒号右侧(key: value):大部分可修改,少数不可,右侧是 “值”,用于填充具体内容、配置或引用,能否修改取决于其是否为固定枚举值。

      1. 可修改:动态值或自定义内容

      大部分情况下,右侧是用户根据需求设置的具体值,可自由修改:

      • 字符串 / 路径:如 hosts: node1 中,node1 可改为其他主机名(如 node2all);home: /home/joe 中,/home/joe 可改为 /home/bob
      • 变量引用:如 name: "{{ user }}" 中,{{ user }} 会动态引用变量值,变量值修改后这里也会同步变化。
      • 文本内容:如 debug 模块的 msg 内容,username is {{ user }} 可改为任意文本(如 用户名为 {{ user }})。
      1. 不可修改:固定枚举值

      部分模块参数的右侧值是 Ansible 规定的枚举值(只能从指定选项中选择),不可随意修改,否则会报错。
      例如:

      • user 模块的 state 参数:只能是 present(创建)或 absent(删除),不能改为 createdelete
      • service 模块的 state 参数:只能是 startedstoppedrestarted 等,不可自定义其他值。
  • 冒号(:)左侧的内容固定的关键字不可修改,有些是自定义名称(可修改)**。具体区分如下:

    • 不可修改:固定关键字

      这些是 Ansible 或 YAML 语法规定的固定 “键”,必须严格按原样书写,修改后会导致语法错误或功能失效。
      例如:

      • Playbook 结构关键字:name(定义任务 / 剧本名称)、hosts(指定目标主机)、vars(定义变量)、tasks(定义任务列表)等。
        例:hosts: node1 中,hosts 不可修改,修改为 host_list: node1 会报错。

      • 模块名:如 user:(用户管理模块)、debug:(调试模块),是 Ansible 内置模块的唯一标识,不可修改。
        例:user: name: joe 中,user 不可修改,改为 add_user: name: joe 会提示 “模块不存在”。

      • 模块参数:模块内置的配置项,如 user 模块的 name(用户名)、home(家目录)、state(状态);debug 模块的 msg(输出信息)等。
        例:name: "{{ user }}" 中,name 不可修改,是 user 模块规定的参数名,改为 username: "{{ user }}" 会导致参数无效。

      • 可修改:自定义标识 / 变量名

        如果左侧是用户自定义的变量名、标签或标识符,则可以修改,只要符合 YAML 命名规范(字母、数字、下划线,不建议用特殊字符)。
        例如:

        • 自定义变量名:vars 下的变量,如 user: joe 中,user 是自定义变量名,可改为 username: joe(后续引用需同步改为 {{ username }})。
        • 自定义标签:如果使用 tags 关键字,标签名可自定义,如 tags: create_user 中,create_user 可修改为 add_user 等。
      2. 可修改:自定义标识 / 变量名

      如果左侧是用户自定义的变量名、标签或标识符,则可以修改,只要符合 YAML 命名规范(字母、数字、下划线,不建议用特殊字符)。
      例如:

      • 自定义变量名:vars 下的变量,如 user: joe 中,user 是自定义变量名,可改为 username: joe(后续引用需同步改为 {{ username }})。
      • 自定义标签:如果使用 tags 关键字,标签名可自定义,如 tags: create_user 中,create_user 可修改为 add_user 等。

实验环境搭建

下面通过一个 “部署 Web 服务” 的案例,实际演示 Playbook 的编写和运行。先搭建实验环境:

1:创建工作目录

# 创建web目录(用于存放Playbook相关文件),并进入该目录
[bq@controller ~]$ mkdir web && cd web

2:配置 Ansible 默认参数(ansible.cfg)

创建ansible.cfg文件,定义远程用户、主机清单路径、提权方式等(避免每次执行命令重复输入参数):

[bq@controller web]$ cat > ansible.cfg <<'EOF'
[defaults]
remote_user = bq  # 默认远程登录用户(要在目标主机存在)
inventory = ./inventory  # 主机清单路径(指定为当前目录的inventory文件)[privilege_escalation]
become = True  # 默认启用提权(执行需要root权限的操作)
become_user = root  # 提权到root用户
become_method = sudo  # 提权方式为sudo
become_ask_pass = False  # 提权时不询问密码(需提前配置sudo免密)
EOF

3:定义主机清单(inventory)

创建inventory文件,列出需要管理的主机(每行一个主机名,需确保 controller 能通过 SSH 连接这些主机):

[bq@controller web]$ cat > inventory <<'EOF'
controller  # 控制节点(可选,可用于本地测试)
node1       # 被管理节点1(示例中主要操作的节点)
node2       # 被管理节点2(预留,本案例暂不使用)
node3
node4
EOF

Playbook 编写(实战案例)

我们编写一个 Playbook(web_deploy.yml),实现以下功能:

  1. 在 node1 上安装并启动 httpd(Web 服务)和 firewalld(防火墙);
  2. 配置防火墙允许 http 访问;
  3. 创建一个测试网页;
  4. 在本地(controller)验证 node1 的 Web 服务是否可用。

Playbook 示例

playbook.yaml 内容如下:

# YAML文件起始标识(建议添加,明确文件格式)
---# 第一个Play:部署Web服务到node1
- name: 在node1上部署Web服务(描述Play的作用)hosts: node1  # 目标主机(从inventory中选node1)# 提权配置(覆盖ansible.cfg的默认设置,这里使用默认即可)# remote_user: bq# become: Truetasks:  # 任务列表(按顺序执行)# 任务1:安装httpd和firewalld(确保是最新版本)- name: 安装最新版的httpd和firewalldyum:  # 使用yum模块(适用于CentOS/RHEL系统)name:  # 要安装的软件包列表- httpd  # Web服务软件- firewalld  # 防火墙软件state: latest  # 状态:确保为最新版本(若已安装则升级)# 任务2:创建测试网页- name: 生成测试网页内容copy:  # 使用copy模块(复制内容到目标文件)content: "Welcome to bq WebSite!\n"  # 网页内容(\n是换行)dest: /var/www/html/index.html  # 目标文件路径(httpd默认首页路径)mode: '0644'  # 文件权限(所有者可读可写,其他用户只读)# 任务3:启动并设置firewalld开机自启- name: 确保firewalld服务启动并开机自启service:  # 使用service模块(管理系统服务)name: firewalld  # 服务名称enabled: true  # 开机自启(true=启用,false=禁用)state: started  # 服务状态(started=启动,stopped=停止,restarted=重启)# 任务4:防火墙放行http服务- name: 配置防火墙允许http访问(80端口)firewalld:  # 使用firewalld模块(管理防火墙规则)service: http  # 预定义服务(对应80端口)permanent: true  # 规则永久生效(重启防火墙后不丢失)state: enabled  # 启用规则immediate: yes  # 立即生效(无需等待防火墙重启)# 任务5:启动并设置httpd开机自启- name: 确保httpd服务启动并开机自启service:name: httpdenabled: truestate: started# 第二个Play:在本地验证Web服务
- name: 验证node1的Web服务是否可用hosts: localhost  # 目标主机为本地(controller自身)become: no  # 不需要提权(本地访问无需root)tasks:- name: 访问node1的Web页面,检查是否正常响应uri:  # 使用uri模块(发送HTTP请求并验证)url: http://node1  # 要访问的URL(node1的http服务)return_content: yes  # 返回页面内容(可选,用于调试)status_code: 200  # 期望的HTTP状态码(200=成功)# YAML文件结束标识(可省略)
...

核心结构说明

  1. Play:每个- name: ...开头的块是一个 Play,用于定义对特定主机的操作(如第一个 Play 针对 node1,第二个针对localhost)。
  2. 任务(tasks):每个任务是具体的操作(如安装软件、修改配置),由name(描述)和模块(如yumservice)组成。
  3. 模块:Ansible 的功能单元,每个模块实现特定功能(如yum管理软件包,service管理服务),参数需符合模块要求(可通过ansible-doc 模块名查文档,如ansible-doc yum)。

Playbook 运行与验证

1:检查语法

在运行前先检查 Playbook 语法是否正确:

[bq@controller web]$ ansible-playbook web_deploy.yml --syntax-check
# 成功输出:playbook: web_deploy.yml(无报错说明语法正确)
2:空运行

-C选项模拟运行,不实际修改,查看会执行哪些操作(适合测试):

[bq@controller web]$ ansible-playbook web_deploy.yml -C
# 输出中会显示每个任务的预期状态(如"changed"表示会修改,"ok"表示无变化)
3:实际运行
[bq@controller web]$ ansible-playbook web_deploy.yml#首次运行成功的输出(部分):
PLAY [在node1上部署Web服务] ******************************************
TASK [Gathering Facts] **********************************************
ok: [node1]TASK [安装最新版的httpd和firewalld] ************************************
changed: [node1]  # 状态为changed,表示执行了安装操作...(中间省略其他任务)PLAY [验证node1的Web服务是否可用] **************************************
TASK [Gathering Facts] **********************************************
ok: [localhost]TASK [访问node1的Web页面,检查是否正常响应] ******************************
ok: [localhost]  # 状态为ok,表示访问成功(状态码200)PLAY RECAP **********************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    ...
node1                      : ok=5    changed=3    ...# 第二次运行时,所有任务会显示ok(因为系统状态已符合预期,无需修改),这体现了 Ansible 的 "幂等性"(重复执行结果一致)。
4:手动验证

在 controller 上直接访问 node1 的网页,确认内容正确:

[bq@controller web]$ curl http://node1
Welcome to bq WebSite!  # 输出预期内容,说明部署成功
运行选项补充
  • 详细输出:用-v系列选项查看更多信息(调试时常用):

    ansible-playbook web_deploy.yml -v  # 显示任务结果
    ansible-playbook web_deploy.yml -vv  # 显示任务结果+配置
    ansible-playbook web_deploy.yml -vvv- #包含关于与受管主机连接的信息。
    ansible-playbook web_deploy.yml -vvvv- #增加了连接插件相关的额外详细程度选项,包括受管主机上用于执行脚本的用户,以及所执行的脚本。
    
  • 指定主机:用-l选项仅对部分主机执行(覆盖 Play 中的hosts配置):

    ansible-playbook web_deploy.yml -l node1  # 仅在node1上执行
    
YAML 注释

在 YAML中, 编号或井号符号(#)右侧的所有内容都是注释。如果注释的左侧有内容, 请在该编号符号的前面加一个空格。注释可用于提高可读性。

示例:

# This is YAML comment
Some data # This is also a YAML comment
注意事项与不足

本案例的潜在问题

  1. 环境依赖
    • 假设目标主机是 CentOS/RHEL(使用yum模块),若为 Ubuntu 需替换为apt模块;
    • 需确保 controller 能解析node1的主机名(可在/etc/hosts中配置);
    • become_ask_pass = False要求目标主机的sudo已配置免密(否则会提权失败,需手动输入密码)。
  2. 错误处理
    • 未添加错误判断(如软件安装失败、服务启动失败时,Playbook 会直接报错终止);
    • 可通过ignore_errors: yes忽略特定错误,或failed_when定义失败条件。
  3. 扩展性
    • 若需部署到多台主机,需在inventory中定义主机组(如[web_servers]),并在 Play 中设置hosts: web_servers
    • 重复任务可提取为变量(vars)或角色(Roles),减少代码冗余。
编写 Playbook 的最佳实践
  1. 多写注释:每个 Play 和任务都用name描述作用,复杂逻辑加#注释;
  2. 先测试再执行:用--syntax-check-C验证后再实际运行;
  3. 利用幂等性:尽量使用支持幂等的模块(如yumstate: present不会重复安装);
  4. 拆分复杂任务:一个 Playbook 只做一件事(如部署 Web、部署数据库分开),便于维护。

Playbook 提权

在playbook中指定此关键字将覆盖/etc/ansible/ansible.cfg文件中的设置特权升级属性

  • remote_user,指定ssh用户

  • become,启用或禁用特权升级

  • become_method,启用特权升级的方法

  • become_user,特殊升级的帐户

---
- name: Enable intranet serviceshosts: node1remote_user: bqbecome: truebecome_method: sudobecome_user: roottasks:- name: latest version of httpd and firewalld installedyum:name:- httpd- firewalldstate: latest

YAML属性补充

YAML 单行字符串

YAML中的字符串通常不需要放在引号里,即使字符串中包含空格。

字符串也可以用双引号或单引号括起。

this is a string
'this is another string'
"this is yet another a string"
YAML 多行字符串
  • 可以使用竖线(I)字符表示,保留字符串中的换行字符。

    示例:

    ---
    - name: test stringhosts: node1tasks:- name: test string# 用户显示变量值或者字符串debug:msg: |Example Company123 Main StreetAtlanta, GA 30303
    
  • 也可以使用大于号(>)字符表示换行字符。执行时换行符使用空格代替,并且行内的引导空白将被删除。

    示例:

    ---
    - name: test stringhosts: node1tasks:- name: test string# 用户显示变量值或者字符串debug:msg: >This is an exampleof a long string,that will becomea single sentence once folded.
    

    这种方法通常用于将很长的字符串在空格字符处断行,使它们跨占多行来提高可读性。

YAML 字典

一组键值对的集合,又称为映射(mapping)和哈希(hashes)。

以缩进块的形式编写键值对集合,如下方所示:user属性是字典格式,是多个键值对集合。

user:name: bq uid: 1088state: absent

字典也可以使用以花括号括起的内联块格式编写,如下方所示:

user: {name: bq, uid: 1088, state: absent}

大多数情形中应避免内联块格式,其可读性较差。不过,当playbook中包含角色列表时,使用这种语法,更加容易区分play中包含的角色和传递给角色的变量。

某些 playbook 可能使用较旧的简写(shorthand)格式,通过将模块的键值对放在与模块名称相同的行上来定义任务。

示例:

- name: shorhand formuser: name=bq uid=1088 state=absent

普通格式:

- name: shorhand formuser:name: bq uid: 1088state: absent

两者格式总结:

  • 通常您应避免简写格式,而使用普通格式。
  • 普通格式的行数较多,更容易操作。任务的关键字垂直堆叠,更容易区分。 阅读play时,您的眼睛直接向下扫视,左右运动较少。
  • 普通格式是原生的YAML,现代文本编辑器中的语法突出显示工具可以识别,简写形式则不支持。
  • 可能会在文档和他人提供的旧playbook中看到这种语法,而且这种语法仍然可以发挥作用。
YAML 列表

一组按次序排列的值,又称为序列(sequence)和数组(array)。

以缩进块的形式编写的键值对集合,如下方所示:

- name: latest version of httpd and firewalld installedyum:name:- httpd- firewalldstate: latest
- name: test html page is installedcopy:content: "Welcome to the example.com intranet!\n"dest: /var/www/html/index.html

以上有两个任务,每个任务都是多个键值对描述。其中yum模块操作的软件包是一个简单的名称列表。

内联格式:

name: [httpd, firewalld]

尽量避免内联格式。

http://www.lryc.cn/news/620317.html

相关文章:

  • 3DM游戏运行库合集离线安装包下载, msvcp140.dll丢失等问题修复
  • ESP32_STM32_DHT20
  • 三极管的基极为什么需要下拉电阻
  • Vue3从入门到精通:4.1 Vue Router 4深度解析与实战应用
  • vue实现模拟 ai 对话功能
  • JS的学习5
  • vue修改element的css属性
  • 决策树回归:用“分而治之”的智慧,搞定非线性回归难题(附3D可视化)
  • 北京JAVA基础面试30天打卡09
  • uniapp授权登录
  • 硬件工程师八月实战项目分享
  • 8.13迎来联动:PUBG布加迪,新版本37.1内容资讯!低配置也能飙车吃鸡!
  • 谈一些iOS组件化相关的东西
  • 【Golang】 Context.WithCancel 全面解析与实战指南
  • CAN仲裁机制的原理
  • 【CV 目标检测】③——目标检测方法
  • 玳瑁的嵌入式日记D17-08013(linux文件编程)
  • 深度学习(5):激活函数
  • Linux 桌面到工作站的“性能炼金术”——开发者效率的 6 个隐形瓶颈与破解方案
  • Celery+RabbitMQ+Redis
  • AR展厅在文化展示与传承领域的应用​
  • 嵌入式学习(day26)frambuffer帧缓冲
  • 嵌入式|VNC实现开发板远程Debian桌面
  • PG靶机 - Pelican
  • 飞凌OK3568开发板QT应用程序编译流程
  • 21. 抽象类和接口的区别
  • 【单板硬件】器件采购:BOM表
  • 大数据可视化设计 | 智能家居 UI 设计:从落地方法到案例拆解
  • 【从网络基础到实战】理解TCP/IP协议体系的核心要点(包含ARP协议等其他协议介绍)
  • 词向量转化