「译文」如何在 Ansible 中复制多个文件和目录

简介: 「译文」如何在 Ansible 中复制多个文件和目录

Ansible 通过 copyfetch 模块提供了基本的复制文件和目录的功能。

您可以使用 copy 模块 将文件和文件夹从本地服务器复制到远程服务器,在远程服务器之间(仅文件)复制,更改文件的权限等。

如果您需要在替换变量后复制文件,例如具有 IP 更改的配置文件,请改用 template 模块

将文件从本地计算机复制到远程服务器

默认情况下,copy 模块将检查本地计算机上 src 参数中设置的文件。然后它将文件复制到目标路径中指定的远程计算机 dest (目标)路径。下面的示例将当前用户(在本地计算机上)的主目录中的 sample.txt 文件复制到远程服务器上的 /tmp 目录中。由于我们没有为文件指定任何权限,因此远程文件的默认权限设置为-rw-rw-r–(0664)

- hosts: blocks
  tasks:
  - name: Ansible copy file to remote server
    copy:
      src: ~/sample.txt
      dest: /tmp 
YAML

📓 备注 1:

如果该文件已存在于远程服务器上,并且和源文件的内容不同,则在运行任务时,将修改目标文件。您可以通过设置 force 参数来控制它。默认设置为yes。因此,它默认情况下会修改文件。如果您不希望在源文件不同的情况下修改文件,则可以将其设置为no。仅当远程服务器上不存在该文件时,以下任务才会复制该文件。示例如下:

- hosts: blocks
  tasks:
  - name: Ansible copy file force
    copy:
      src: ~/sample.txt
      dest: /tmp 
      force: no
YAML

📓 备注 2:

如果在本地计算机上找不到该文件,则 Ansible 将引发类似于以下的错误。

fatal: [remote-machine-1]: FAILED! => {“changed”: false, “failed”: true, “msg”: “Unable to find ‘~/sample.txt’ in expected paths.”}

将目录从本地计算机复制到远程服务器

您也可以使用 Ansible copy 模块复制文件夹 / 目录。如果 src 路径是目录,则将以递归方式复制它。这意味着将复制整个目录。

现在,有两个不同的变体。取决于是否在 src 路径的末尾使用 /字符。

第一种方法将 在远程服务器上创建一个目录 ,其名称在src 参数中设置。然后它将复制源文件夹的内容并将其粘贴到该目录。 如果你想要这个行为,那么不要在 src 参数路径后加/

下面的 Ansible 复制目录示例将首先在远程服务器的 /tmp 中创建一个名为 copy_dir_ex 的目录。查看 tmp 文件夹中会有一个 copy_dir_ex 文件夹。

- hosts: blocks
  tasks:
  - name: Ansible copy directory to the remote server
    copy:
      src:/Users/mdtutorials2/Documents/Ansible/copy_dir_ex
      dest:/Users/mdtutorials2/Documents/Ansible/tmp
output
------
Ansible-Pro:Ansible mdtutorials2$ tree tmp
tmp
└── copy_dir_ex
    ├── file1
    ├── file2
    ├── file3
    └── tmp2
        ├── file4
        └── file5
ASCIIDOC

第二种方法将仅将文件从源目录复制到远程服务器。它 不会 在远程服务器上 创建目录 。如果您想要这种行为,则 在 src 参数中的路径之后输入/

在下面的示例中,copy_dir_ex内部的文件将被复制到远程服务器的 /tmp 文件夹中。如您所见,src目录未在目标中创建。仅复制目录的内容。

- hosts: blocks
  tasks:
  - name: Ansible copy files from a directory to remote server
    copy:
      src:/Users/mdtutorials2/Documents/Ansible/copy_dir_ex/
      dest:/Users/mdtutorials2/Documents/Ansible/tmp
output
------
tmp/
├── file1
├── file2
├── file3
└── tmp2
    ├── file4
    └── file5
ASCIIDOC

📓 备注:

  1. 如果需要设置远程目录的权限,可以使用 directory_mode参数来进行设置。仅当远程计算机上不存在目录时,才设置权限。
  2. 您还可以设置目录的组和所有者。您应该将各自的名称赋值给 groupowner的参数。

在同一台远程计算机上的不同文件夹之间复制文件

您还可以在远程服务器上的各个位置之间复制文件。您必须将 remote_src 参数设置为yes

以下示例将复制远程服务器的 /tmp 目录中的 hello6 文件,并将其粘贴到 /etc/ 目录中。

- hosts: blocks
  tasks:
  - name: Ansible copy files remote to remote
    copy:
      src: /tmp/hello6
      dest: /etc
      remote_src: yes
YAML

📓 备注:

从 Ansible 2.2.1.0 开始,不支持在远程服务器中复制目录。如果尝试,将出现以下错误:

fatal: [remote-machine-1]: FAILED! => {"changed": false, "failed": true, "msg": "Remote copy does not support recursive copy of directory: /tmp/copy_dir_ex"}

使用 with_items 复制多个文件 / 目录

如果要复制多个文件,则可以使用 with_items 遍历它们。

以下示例将复制 home 目录列表给出的多个文件。

- hosts: blocks
  tasks:
  - name: Ansible copy multiple files with_items
    copy:
      src: ~/{{item}}
      dest: /tmp
      mode: 0774
    with_items:
      ['hello1','hello2','hello3','sub_folder/hello4']
YAML

复制具有不同权限 / 目的地设置的多个文件

在上述任务中,我们正在复制多个文件,但是所有文件都具有相同的权限和相同的目的地。但是有时我们想为不同的文件设置权限,或者每个文件的目标文件夹都不同。这可以通过与字典结构一起使用 with_items 来实现。

在以下任务中,我试图将 3 个文件复制到 2 个不同的文件夹中。此外,每个文件的文件权限也不同。我提供了一个字典结构,其中提到了每个文件的不同设置。

从输出中可以看到,文件已复制到给定的文件夹,并且权限设置正确。

- hosts: all
  tasks:
  - name: Copy multiple files in Ansible with different permissions
    copy:
      src: "{{ item.src }}"
      dest: "{{ item.dest }}"
      mode: "{{ item.mode }}"
    with_items:
      - { src: '/home/mdtutorials2/test1',dest: '/tmp/devops_system1', mode: '0777'}
      - { src: '/home/mdtutorials2/test2',dest: '/tmp/devops_system2', mode: '0707'}
      - { src: '/home/mdtutorials2/test3',dest: '/tmp2/devops_system3', mode: '0575'}
YAML
output
======
mdtutorials2@system01:~$ ls -lrt /tmp
drwxrwxrwx 2 root          root          4096 Oct  9 14:28 devops_system1
drwx---rwx 2 root          root          4096 Oct  9 14:28 devops_system2
mdtutorials2@system01:~$ ls -lrt /tmp2
-r-xrwxr-x 1 root root 0 Oct  9 14:33 devops_system3
ASCIIDOC

复制与 pattern(通配符)匹配的文件夹中的所有文件

如果需要复制目录中与通配符匹配的所有文件,则可以使用with_fileglob

在以下示例中,将本地计算机 / tmp 目录中所有以’hello’开头的文件复制到远程服务器。

- hosts: blocks
  tasks:
  - name: Ansible copy multiple files with wildcard matching.
    copy:
      src: "{{ item }}"
      dest: /etc
    with_fileglob:
      - /tmp/hello*
YAML

复制之前在远程服务器中创建文件备份

复制文件时,可能会发生错误。您可能会复制错误的文件,写入错误的内容等。这将造成很多麻烦。因此,如果在远程服务器上创建远程文件的备份将很有帮助。

Ansible 复制模块为此提供了一个 backup 参数。如果远程文件存在且与复制的文件不同,则将创建一个新文件。新文件将通过附加时间戳和原始文件名来命名。备份参数的默认值为no

例如,以下示例将在远程服务器的 /tmp 目录中创建 helloworld.txt 的备份。它将被命名为helloworld.txt.8925.2019-10-12@14:53:13

- hosts: blocks
  tasks:
  - name: ansible copy file backup example
    copy:
      src: ~/helloworld.txt
      dest: /tmp
      backup: yes
YAML

使用临时 (Ad-hoc) 方法复制文件

以上大多数任务也可以以 Ad-hoc 方式完成。

ansible blocks -m copy -a "src=~/sample.txt dest=/tmp" -i inventory.ini
ansible blocks -m copy -a "src=~/copy_dir_ex dest=/tmp" -i inventory.ini
ansible blocks -m copy -a "src=/tmp/hello6 dest=/tmp/hello7 remote_src=yes" -s -i inventory.ini
SHELL

将文件从远程计算机复制到本地计算机

您还可以将文件从远程服务器复制到本地计算机。这可以使用 Ansible fetch模块完成。当您要将某些日志文件从远程服务器复制到本地计算机时,这很有用。

默认情况下,将在目标目录(本地计算机)中创建一个以您正在连接的每个主机命名的目录。提取的文件将被复制到此处。如果远程服务器上不存在该文件,则默认情况下不会引发任何错误。

在以下示例中,我在 remote-server-1 上运行任务。该文件将被复制到 本地计算机的 /etc/remote-server-1/tmp 目录中。

- hosts: blocks
  tasks:
  - name: Ansible fetch files from remote server to the local machine using Ansible fetch module
    fetch:
      src: /tmp/hello2
      dest: /etc
      mode: 0774
YAML

如果您不希望出现这种情况,并且需要将文件直接复制到目标目录,则应使用 flat 参数。

- hosts: blocks
  tasks:
  - name: Ansible fetch directory example with flat parameter set
    fetch:
      src: /tmp/hello2
      dest: /tmp/
      mode: 0774
      flat: yes
YAML

📓 备注:

  1. 如果您使用 flat 参数,并且文件名不是唯一的,则每次获取文件时都会替换现有文件。
  2. 如果您希望在源文件丢失的情况下引发错误,则将 fail_on_missing 参数设置为yes。如果远程文件不存在,以下示例将引发错误。
- hosts: blocks
  tasks:
  - name: Ansible fetch example with fail_on_missing set
    fetch:
      src: /tmp/fetch.txt
      dest: /tmp/
      mode: 0774
      fail_on_missing: yes
YAML

📓 备注:

如果尝试将目标路径 dest 设置为目录,请在路径末尾添加“\。否则 Ansible 将运行该任务,就像目标路径 dest 是一个文件一样,并尝试替换它。您可能会收到以下错误:(只针对加参数 flat 的情况)

fatal: [remote-machine-1]: FAILED! => {“failed”: true, “msg”: “dest is an existing directory, use a trailing slash if you want to fetch src into that directory”}

使用 copy 模块写入文件

您还可以使用 Ansible copy 模块中的 contents 参数写入文件。以下示例将给 content 参数提供的值写入 check4.txt 文件。

- hosts: all
  tasks:
  - name: Ansible write to a file example
  - copy:
      content: |
        Content parameter example.
        Check4.txt will be created after this task is executed.
      dest: /Users/mdtutorials2/Documents/Ansible/check4.txt
      backup: yes
YAML

copy 模块的返回值

copy 模块为每个任务返回一些值。完整列表可在 Ansible 文档中找到

例:

"changed": true, 
"checksum": "98d8fb24e8b2c2cec9c5ae963bd65c3657f50b16", 
"dest": "/tmp/sample.txt", 
"gid": 0, 
"group": "root", 
"md5sum": "ce83d23d6eb6bf079e1fc5c448ea9a9f", 
"mode": "0644", 
"owner": "root", 
"size": 13, 
"src": "/home/mdtutorials2/.ansible/tmp/ansible-tmp-1489974916.02-178756727263160/source", 
"state": "file", 
"uid": 0
YAML

将查找到的文件复制

使用 find 模块递归查找 /appl/scripts/inq 下的所有符合 patterns="inq.Linux*" 的文件,并将这些文件赋值到/usr/local/bin 目录。

- hosts: lnx
  tasks:
    - find: paths="/appl/scripts/inq" recurse=yes patterns="inq.Linux*"
      register: file_to_copy
    - copy: src={{ item.path }} dest=/usr/local/sbin/
      owner: root
      mode: 0775
      with_items: "{{ files_to_copy.files }}"
YAML

find 模块的返回值如下:

Key Returned 描述
examined 类型:integer success 查找的文件系统对象数。示例: 34
files 类型:list success 找到符合指定条件的所有匹配项 示例:[{'path': '/var/tmp/test1', 'mode': '0644', '...': '...', 'checksum': '16fac7be61a6e4591a33ef4b729c5c3302307523'}, {'path': '/var/tmp/test2', '...': '...'}]
matched 类型:integer success 匹配数量 ** 示例:**14

具体解释:

  • register: file_to_copy 所有返回值注册为file_to_copy 对象
  • files_to_copy.files 即找到的符合指定条件的所有匹配项 示例:[{'path': '/var/tmp/test1', 'mode': '0644', '...': '...', 'checksum': '16fac7be61a6e4591a33ef4b729c5c3302307523'}, {'path': '/var/tmp/test2', '...': '...'}]
  • item.path: 具体的符合的文件路径,即:/var/tmp/test1 /var/tmp/test2
相关文章
Ansible 文件从远程取文件fetch和传文件到远程copy(学习笔记四)
fetch模块: copy模块: 1、从远程主机获取文件:ansible all -m fetch -a "src=/root/test.sh dest=/root/test" image.
4653 0
|
关系型数据库 MySQL Shell
|
Shell Python
Ansible yaml的语法、playbook文件例子(学习笔记十七)
1、ansible有两种调用方式,一种是临时语句,一种是yml文件调用,语法格式分别为: ansible all -m ping ansible-playbook  test.yml 2、test.yml为yaml文件,yaml使用空白、缩进、分行组织数据。
1345 0
Ansible 获取主机信息模块setup、获取文件详细信息模块stat(学习笔记十)
setup 1、获取setup的所有信息,获取的信息有上百条: ansible all -m setup "ansible_facts": { "ansible_all_ipv4_addresses": [ "172.
2533 0
|
应用服务中间件 nginx
Ansible hosts文件写法(学习笔记八)
1、正常写法,name1为别名: [test1] name1 ansible_ssh_host=192.168.1.111 ansible_ssh_user="root" ansible_ssh_pass="1234" ansible_ssh_port=22 name2 ansible_ssh_host=192.
4345 0
Ansible文件内容修改lineinfile模块(学习笔记五)
lineinfile:文件内容修改、在某行前面添加一行、在某行后面添加一行、删除某一行、末尾加入一行、替换或添加某一行 1、文件内容修改,其中regexp为要修改的源内容的正则匹配,line为修改后的内容:ansible all -m lineinfile -a "dest=/root/test.
3399 0