安全地传输文件:使用 Ansible 的 Copy 和 Fetch 模块
使用 Ansible copy 和 fetch 临时命令将文件推送到受管节点,并将日志或配置取回控制节点。
安全传输文件:使用 Ansible Copy 和 Fetch 模块
移动文件是您需要掌握的第一个实用 Ansible 任务:将配置文件推送到服务器、收集日志文件,或在更改前备份远程文件。copy 和 fetch 模块清晰地处理了这两个方向。
本指南使用临时命令,因此您无需编写完整的剧本即可运行一次性传输。当您希望任务可重复时,相同的模块参数也适用于剧本。
前提条件
在执行以下示例之前,请确保您已具备以下条件:
- Ansible 控制节点: 安装了 Ansible 的机器。
- 清单文件: 一个可操作的清单文件(例如
/etc/ansible/hosts),定义了您的受管节点。 - 连接性: 已配置到远程主机的 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"
运行此命令后,如果您目标是 webserver1 和 webserver2,您的本地目录结构将是:
/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 设置权限
切勿在未明确定义 mode 和 owner 的情况下推送配置文件。如果您依赖远程系统的默认 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
虽然 copy 和 fetch 适用于快速操作和小文件,但对于大型目录树或高效的增量传输,请使用 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 可以使获取的文件更易于读取。对于一组服务器,请保留默认的基于主机的目录结构,这样一台主机的日志就不会覆盖另一台的日志。