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

4.Ansible自动化之-部署文件到主机

4 - 部署文件到受管主机

实验环境

先通过以下命令搭建基础环境(创建工作目录、配置 Ansible 环境和主机清单):

# 在控制节点(controller)上创建web目录并进入,作为工作目录
[bq@controller ~]$ mkdir web && cd web# 创建Ansible配置文件ansible.cfg,定义连接和权限提升参数
[bq@controller web]$ cat > ansible.cfg <<'EOF'
[defaults]
remote_user = bq    # 默认远程连接用户为bq
inventory = ./inventory  # 指定主机清单文件路径为当前目录的inventory[privilege_escalation]
become = True           # 允许提权(切换到其他用户)
become_user = root      # 提权目标用户为root
become_method = sudo    # 提权方式为sudo
become_ask_pass = False # 提权时不询问密码(需提前配置sudo免密)
EOF# 创建主机清单文件inventory,列出需要管理的主机
[bq@controller web]$ cat > inventory <<'EOF'
controller  # 控制节点自身
node1       # 受管节点1
node2       # 受管节点2
node3       # 受管节点3
node4       # 受管节点4
EOF

修改文件并将其复制到主机

Ansible 的 Files 模块库包含一系列文件管理工具,能帮我们完成创建文件、复制文件、修改权限等日常 Linux 文件操作。下面逐个介绍常用模块的用法。

file 模块:管理文件 / 目录的属性(创建、删除、改权限等)

模块作用:可以设置文件 / 目录的权限、所有者、SELinux 上下文等属性,也能直接创建空文件或目录,或者删除不需要的文件 / 目录(类似 Linux 的touchmkdirrmchmod等命令的组合)。

实验 1:创建文件并设置权限

实验流程

  1. 编写 playbook,定义要创建的文件路径、所有者、权限等信息;
  2. 执行 playbook,让 Ansible 在目标主机上执行创建操作;
  3. 登录受管节点,检查文件是否创建成功,以及属性是否符合预期。
---
- hosts: node1        # 目标主机为node1(仅在该节点执行)gather_facts: no    # 不收集主机信息(减少执行时间,加快操作速度)tasks:- name: Touch a file and set permissions  # 任务描述:创建文件并设置权限file:path: /tmp/testfile  # 目标文件的路径(在node1的/tmp目录下创建testfile)owner: bq         # 文件的所有者设置为bq用户group: wheel         # 文件的所属组设置为wheel组mode: 0640           # 文件权限设置为640(所有者可读可写,组内用户可读,其他用户无权限;必须带前导0,否则会解析错误)state: touch         # 状态为"创建文件"(类似Linux的touch命令,若文件不存在则创建空文件,存在则更新修改时间)

注意:mode参数必须带前导 0(如0640)或用引号包裹(如'640')。如果直接写640,Ansible 会当作十进制处理,导致权限计算错误(比如变成-w-------T这种不符合预期的权限)。

实验 2:创建目录

实验流程

  1. 编写 playbook,指定要创建的目录路径、所有者、权限等;
  2. 执行 playbook,让 Ansible 在目标主机上创建目录;
  3. 登录受管节点,验证目录是否存在,以及所有者、权限是否正确。
---
- hosts: node1gather_facts: notasks:- name: create directory  # 任务描述:创建目录file:path: /webdev         # 目标目录路径(在node1的根目录下创建webdev目录)owner: apache         # 目录所有者设置为apache用户(通常用于web服务相关目录)group: apache         # 目录所属组设置为apache组mode: 0755            # 目录权限为755(所有者可读可写可执行,组和其他用户可读可执行;目录需要执行权限才能进入)state: directory      # 状态为"创建目录"(类似Linux的mkdir命令,若目录不存在则创建,存在则不做操作)
...                           # YAML文件结尾的省略符号(实际编写时必须包含)
实验 3:删除文件

实验流程

  1. 编写 playbook,指定要删除的文件路径;
  2. 执行 playbook,让 Ansible 在目标主机上删除文件;
  3. 登录受管节点,确认文件已被删除。
---
- hosts: node1gather_facts: notasks:- name: delete file  # 任务描述:删除文件file:path: /tmp/testfile  # 要删除的文件路径(node1上的/tmp/testfile)state: absent        # 状态为"不存在"(即删除文件,类似Linux的rm命令;若文件不存在则不做操作)
sefcontext 模块:管理 SELinux 的持久规则

模块作用:用于在 SELinux 的规则库中添加或删除持久规则(类似 Linux 的semanage fcontext命令)。注意:添加的规则不会立即生效,需要通过restorecon等命令重新标注文件后才会应用。

实验:添加 SELinux 上下文规则

实验流程

  1. 编写 playbook,定义要设置的文件路径和对应的 SELinux 类型;
  2. 执行 playbook,让 Ansible 在目标主机上添加 SELinux 规则;
  3. (可选)在受管节点执行restorecon命令,使新添加的规则立即生效。
---
- name: 添加SELinux上下文规则hosts: node1tasks:- name: 获取SElinux当前状态command: getenforce  # 执行getenforce命令,获取SELinux当前模式(Enforcing/Permissive)register: selinux_running_state  # 将命令结果保存到变量selinux_running_statechanged_when: false  # 标记该任务不会改变主机状态(避免Ansible误判为"已修改")failed_when: false   # 即使命令执行失败也不标记任务失败(兼容SELinux未开启的情况)- name: 仅在Permissive模式下切换为Enforcingcommand: setenforce 1  # 将SELinux切换为强制模式(1表示Enforcing)ignore_errors: no  # 若执行失败则标记任务失败(确保SELinux正常运行)- name: 安装policycoreutils-python依赖yum:  # 使用yum模块安装依赖包(SELinux规则管理需要该工具)name: policycoreutils-pythonstate: present  # 确保包已安装- name: 设置/samba目录的SELinux上下文sefcontext:target: '/samba(/.*)?'  # 匹配路径:/samba目录及所有子目录和文件(正则表达式)setype: samba_share_t   # 设置SELinux类型为samba_share_t(Samba共享目录的专用类型)state: present          # 状态为"存在"(即添加该规则到SELinux规则库)

注意:sefcontext模块仅修改 SELinux 的规则库,不会直接改变现有文件的 SELinux 上下文。如果要让规则立即生效,需配合file模块(file模块会实时应用上下文)或手动执行restorecon -R /samba(递归刷新 /samba 目录的上下文)。

lineinfile 模块:管理文件中的单行内容

模块作用:用于修改已存在的文件,可确保文件中存在特定行、替换符合条件的行,或在指定位置插入行(类似 Linux 的sed命令的单行处理功能)。

实验 1:向文件添加特定行

实验流程

  1. 编写 playbook,先创建目标文件,再指定要添加的行内容;
  2. 执行 playbook,让 Ansible 在目标文件中添加行;
  3. 查看文件内容,验证行是否添加成功。
---
- hosts: node1gather_facts: notasks:- name: 创建文件file:  # 先创建/tmp/testfile文件(若已存在则不做操作)path: /tmp/testfilestate: touchowner: bqgroup: wheelmode: 0644- name: add line  # 任务描述:添加一行内容lineinfile:path: /tmp/testfile  # 目标文件路径(node1上的/tmp/testfile)line: 'Add this line to file'  # 要添加的行内容state: present      # 确保该行存在(如果文件中没有,则添加到末尾;如果已有,则不重复添加)
实验 2:在指定位置插入行

实验流程

  1. 编写 playbook,指定目标文件、要插入的行,以及插入位置(某行之前 / 之后);
  2. 执行 playbook,让 Ansible 在指定位置插入行;
  3. 查看文件内容,验证行是否插入到正确位置。
# 在"Listen 80"行之前插入"Listen 82"
---
- hosts: node1gather_facts: notasks:- name: add line before Listen 80lineinfile:path: /etc/httpd/conf/httpd.conf  # 目标文件(httpd服务的配置文件)line: 'Listen 82'                 # 要插入的行(让httpd监听82端口)insertbefore: 'Listen 80'         # 插入位置:在"Listen 80"行之前state: present# 在"Listen 80"行之后插入"Listen 82"
---
- hosts: node1gather_facts: notasks:- name: add line after Listen 80lineinfile:path: /etc/httpd/conf/httpd.confline: 'Listen 82'insertafter: 'Listen 80'  # 插入位置:在"Listen 80"行之后state: present
...
实验 3:替换符合条件的行

实验流程

  1. 编写 playbook,用正则表达式匹配要替换的行,指定新内容;
  2. 执行 playbook,让 Ansible 替换目标行;
  3. 查看文件内容,验证匹配的行是否被正确替换。
# 替换包含"Add"的行
---
- hosts: node1gather_facts: notasks:- name: replace line  # 任务描述:替换行内容lineinfile:path: /tmp/testfileregexp: 'Add'     # 正则表达式:匹配所有包含"Add"的行line: 'replace'   # 替换后的内容(将匹配的行替换为"replace")state: present# 注释掉httpd的80端口监听(在行首加#)
---
- hosts: node1gather_facts: notasks:- name: comment Listen 80lineinfile:path: /etc/httpd/conf/httpd.confline: '#Listen 80'  # 替换后的内容(在原行首加#,实现注释)regexp: '^Listen 80'  # 正则表达式:匹配以"Listen 80"开头的行(^表示行首)state: present
...
replace 模块:批量替换文件中的内容

模块作用:用正则表达式匹配文件中所有符合条件的内容,并一次性替换(类似 Linux 的sed -i 's/原内容/新内容/g'命令,会替换所有匹配项,而不仅是单行)。

实验:替换所有匹配的行

实验流程

  1. 编写 playbook,定义目标文件、匹配规则(正则表达式)和替换内容;
  2. 执行 playbook,让 Ansible 批量替换文件内容;
  3. 查看文件内容,验证所有匹配的内容是否被替换。
---
- hosts: node1gather_facts: notasks:- name: replace multi line  # 任务描述:批量替换行replace:path: /tmp/testfile    # 目标文件(node1上的/tmp/testfile)regexp: '^Hello World.*'  # 正则表达式:匹配所有以"Hello World"开头的行(.*表示任意字符)replace: 'Hello bq'    # 替换后的内容(将匹配的行替换为"Hello bq")
...
blockinfile 模块:管理文件中的多行文本块

模块作用:向文件中插入、更新或删除多行文本块。插入的内容会自动添加标记(# BEGIN ANSIBLE MANAGED BLOCK# END ANSIBLE MANAGED BLOCK),方便后续识别和更新(再次执行时会更新块内内容,而不是重复添加)。

实验:向文件添加多行文本块

实验流程

  1. 编写 playbook,定义目标文件和要添加的多行内容;
  2. 执行 playbook,让 Ansible 在目标文件中插入文本块;
  3. 查看文件内容,验证文本块是否添加,及是否包含自动生成的标记。
---
- hosts: node1gather_facts: notasks:- name: add block lines to file  # 任务描述:添加多行文本块blockinfile:path: /tmp/testfile          # 目标文件(node1上的/tmp/testfile)block: |                     # 要添加的多行内容(| 表示保留换行符,保持原格式)line 1 in fileline 2 in fileaaline 3 in file sssstate: present               # 确保文本块存在(若不存在则添加;若已存在则更新内容)
...

执行后,文件中会添加以下内容(自动包含标记):

# BEGIN ANSIBLE MANAGED BLOCK
line 1 in file
line 2 in fileaa
line 3 in file sss
# END ANSIBLE MANAGED BLOCK
stat 模块:获取文件的状态信息

模块作用:检索文件的详细信息(如权限、校验和、创建时间、大小等),类似 Linux 的stat命令。获取的结果可以保存到变量中,用于后续任务的条件判断(比如根据文件是否存在决定是否执行某操作)。

实验:获取文件的 MD5 校验和

实验流程

  1. 编写 playbook,用 stat 模块获取文件信息并保存到变量;
  2. 执行 playbook,通过 debug 模块输出文件的 MD5 校验和;
  3. 查看输出结果,验证是否正确获取校验和。
---
- hosts: node1gather_facts: notasks:- stat:  # 调用stat模块获取文件信息path: /tmp/testfile        # 目标文件(node1上的/tmp/testfile)checksum_algorithm: md5    # 指定校验和算法为MD5(可选值:md5、sha1、sha256等)register: result             # 将获取的信息保存到变量result中- debug:  # 输出MD5校验和msg: "/tmp/testfile md5 is {{ result.stat.checksum }}"  # 通过{{ }}引用变量中的checksum值- debug:  # 输出所有文件信息(方便查看详细内容,如权限、大小等)var: result  # 直接输出变量result的内容
...
copy 模块:复制文件到受管节点

模块作用:将控制节点或其他远程节点的文件复制到受管节点,类似 Linux 的scp命令。支持设置文件权限、所有者,以及是否备份原文件、是否强制覆盖等。

实验 1:复制控制节点文件到受管节点

实验流程

  1. 在控制节点准备好要复制的文件(如/tmp/testfile);
  2. 编写 playbook,指定控制节点的源文件路径和受管节点的目标路径;
  3. 执行 playbook,让 Ansible 完成文件复制;
  4. 在受管节点查看目标路径,验证文件是否复制成功。
---
- name: 复制控制节点文件到受管节点hosts: node1  # 目标受管节点tasks:- name: 复制控制节点的/tmp/testfile到受管节点copy:src: /tmp/testfile  # 控制节点上的源文件路径(可以是绝对路径,或相对于playbook的相对路径)dest: /tmp/  # 受管节点上的目标目录(复制后会保持原文件名,即/tmp/testfile)owner: root  # 可选:设置文件所有者为rootgroup: root  # 可选:设置文件所属组为rootmode: 0644   # 可选:设置文件权限为644(所有者可读可写,组和其他用户可读)backup: yes  # 可选:如果目标文件已存在,先创建.bak备份(如/tmp/testfile.bak)- name: 验证文件是否复制成功stat:  # 检查受管节点上的目标文件path: /tmp/testfile  # 受管节点上的目标文件路径register: file_check  # 将检查结果保存到变量file_check- name: 输出验证结果debug:  # 当文件存在时,输出成功信息msg: "文件已成功复制到受管节点,路径为: /tmp/testfile"when: file_check.stat.exists  # 条件:仅当file_check.stat.exists为true时执行- name: 查看文件内容(可选)command: cat /tmp/testfile  # 读取文件内容register: file_content  # 保存内容到变量file_contentwhen: file_check.stat.exists  # 仅当文件存在时执行- name: 显示文件内容debug:  # 输出文件内容msg: "文件内容:\n{{ file_content.stdout }}"  # stdout存储命令执行结果when: file_check.stat.exists  # 仅当文件存在时执行
...

说明:copy模块默认force: yes(强制覆盖目标文件),如果设置force: no,则当目标文件已存在时不会覆盖(保留原文件)。

实验 2:直接写入字符串到文件

实验流程

  1. 编写 playbook,用content参数定义要写入的文件内容;
  2. 执行 playbook,让 Ansible 在受管节点创建文件并写入内容;
  3. 在受管节点查看文件内容,验证是否正确。
---
- name: 直接写入字符串到受管节点的文件hosts: node1tasks:- name: 创建文件并写入内容copy:content: |  # 要写入的内容(| 表示保留换行,支持多行)这是第一行内容这是第二行内容可以包含多行字符串最后一行内容dest: /tmp/demo.txt  # 受管节点上的目标文件路径(会创建该文件)owner: root          # 可选:设置文件所有者为rootgroup: root          # 可选:设置文件所属组为rootmode: 0644           # 可选:设置文件权限为644- name: 验证文件内容command: cat /tmp/demo.txt  # 读取文件内容register: file_content  # 保存内容到变量- name: 显示文件内容debug:  # 输出文件内容msg: "文件内容如下:\n{{ file_content.stdout }}"
...
synchronize 模块:基于 rsync 同步文件 / 目录

模块作用:封装了rsync工具,用于高效同步文件 / 目录(速度比copy模块快,适合大量文件或大文件同步)。需要控制节点和受管节点都安装rsync工具。

实验 1:同步单个文件

实验流程

  1. 确保控制节点和受管节点都安装rsync(可通过yum install -y rsync安装);
  2. 编写 playbook,指定控制节点的源文件路径和受管节点的目标路径;
  3. 执行 playbook,让 Ansible 通过 rsync 同步文件;
  4. 在受管节点验证文件是否同步成功。
---
- name: 使用synchronize模块同步单个文件hosts: node1  # 受管节点tasks:# 步骤1:确保控制节点和受管节点都安装rsync- name: 安装rsync工具yum:name: rsyncstate: present  # 确保rsync已安装# 步骤2:同步控制节点的文件到受管节点- name: 同步单个文件到受管节点synchronize:src: /path/on/control/node/source.txt  # 控制节点上的源文件路径(替换为实际路径)dest: /path/on/remote/node/destination.txt  # 受管节点上的目标路径(替换为实际路径)mode: push  # 同步方向:从控制节点推送到受管节点(默认就是push,可省略)# 步骤3:验证文件是否同步成功- name: 检查受管节点上的目标文件stat:path: /path/on/remote/node/destination.txt  # 受管节点上的目标文件路径register: file_status  # 保存检查结果- name: 显示验证结果debug:  # 当文件存在时,输出成功信息msg: "文件同步成功,路径:{{ file_status.stat.path }}"when: file_status.stat.exists  # 仅当文件存在时执行
...
实验 2:同步目录

实验流程

  1. 在控制节点准备要同步的目录(如/etc/sysconfig);
  2. 编写 playbook,指定控制节点的源目录和受管节点的目标路径;
  3. 执行 playbook,让 Ansible 同步目录;
  4. 在受管节点查看目标路径,验证目录内容是否同步成功。
---
- hosts: node1gather_facts: noremote_user: root  # 同步系统目录可能需要root权限tasks:- name: synchronize directory  # 任务描述:同步目录synchronize:src: /etc/sysconfig  # 控制节点上的源目录(/etc/sysconfig,包含系统服务配置)dest: /tmp/          # 受管节点上的目标路径(同步后会在/tmp下创建sysconfig子目录,即/tmp/sysconfig)
...
fetch 模块:从受管节点获取文件到控制节点

模块作用:将受管节点的文件复制到控制节点,常用于收集日志、配置文件等。文件会按 “控制节点目标路径 / 受管节点名 / 原文件路径” 的结构保存(方便区分不同节点的文件)。

实验:从受管节点获取文件

实验流程

  1. 编写 playbook,指定受管节点的源文件路径和控制节点的保存路径;
  2. 执行 playbook,让 Ansible 从受管节点复制文件到控制节点;
  3. 在控制节点查看保存路径,验证文件是否按预期结构保存。
---
- hosts: node1gather_facts: notasks:- name: fetch file from remote node  # 任务描述:获取远程文件fetch:src: /tmp/testfile  # 受管节点上的源文件路径(node1的/tmp/testfile)dest: /tmp          # 控制节点上的保存路径
...

执行后,文件会保存在控制节点的/tmp/node1/tmp/testfile(路径结构:目标路径/受管节点名/原文件绝对路径)。

使用 JINJA2 模板部署文件

Jinja2 模板是一种带变量和逻辑的文件(比如包含{{ 变量 }}{% 循环/条件 %}等)。通过 Ansible 的template模块部署到受管节点时,Ansible 会自动替换变量、执行逻辑,生成个性化的配置文件。

基础示例:部署动态网页

实验流程

  1. 创建 Jinja2 模板文件(包含变量,如{{ ansible_fqdn }});
  2. 编写 playbook,用template模块部署模板到受管节点;
  3. 执行 playbook,在受管节点查看生成的文件,验证变量是否被正确替换。
步骤 1:编写 playbook(deploy_web.yml
---
- name: Enable intranet services  # 部署web服务hosts: node1tasks:- name: ensure latest version of httpd  # 安装httpd服务(用于提供web服务)yum:name: httpdstate: latest  # 确保安装最新版本- name: deploy test html page  # 部署动态主页template:src: index.html.j2  # 控制节点上的Jinja2模板文件(与playbook同目录)dest: /var/www/html/index.html  # 受管节点上的目标文件(httpd的默认主页路径)- name: start and enable httpd  # 启动httpd并设置开机自启service:name: httpdenabled: true  # 开机自启state: restarted  # 重启服务(使配置生效)
步骤 2:创建模板文件(index.html.j2

在 playbook 同目录下创建index.html.j2,内容如下:

Welcome to {{ ansible_fqdn }}  # {{ }} 中的变量会被替换为受管节点的完全主机名(如node1.bq.cloud)
步骤 3:执行与验证

执行 playbook 后,受管节点的/var/www/html/index.html内容会自动替换变量,变成:

Welcome to node1.bq.cloud  # 假设node1的完全主机名是node1.bq.cloud
进阶示例:部署 SSH 配置文件

实验流程

  1. 创建含多个变量的 Jinja2 模板(如{{ ssh_port }}{{ root_allowed }});
  2. 在 playbook 中定义模板变量的值;
  3. 部署模板到受管节点,验证生成的配置文件是否正确替换变量。
步骤 1:编写模板(sshd_config.j2
# {{ ansible_managed }}  # 会替换为"Ansible managed"(可在ansible.cfg中自定义)
# DO NOT MAKE LOCAL MODIFICATIONS TO THIS FILE AS THEY WILL BE LOST
Port {{ ssh_port }}  # SSH端口(使用变量ssh_port的值)
ListenAddress {{ ansible_facts['default_ipv4']['address'] }}  # 监听IP(使用受管节点的默认IPv4地址)HostKey /etc/ssh/ssh_host_rsa_key  
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTHPRIV
PermitRootLogin  {{ root_allowed }}  # 是否允许root登录(使用变量root_allowed的值)
AllowGroups {{ groups_allowed }}  # 允许登录的组(使用变量groups_allowed的值)AuthorizedKeysFile      /etc/.rht_authorized_keys .ssh/authorized_keys
PasswordAuthentication {{ passwords_allowed }}  # 是否允许密码认证(使用变量passwords_allowed的值)
步骤 2:编写 playbook(deploy_ssh.yml
---
- name: config sshd service  # 配置SSH服务hosts: node1vars:  # 定义模板中用到的变量(键值对形式)ssh_port: 1022  # SSH端口设为1022(非默认端口更安全)root_allowed: "yes"  # 允许root登录groups_allowed: wheel  # 允许wheel组用户登录passwords_allowed: "yes"  # 允许密码认证ansible_managed: "Ansible managed: do not edit manually"  # 覆盖默认的ansible_managed变量tasks:- name: deploy sshd config  # 部署模板template:src: sshd_config.j2  # 控制节点上的模板文件dest: /root/sshd_config  # 先部署到/root目录验证(实际使用时应替换为/etc/ssh/sshd_config)
Jinja2 模板语法详解

模板中通过特殊符号包裹变量和逻辑,常用符号:

  • {{ 变量/表达式 }}:输出变量或表达式结果(如{{ 1+1 }}输出2);
  • {% 控制语句 %}:用于循环(for)、条件判断(if)等(如{% for user in users %});
  • {# 注释 #}:模板内的注释,不会出现在生成的文件中(仅用于模板编写者参考)。
1. for 循环:遍历列表 / 字典

作用:重复输出列表或字典中的每个元素,类似编程语言中的for循环。

示例 1:遍历用户列表
  • playbook 中定义变量:

    vars:users:  # 定义一个用户列表- tom- jack- Snoopy- lucy
    
  • 模板文件(testfile.j2):

    {% for user in users %}  # 遍历users列表,每次取一个元素赋值给user
    {{ user }}  # 输出当前user的值
    {% endfor %}  # 结束循环
    
  • 生成的文件内容:

    tom
    jack
    Snoopy
    lucy
    
示例 2:带索引的循环
  • 模板文件(testfile.j2):

    {% for user in users %}
    {{ loop.index }} - {{ user }}  # loop.index是循环的序号(从1开始)
    {% endfor %}
    
  • 生成的文件内容:

    1 - tom
    2 - jack
    3 - Snoopy
    4 - lucy
    
示例 3:生成主机列表文件

需求:在/etc/myhosts中添加所有主机的 IP、完全主机名和主机名。

  • 主机清单(inventory):

    [controllers]
    controller[dev]
    node1[test]
    node2[prod]
    node3
    node4
    
  • playbook(deploy_hosts.yml):

    ---
    - name: deploy /etc/myhostshosts: all  # 必须对所有主机执行,才能收集所有主机的信息tasks:- name: generate /etc/myhoststemplate:src: hosts.j2dest: /etc/myhostswhen: inventory_hostname in groups.dev  # 只部署到dev组主机(这里指node1)
    ...
    
  • 模板文件(hosts.j2):

    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6{% for server in groups.all %}   # 遍历所有主机(groups.all是包含所有主机的列表)
    # hostvars[server]               # 用于获取其他主机的信息(如IP、主机名)
    {{ hostvars[server].ansible_default_ipv4.address }} {{ hostvars[server].ansible_fqdn }} {{ hostvars[server].ansible_hostname }}
    {% endfor %}
    
2. if 条件判断:根据条件输出内容

作用:满足条件时才输出特定内容,类似if-else语句。

示例 1:判断变量是否存在
{% if PORT is defined %}  # 如果PORT变量已定义(在playbook中设置过)
bind-address=0.0.0.0:{{ PORT }}  # 使用PORT变量的值(如0.0.0.0:3307)
{% else %}  # 否则(PORT未定义)
bind-address=0.0.0.0:3306  # 使用默认端口3306
{% endif %}
示例 2:循环中过滤元素
{% for num in [7,1,5,3,9] if num>3 %}  # 只遍历大于3的数字(过滤条件)
{{ num }}
{% endfor %}

生成的文件内容:

7
5
9
3. 表达式:支持运算和比较
比较运算
{{ 1 == 1 }}  # 等于 → True
{{ 2 != 2 }}  # 不等于 → False
{{ 2 > 1 }}   # 大于 → True
{{ 2 <= 1 }}  # 小于等于 → False
逻辑运算
{{ (2 > 1) or (1 > 2) }}  # 或 → True(只要一个条件成立)
{{ (2 > 1) and (1 > 2) }} # 与 → False(两个条件都成立才为True)
{{ not true }}  # 非 → False(取反)
算术运算
{{ 3 + 2 }}   # 加 → 5
{{ 3 * 5 }}   # 乘 → 15
{{ 2 **3 }}  # 幂 → 8(2的3次方)
{{ 7 // 5 }}  # 整除 → 1(只保留整数部分)
{{ 17 % 5 }}  # 取余 → 2(17除以5的余数)
4. 过滤器:格式化输出结果

过滤器用于对变量或表达式的结果进行处理(如转换大小写、排序等),格式为{{ 变量 | 过滤器 }}

字符串处理
{{ 'hello' | upper }}  # 转大写 → HELLO
{{ 'HELLO' | lower }}  # 转小写 → hello
{{ 'hello' | capitalize }}  # 首字母大写 → Hello
{{ '  hello  ' | trim }}  # 去除首尾空格 → hello
列表处理
{{ [3,1,7] | sort }}  # 升序排序 → [1, 3, 7]
{{ [3,1,7] | max }}   # 最大值 → 7
{{ [3,1,7] | sum }}   # 求和 → 11
{{ [3,1,7] | join(',') }}  # 用逗号连接 → 3,1,7
数字处理
{{ '123' | int }}  # 转整数 → 123(将字符串转为整数)
{{ 'abc' | int(default=0) }}  # 转换失败用默认值 → 0(字符串无法转整数时返回0)
{{ 12.5 | round }}  # 四舍五入 → 13
{{ -5 | abs }}  # 绝对值 → 5
ansible_managed 变量

用于在模板中添加 “此文件由 Ansible 管理” 的注释,提醒用户不要手动修改(否则下次执行 playbook 可能被覆盖)。默认值在ansible.cfg中定义:

[defaults]
ansible_managed = Ansible managed  # 可自定义,如"Ansible managed: do not edit manually"

在模板中引用:

# {{ ansible_managed }}  # 会替换为上述配置的值(如"Ansible managed: do not edit manually")

如涉及版权问题请联系作者处理!!!!

http://www.dtcms.com/a/336219.html

相关文章:

  • Mac(五)自定义鼠标滚轮方向 LinearMouse
  • 【网络通信】TCP/IP 协议全方位解析​
  • 计算机网络 TCP、UDP 区别
  • 云原生俱乐部-RH134知识点总结(2)
  • mediamtx v1.14.0版本全面解析:RTP流接收、IPv6支持与性能监控体系升级​
  • 如何做HTTP优化
  • Python 项目里的数据清理工作(数据清洗步骤应用)
  • 芯片行业主要厂商
  • Java 大视界 -- 基于 Java 的大数据分布式计算在气象灾害预警与应急响应中的应用
  • LeetCode 837.新 21 点:动态规划+滑动窗口
  • 动态规划法 - 53. 最大子数组和
  • MySQL数据库基础操作指南:从创建到管理的完整流程
  • Linux系统中6种替代top的工具
  • SparkSQL性能优化实践指南
  • ubuntu 24.04 安装
  • RAC环境redo在各节点本地导致数据库故障恢复---惜分飞
  • 云智智慧停充一体云-allnew全新体验-路内停车源码+路外停车源码+充电桩源码解决方案
  • 从零配置YOLOv8环境:RTX 3060显卡完整指南
  • 43.安卓逆向2-补环境-使用unidbg(使用Smali语法调用方法和使用方法地址调用方法)
  • n2n局域网搭建
  • 0-12岁幼儿启蒙与教育
  • Linux操作系统远程连接
  • 代码管理系统简介与部署
  • 《告别 if-else 迷宫:Python 策略模式 (Strategy Pattern) 的优雅之道》
  • Honor of Kings 101star (S40) 2025.08.17
  • Spring Bean 的生命周期:从创建到销毁的完整旅程​
  • Gemini 学习记录:实践与反思
  • 深度解析 Spring Bean 生命周期
  • UE5多人MOBA+GAS 49、创建大厅
  • MariaDB 多源复制