安全地传输文件:使用 Ansible 的 Copy 和 Fetch 模块

使用 Ansible copy 和 fetch 临时命令将文件推送到受管节点,并将日志或配置取回控制节点。

安全传输文件:使用 Ansible Copy 和 Fetch 模块

移动文件是您需要掌握的第一个实用 Ansible 任务:将配置文件推送到服务器、收集日志文件,或在更改前备份远程文件。copyfetch 模块清晰地处理了这两个方向。

本指南使用临时命令,因此您无需编写完整的剧本即可运行一次性传输。当您希望任务可重复时,相同的模块参数也适用于剧本。

前提条件

在执行以下示例之前,请确保您已具备以下条件:

  1. Ansible 控制节点: 安装了 Ansible 的机器。
  2. 清单文件: 一个可操作的清单文件(例如 /etc/ansible/hosts),定义了您的受管节点。
  3. 连接性: 已配置到远程主机的 SSH 密钥访问。

所有示例均假定目标组在清单中名为 webservers

理解用于文件传输的临时命令

临时命令是直接从终端执行的单行命令,非常适合不需要永久剧本的快速任务。基本结构是:

ansible <主机组> -m <模块名> -a "key=value key2=value2 ..."

对于文件传输,我们使用 -m copy-m fetch 模块名称,并使用 -a 标志传递必需参数。

copy 模块:将文件推送到远程节点

copy 模块用于将位于 Ansible 控制机器 上的文件传输到一个或多个 受管节点。这是部署配置文件、脚本或小型资产的标准方法。

copy 的关键参数

copy 模块需要两个基本参数,并接受几个用于配置管理的可选参数:

参数 描述 必需? 示例值
src Ansible 控制机器上的本地文件路径。对于临时命令,绝对路径最清晰。 /tmp/config.conf
dest 文件在远程受管节点上的放置路径。 /etc/app/config.conf
owner 应在远程节点上拥有该文件的用户名。 nginx
group 应在远程节点上拥有该文件的组名。 www-data
mode 为目标文件设置的权限(八进制)。 0644
backup 如果为 yes,则在覆盖原始文件之前创建备份文件。 yes

示例 1:简单文件部署

假设您本地有一个自定义的每日消息(motd)文件,并希望将其推送到所有 Web 服务器。

# 本地文件路径:/home/user/ansible/motd_banner
# 远程目标路径:/etc/motd

ansible webservers -m copy -a "src=/home/user/ansible/motd_banner dest=/etc/motd"

示例 2:设置权限和所有权

如果您要部署一个安全配置文件,必须指定所有者、组和受限权限(例如,只有所有者可以读/写)。

# 部署应用程序配置文件,由 'app_user' 拥有,组为 'devops',
# 仅所有者具有读/写权限(0600)。

ansible webservers -m copy -b -a "src=/tmp/app_settings.yaml dest=/etc/app/settings.yaml owner=app_user group=devops mode=0600"

关于 -b 的说明: 当远程目标需要提升权限(例如写入 /etc)时,必须使用 -b(或 --become)标志。

fetch 模块:从远程节点检索文件

fetch 模块执行与 copy 相反的操作:它将文件从 受管节点 取回到 Ansible 控制机器。这对于备份配置文件、检索日志或收集诊断信息非常有用。

fetch 的关键参数

fetch 模块需要远程节点上的源文件和控制机器上的目标 目录

参数 描述 必需? 示例值
src 远程受管节点上文件的绝对路径。 /var/log/nginx/error.log
dest 控制机器上保存文件的 目录 的绝对路径。 /tmp/backups/logs
flat 如果为 yes,生成的文件名将不包含主机名结构(从多个主机获取时不推荐)。 no(默认)

关键区别:目标结构

copy 模块不同,fetch 模块会根据远程主机名自动创建一个结构化的子目录路径,以防止从多个服务器检索文件时发生文件名冲突。

控制机器上的结果路径将如下所示:

<dest>/<hostname>/<src>

例如,从 host1 获取 /etc/nginx/nginx.conf/tmp/backups 将得到:

/tmp/backups/host1/etc/nginx/nginx.conf

示例 3:检索远程配置备份

要将所有 Web 服务器的运行配置文件检索到本地备份目录:

# 从所有 Web 服务器检索 nginx.conf 到本地目录 /tmp/config_backups

ansible webservers -m fetch -a "src=/etc/nginx/nginx.conf dest=/tmp/config_backups"

运行此命令后,如果您目标是 webserver1webserver2,您的本地目录结构将是:

/tmp/config_backups/
├── webserver1
│   └── etc
│       └── nginx
│           └── nginx.conf
└── webserver2
    └── etc
        └── nginx
            └── nginx.conf

示例 4:检索单个文件而不带主机结构(flat=yes

如果您完全确定只从单个主机获取文件,或者只需要文件内容(而不是来源结构),可以使用 flat=yes。这将导致文件直接放置在目标文件夹中,并以原始远程文件名命名。

# 从单个主机检索本地健康状态报告,直接保存。

ansible webserver1 -m fetch -a "src=/tmp/health_status.txt dest=/tmp/reports flat=yes"

# 结果路径:/tmp/reports/health_status.txt

警告: 仅在目标是单个主机或您打算在后续运行中覆盖文件时使用 flat=yes,因为 Ansible 不会阻止冲突。

最佳实践和安全注意事项

小的文件传输错误可能演变成生产事故,尤其是当文件落入 /etc 或包含机密信息时。

始终使用 copy 设置权限

切勿在未明确定义 modeowner 的情况下推送配置文件。如果您依赖远程系统的默认 umask,敏感文件(如 SSH 密钥或数据库凭据)可能会获得过于宽松的访问权限。

# 不良实践(模式源自 umask)
- name: 部署不安全的密钥
  ansible.builtin.copy:
    src: private.key
    dest: /etc/app/private.key

# 良好实践(明确限制访问)
- name: 部署安全密钥
  ansible.builtin.copy:
    src: private.key
    dest: /etc/app/private.key
    mode: '0600'
    owner: root

对关键更改使用 backup=yes

当使用 copy 覆盖现有的关键文件(例如 /etc/sudoers)时,请包含 backup=yes。Ansible 将在覆盖文件之前在远程节点上创建一个带时间戳的备份副本,从而提供简单的回滚选项。

对于大型传输考虑使用 synchronize

虽然 copyfetch 适用于快速操作和小文件,但对于大型目录树或高效的增量传输,请使用 ansible.posix.synchronize。它封装了 rsync,因此控制节点和目标环境需要正确的 rsync 和 SSH 访问。

要点

当源文件在控制节点上而目标在受管节点上时,使用 copy。当源文件在受管节点上而您希望将文件保存在本地时,使用 fetch

模块 方向 临时命令示例
copy 控制节点 -> 受管节点 ansible all -m copy -a "src=/local/file dest=/remote/path mode=0644"
fetch 受管节点 -> 控制节点 ansible all -m fetch -a "src=/remote/file dest=/local/dir"

对于单台服务器,flat=yes 可以使获取的文件更易于读取。对于一组服务器,请保留默认的基于主机的目录结构,这样一台主机的日志就不会覆盖另一台的日志。