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

4.Ansible部署文件到主机

4 - 部署文件到受管主机

实验环境

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

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

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

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

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

模块作用:用于设置文件 / 目录的权限、所有者、SELinux 上下文等属性,也能创建或删除文件 / 目录。

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

实验流程

  1. 编写 playbook,定义要创建的文件路径、所有者、权限等;
  2. 执行 playbook;
  3. 登录受管节点验证文件是否创建及属性是否正确。
---
- hosts: node1        # 目标主机为node1gather_facts: no    # 不收集主机信息(加快执行速度)tasks:- name: Touch a file and set permissions  # 任务描述:创建文件并设置权限file:path: /tmp/testfile  # 目标文件路径owner: laoma         # 文件所有者为laomagroup: wheel         # 文件所属组为wheelmode: 0640           # 文件权限为640(注意必须带前导0,否则会解析错误)state: touch         # 状态为创建文件(类似touch命令)

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

实验 2:创建目录

实验流程

  1. 编写 playbook,指定目录路径、所有者、权限;
  2. 执行 playbook;
  3. 验证目录是否创建及属性是否正确。
---
- hosts: node1gather_facts: notasks:- name: create directory  # 任务描述:创建目录file:path: /webdev         # 目标目录路径owner: apache         # 目录所有者为apachegroup: apache         # 目录所属组为apachemode: 0755            # 目录权限为755(读/写/执行权限:所有者全有,组和其他有读和执行)state: directory      # 状态为创建目录(类似mkdir命令)
...                           # 后面playbook脚本大部分省略了这个符号(写的时候必须得有)
实验 3:删除文件

实验流程

  1. 编写 playbook,指定要删除的文件路径;
  2. 执行 playbook;
  3. 验证文件是否被删除。
---
- hosts: node1gather_facts: notasks:- name: delete file  # 任务描述:删除文件file:path: /tmp/testfile  # 要删除的文件路径state: absent        # 状态为"不存在"(即删除文件,类似rm命令)
sefcontext 模块:管理 SELinux 的持久规则

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

实验:添加 SELinux 上下文规则

实验流程

  1. 编写 playbook,定义要设置的文件路径和 SELinux 类型;
  2. 执行 playbook 添加规则;
  3. (可选)在受管节点执行restorecon使规则生效。
---
- hosts: node1gather_facts: notasks:- sefcontext:target: '/samba(/.*)?'  # 匹配/samba目录及所有子目录文件setype: samba_share_t   # 设置SELinux类型为samba_share_t(用于Samba共享)state: present          # 状态为"存在"(即添加规则)

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

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

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

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

实验流程

  1. 编写 playbook,指定目标文件和要添加的行;
  2. 执行 playbook;
  3. 查看文件验证行是否添加成功。
---
- hosts: node1gather_facts: notasks:- name: add line  # 任务描述:添加一行内容lineinfile:path: /tmp/testfile  # 目标文件路径line: 'Add this line to file'  # 要添加的行内容state: present      # 确保行存在(如果不存在则添加)
实验 2:在指定位置插入行

实验流程

  1. 编写 playbook,指定目标文件、要插入的行,以及插入位置(在某行之前 / 之后);
  2. 执行 playbook;
  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'                 # 要插入的行(监听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;
  3. 验证匹配的行是否被替换。
# 替换包含"Add"的行
---
- hosts: node1gather_facts: notasks:- name: replace line  # 任务描述:替换行内容lineinfile:path: /tmp/testfileregexp: 'Add'     # 正则表达式:匹配包含"Add"的行line: '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 模块:批量替换文件中的内容

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

实验:替换所有匹配的行

实验流程

  1. 编写 playbook,定义目标文件、匹配规则和替换内容;
  2. 执行 playbook;
  3. 验证所有匹配的内容是否被替换。
---
- hosts: node1gather_facts: notasks:- name: replace multi line  # 任务描述:批量替换行replace:path: /tmp/testfile    # 目标文件regexp: '^Hello World.*'  # 匹配以"Hello World"开头的所有行replace: 'Hello Laoma'    # 替换后的内容
blockinfile 模块:管理文件中的多行文本块

模块作用:向文件中插入、更新或删除多行文本块,插入的内容会自动添加标记(# BEGIN ANSIBLE MANAGED BLOCK# END ANSIBLE MANAGED BLOCK),方便后续管理。

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

实验流程

  1. 编写 playbook,定义目标文件和要添加的多行内容;
  2. 执行 playbook;
  3. 查看文件验证文本块是否添加,及是否包含标记。
---
- hosts: node1gather_facts: notasks:- name: add block lines to file  # 任务描述:添加多行文本块blockinfile:path: /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 模块输出校验和;
  3. 查看输出结果验证。
---
- hosts: node1gather_facts: notasks:- stat:path: /tmp/testfile        # 目标文件checksum_algorithm: md5    # 指定校验和算法为MD5register: result             # 将结果保存到变量result- debug:msg: "/tmp/testfile md5 is {{ result.stat.checksum }}"  # 输出MD5值- debug:var: result  # 输出所有文件信息(方便查看详细内容)
copy 模块:复制文件到受管节点

模块作用:将控制节点或其他远程节点的文件复制到受管节点,类似scp命令,支持设置权限、强制覆盖等。

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

实验流程

  1. 在控制节点准备好要复制的文件(如/tmp/testfile);
  2. 编写 playbook,指定源文件和目标路径;
  3. 执行 playbook;
  4. 在受管节点验证文件是否复制成功。
---
- hosts: node1gather_facts: notasks:- name: copy /tmp/testfile to remote node  # 任务描述:复制文件copy:src: /tmp/testfile  # 控制节点上的源文件路径dest: /tmp          # 受管节点上的目标路径(保留原文件名)

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

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

实验流程

  1. 编写 playbook,用content参数定义文件内容;
  2. 执行 playbook;
  3. 在受管节点查看文件内容是否正确。
---
- hosts: node1gather_facts: notasks:- name: write string into /tmp/testfile  # 任务描述:写入字符串到文件copy:content: "hello world\n"  # 要写入的内容(\n表示换行)dest: /tmp/testfile       # 目标文件路径
synchronize 模块:基于 rsync 同步文件 / 目录

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

实验 1:同步单个文件

实验流程

  1. 确保控制节点和受管节点都安装rsyncyum install -y rsync);
  2. 编写 playbook,指定源文件和目标路径;
  3. 执行 playbook;
  4. 验证文件是否同步成功。
---
- hosts: node1gather_facts: notasks:- name: synchronize file  # 任务描述:同步文件synchronize:src: /tmp/testfile  # 源文件(控制节点路径)dest: /tmp/         # 目标路径(受管节点)
实验 2:同步目录

实验流程

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

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

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

实验流程

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

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

使用 JINJA2 模板部署文件

Jinja2 模板是一种带变量和逻辑的文件,通过 Ansible 的template模块部署到受管节点时,会自动替换变量和执行逻辑,生成个性化配置文件。

基础示例:部署动态网页

实验流程

  1. 创建 Jinja2 模板文件(含变量);
  2. 编写 playbook,用template模块部署模板;
  3. 执行 playbook,验证生成的文件是否替换了变量。
步骤 1:编写 playbook(deploy_web.yml
---
- name: Enable intranet services  # 部署web服务hosts: node1tasks:- name: ensure latest version of httpd  # 安装httpdyum:name: httpdstate: latest- name: deploy test html page  # 部署动态主页template:src: index.html.j2  # 控制节点上的Jinja2模板dest: /var/www/html/index.html  # 受管节点上的目标文件- name: start and enable httpd  # 启动并设置开机自启service:name: httpdenabled: truestate: restarted
步骤 2:创建模板文件(index.html.j2
Welcome to {{ ansible_fqdn }}  # {{ }} 中的变量会被替换为受管节点的完全主机名
步骤 3:执行与验证

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

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

实验流程

  1. 创建含多个变量的 Jinja2 模板;
  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端口(变量)
ListenAddress {{ ansible_facts['default_ipv4']['address'] }}  # 监听IP(来自主机信息)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登录(变量)
AllowGroups {{ groups_allowed }}  # 允许登录的组(变量)AuthorizedKeysFile      /etc/.rht_authorized_keys .ssh/authorized_keys
PasswordAuthentication {{ passwords_allowed }}  # 是否允许密码认证(变量)
步骤 2:编写 playbook(deploy_ssh.yml
---
- name: config sshd service  # 配置SSH服务hosts: node1vars:  # 定义模板中用到的变量ssh_port: 1022root_allowed: "yes"groups_allowed: wheelpasswords_allowed: "yes"ansible_managed: "Ansible managed: do not edit manually"  # 覆盖默认的ansible_managedtasks:- name: deploy sshd config  # 部署模板template:src: sshd_config.j2dest: /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组主机
    
  • 模板文件(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变量已定义
bind-address=0.0.0.0:{{ PORT }}  # 使用PORT变量
{% else %}  # 否则
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
{{ not true }}  # 非 → False
算术运算
{{ 3 + 2 }}   # 加 → 5
{{ 3 * 5 }}   # 乘 → 15
{{ 2 **3 }}  # 幂 → 8(2的3次方)
{{ 7 // 5 }}  # 整除 → 1
{{ 17 % 5 }}  # 取余 → 2
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
{{ 12.5 | round }}  # 四舍五入 → 13
{{ -5 | abs }}  # 绝对值 → 5
ansible_managed 变量

用于在模板中添加 “此文件由 Ansible 管理” 的注释,避免手动修改。默认值在ansible.cfg中定义:

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

在模板中引用:

# {{ ansible_managed }}  # 会替换为上述配置的值

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

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

相关文章:

  • Torch -- 卷积学习day2 -- 卷积扩展、数据集、模型
  • Linux软件编程(四)多任务与多进程管理
  • 机械硬盘模块逻辑与工作原理
  • 某处卖600的【独角仙】尾盘十分钟短线 尾盘短线思路 手机电脑通用无未来函数
  • uniapp对接极光消息推送
  • 【CLR via C#(第3版)阅读笔记】类型基础
  • [特殊字符]走进华为,解锁商业传奇密码
  • K8s学习----Namespace:资源隔离与环境管理的核心机制
  • 渲染 opentype 多个字符的文本,并设置文本的渲染开始位置
  • Warm-Flow 1.8.0 重大更新
  • Lua 脚本在 Redis 中的应用
  • vivo Pulsar 万亿级消息处理实践(4)-Ansible运维部署
  • 河南萌新联赛2025第(五)场:信息工程大学补题
  • 飞书文档定时自动同步至百炼知识库
  • ESP32 I2S音频总线学习笔记(六):DIY蓝牙音箱教程
  • CVPR 2025 | 北大团队SLAM3R:单目RGB长视频实时重建,精度效率双杀!
  • 在mysql> 下怎么运行 .sql脚本
  • C#WPF实战出真汁00--项目介绍
  • 极速开发新体验_Vite构建工具详解
  • 使用YOLOv13进行钢板表面缺陷检测
  • Python之Django使用技巧(附视频教程)
  • 云手机都具有哪些特点?
  • Ollama如何分别使用2张H100GPU和4张A100部署GPT-OSS-120B全指南:硬件配置与负载均衡实战
  • Linux命令大全-zip命令
  • 嵌入式学习(day27)多任务进程
  • 接口测试与常用接口测试工具详解
  • CMake message()使用指南
  • SpringMVC(详细版从入门到精通)未完
  • 微前端-解决MicroApp微前端内存泄露问题
  • python bokeh