如何在 Ansible 中创建带内容的文件

AnsibleAnsibleBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

Ansible 是一个强大的 IT 自动化工具,它简化了基础设施管理。在这个实践实验(hands-on lab)中,你将学习如何使用 Ansible 在目标系统上创建具有特定内容的文件。通过完成这个实验,你将理解 Ansible 文件管理的基础知识,并能够在自己的基础设施中实现自动化的文件创建。

安装和设置 Ansible

在开始使用 Ansible 创建文件之前,我们需要在系统上安装和配置它。让我们设置我们的环境:

安装 Ansible

首先,我们将更新软件包列表并在我们的 Ubuntu 22.04 系统上安装 Ansible:

sudo apt update
sudo apt install -y ansible

运行这些命令后,你应该看到输出,表明 Ansible 已经成功安装。让我们验证安装:

ansible --version

你应该看到类似这样的输出:

ansible [core 2.12.0]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.10.x (default, ...) [GCC 11.2.0]
  jinja version = 3.0.3
  libyaml = True

创建一个简单的 Ansible Inventory(清单)

Ansible 使用一个 inventory 文件来定义它将要管理的 hosts(主机)。对于这个实验,我们将创建一个本地 inventory,其中包括我们自己的机器:

  1. 为我们的 Ansible 项目创建一个新目录:
mkdir -p ~/project/ansible-files
cd ~/project/ansible-files
  1. 使用 VSCode 创建一个 inventory 文件:
    • 点击 WebIDE 中的 Explorer(资源管理器)图标
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 inventory
    • 将以下内容添加到文件中:
[local]
localhost ansible_connection=local

这个 inventory 文件告诉 Ansible 在本地机器上运行命令,而无需使用 SSH。

  1. 在同一目录中创建一个简单的 ansible.cfg 文件:
    • 点击 WebIDE 中的 Explorer(资源管理器)图标
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 ansible.cfg
    • 将以下内容添加到文件中:
[defaults]
inventory = ./inventory
host_key_checking = False
  1. 让我们通过运行一个简单的 Ansible 命令来验证我们的设置:
cd ~/project/ansible-files
ansible local -m ping

你应该看到类似这样的输出:

localhost | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

这确认了 Ansible 已正确安装并配置为在你的本地机器上运行命令。

使用 Ansible Playbook 创建带有内容的文件

现在我们已经设置好了 Ansible,让我们学习如何创建带有内容的文件。Ansible 提供了几个用于管理文件的模块,在这个步骤中,我们将重点关注 copy 模块。

理解 Ansible Playbook

Ansible Playbook 是 YAML 文件,描述了要在目标主机上执行的一组任务。每个任务都使用一个特定的 Ansible 模块来执行一个操作。

让我们创建第一个 playbook 来创建一个带有内容的文件:

  1. 在 WebIDE 中,在 ~/project/ansible-files 目录中创建一个新文件:
    • 右键单击该目录并选择 "New File"(新建文件)
    • 将文件命名为 create_file.yml
    • 添加以下内容:
---
- name: Create a file with content
  hosts: local
  tasks:
    - name: Create a simple text file
      copy:
        dest: "~/project/hello.txt"
        content: |
          Hello from Ansible!
          This file was created using the Ansible copy module.
          Current date: {{ ansible_date_time.date }}

让我们理解一下这个 playbook 的作用:

  • hosts: local 行指定此 playbook 将在 inventory 中的 local 组的主机上运行。
  • tasks 部分包含要执行的任务列表。
  • copy 模块用于创建带有内容的文件。
  • dest 参数指定文件的目标路径。
  • content 参数包含将要写入文件的文本内容。
  • {{ ansible_date_time.date }} 是一个变量,当 playbook 运行时,它将被替换为当前日期。
  1. 现在,让我们运行 playbook:
cd ~/project/ansible-files
ansible-playbook create_file.yml

你应该看到类似这样的输出:

PLAY [Create a file with content] ***********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create a simple text file] ***********************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 让我们验证文件是否已创建并包含预期的内容:
cat ~/project/hello.txt

你应该看到类似这样的输出:

Hello from Ansible!
This file was created using the Ansible copy module.
Current date: 2023-08-15

日期将反映你运行 playbook 时的当前日期。

Ansible 中的幂等性

幂等性是 Ansible 的一个关键特性——多次运行同一个 playbook 应该产生相同的结果。让我们再次运行 playbook,看看幂等性是如何发挥作用的:

ansible-playbook create_file.yml

这次,你应该看到 "changed" 计数为 0:

PLAY [Create a file with content] ***********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create a simple text file] ***********************************************
ok: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

这表明 Ansible 识别到文件已经存在,并且内容正确,因此它不会再次修改它。

在 Ansible 中使用变量和模板

在这一步中,我们将探讨如何使用变量和模板,通过 Ansible 创建更具动态性的文件。

使用变量

变量使你的 playbooks 更加灵活和可重用。让我们创建一个使用变量来创建配置文件的 playbook:

  1. 在 WebIDE 的 ~/project/ansible-files 目录中创建一个新文件:
    • 右键单击该目录并选择 "New File"(新建文件)
    • 将文件命名为 variables_demo.yml
    • 添加以下内容:
---
- name: Create files using variables
  hosts: local
  vars:
    app_name: "MyApplication"
    app_version: "1.0.0"
    port_number: 8080
    log_level: "INFO"
  tasks:
    - name: Create config file with variables
      copy:
        dest: "~/project/app_config.ini"
        content: |
          ## Configuration for {{ app_name }}
          ## Generated by Ansible

          [application]
          name = {{ app_name }}
          version = {{ app_version }}

          [server]
          port = {{ port_number }}
          log_level = {{ log_level }}

在这个 playbook 中:

  • vars 部分定义了可以在整个 playbook 中使用的变量。
  • 变量使用 {{ variable_name }} 语法引用。
  • copy 模块用于创建包含这些变量内容的文件。
  1. 现在,让我们运行 playbook:
cd ~/project/ansible-files
ansible-playbook variables_demo.yml

你应该看到类似这样的输出:

PLAY [Create files using variables] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create config file with variables] ***************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 让我们检查生成文件的内容:
cat ~/project/app_config.ini

你应该看到类似这样的输出:

## Configuration for MyApplication
## Generated by Ansible

[application]
name = MyApplication
version = 1.0.0

[server]
port = 8080
log_level = INFO

使用 Jinja2 模板

对于更复杂的文件内容,Ansible 支持 Jinja2 模板。让我们创建一个模板文件并在 playbook 中使用它:

  1. 创建 templates 目录:
mkdir -p ~/project/ansible-files/templates
  1. 在 WebIDE 中创建一个模板文件:
    • 导航到 ~/project/ansible-files/templates 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 web_config.j2
    • 添加以下内容:
## Web Server Configuration
## Generated by Ansible on {{ ansible_date_time.date }}

server {
    listen {{ web_port }};
    server_name {{ server_name }};

    location / {
        root {{ doc_root }};
        index index.html;
    }

    {% if enable_ssl %}
    ## SSL Configuration
    ssl_certificate {{ ssl_cert }};
    ssl_certificate_key {{ ssl_key }};
    {% endif %}
}
  1. 现在创建一个使用此模板的 playbook:
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 template_demo.yml
    • 添加以下内容:
---
- name: Create files using templates
  hosts: local
  vars:
    web_port: 80
    server_name: "example.com"
    doc_root: "/var/www/html"
    enable_ssl: true
    ssl_cert: "/etc/ssl/certs/example.com.crt"
    ssl_key: "/etc/ssl/private/example.com.key"
  tasks:
    - name: Create web server config from template
      template:
        src: templates/web_config.j2
        dest: ~/project/web_server.conf

在这个 playbook 中:

  • 使用 template 模块代替 copy
  • src 参数指向我们的模板文件。
  • dest 参数指定创建输出文件的位置。
  • vars 部分中定义的变量将在模板中使用。
  1. 运行 playbook:
cd ~/project/ansible-files
ansible-playbook template_demo.yml

你应该看到类似这样的输出:

PLAY [Create files using templates] ********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create web server config from template] **********************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 让我们检查生成的配置文件:
cat ~/project/web_server.conf

你应该看到类似这样的输出:

## Web Server Configuration
## Generated by Ansible on 2023-08-15

server {
    listen 80;
    server_name example.com;

    location / {
        root /var/www/html;
        index index.html;
    }

    ## SSL Configuration
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;
}

注意 Jinja2 模板是如何使用我们的变量呈现的,并且由于 enable_ssl 设置为 true,因此包含了 SSL 的条件部分。

使用 Ansible 进行高级文件管理

在最后一步中,我们将探索一些使用 Ansible 的高级文件管理技术,包括文件权限、条件性文件创建以及使用多个与文件相关的模块。

设置文件权限和所有权

创建文件时,你通常需要设置特定的权限和所有权。让我们创建一个演示此功能的 playbook:

  1. 在 WebIDE 中创建一个新文件:
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 file_permissions.yml
    • 添加以下内容:
---
- name: Manage file permissions and ownership
  hosts: local
  tasks:
    - name: Create a script file with execute permissions
      copy:
        dest: ~/project/script.sh
        content: |
          #!/bin/bash
          echo "This script was created by Ansible"
          echo "Current user: $(whoami)"
          echo "Current directory: $(pwd)"
        mode: "0755"

    - name: Create a read-only configuration file
      copy:
        dest: ~/project/readonly.conf
        content: |
          ## This is a read-only configuration file
          setting1 = value1
          setting2 = value2
        mode: "0444"

在这个 playbook 中:

  • mode 参数用于设置文件权限。
  • 0755 表示所有者具有读、写和执行权限,组和其他用户具有读和执行权限。
  • 0444 表示对所有人只读。
  1. 运行 playbook:
cd ~/project/ansible-files
ansible-playbook file_permissions.yml

你应该看到类似这样的输出:

PLAY [Manage file permissions and ownership] **********************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create a script file with execute permissions] **************************
changed: [localhost]

TASK [Create a read-only configuration file] **********************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 让我们检查已创建文件的权限:
ls -l ~/project/script.sh ~/project/readonly.conf

你应该看到类似这样的输出:

-rwxr-xr-x 1 labex labex 118 Aug 15 12:34 /home/labex/project/script.sh
-r--r--r-- 1 labex labex  73 Aug 15 12:34 /home/labex/project/readonly.conf
  1. 让我们验证脚本是否可以执行:
~/project/script.sh

你应该看到类似这样的输出:

This script was created by Ansible
Current user: labex
Current directory: /home/labex/project/ansible-files

条件性文件创建

有时你只需要在满足特定条件时才创建文件。让我们创建一个演示条件性文件创建的 playbook:

  1. 在 WebIDE 中创建一个新文件:
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 conditional_file.yml
    • 添加以下内容:
---
- name: Conditional file creation
  hosts: local
  vars:
    environment: "development"
    create_debug_file: true
    create_backup: false
  tasks:
    - name: Create environment-specific configuration
      copy:
        dest: "~/project/{{ environment }}_config.yml"
        content: |
          ## Configuration for {{ environment }} environment
          debug: {{ 'enabled' if environment == 'development' else 'disabled' }}
          log_level: {{ 'DEBUG' if environment == 'development' else 'INFO' }}

    - name: Create debug log file
      copy:
        dest: ~/project/debug.log
        content: |
          ## Debug log file
          ## Created: {{ ansible_date_time.iso8601 }}
        mode: "0644"
      when: create_debug_file

    - name: Create backup directory
      file:
        path: ~/project/backup
        state: directory
        mode: "0755"
      when: create_backup

在这个 playbook 中:

  • when 指令用于任务的条件执行。
  • Jinja2 条件语句用于在文件内容中根据变量更改值。
  • file 模块用于创建目录。
  1. 运行 playbook:
cd ~/project/ansible-files
ansible-playbook conditional_file.yml

你应该看到类似这样的输出:

PLAY [Conditional file creation] **********************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create environment-specific configuration] ******************************
changed: [localhost]

TASK [Create debug log file] **************************************************
changed: [localhost]

TASK [Create backup directory] ************************************************
skipped: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

请注意,"Create backup directory"(创建备份目录)任务被跳过,因为 create_backup 设置为 false

  1. 让我们检查已创建的文件:
cat ~/project/development_config.yml
cat ~/project/debug.log
ls -la ~/project/ | grep backup

你应该看到已创建的两个文件的内容,并确认没有创建备份目录。

使用多个与文件相关的模块

Ansible 提供了几个用于文件管理的模块。让我们创建一个演示使用多个与文件相关的模块的 playbook:

  1. 在 WebIDE 中创建一个新文件:
    • 导航到 ~/project/ansible-files 目录
    • 右键单击并选择 "New File"(新建文件)
    • 将文件命名为 file_modules.yml
    • 添加以下内容:
---
- name: Demonstrate file-related modules
  hosts: local
  tasks:
    - name: Create a directory
      file:
        path: ~/project/ansible_demo
        state: directory
        mode: "0755"

    - name: Create a file using the copy module
      copy:
        dest: ~/project/ansible_demo/copied.txt
        content: "This file was created using the copy module.\n"

    - name: Create a symbolic link
      file:
        src: ~/project/ansible_demo/copied.txt
        dest: ~/project/ansible_demo/link_to_copied.txt
        state: link

    - name: Create a file with blockinfile module
      blockinfile:
        path: ~/project/ansible_demo/block.txt
        create: true
        block: |
          This is a block of text
          that will be inserted
          as a single unit.
        marker: "## {mark} ANSIBLE MANAGED BLOCK"

在这个 playbook 中:

  • file 模块与 state: directory 一起使用来创建一个目录。
  • file 模块与 state: link 一起使用来创建一个符号链接。
  • blockinfile 模块用于创建一个包含由标记注释包围的文本块的文件。
  1. 运行 playbook:
cd ~/project/ansible-files
ansible-playbook file_modules.yml

你应该看到类似这样的输出:

PLAY [Demonstrate file-related modules] ***************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create a directory] *****************************************************
changed: [localhost]

TASK [Create a file using the copy module] ************************************
changed: [localhost]

TASK [Create a symbolic link] *************************************************
changed: [localhost]

TASK [Create a file with blockinfile module] **********************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  1. 让我们验证结果:
ls -la ~/project/ansible_demo/
cat ~/project/ansible_demo/copied.txt
cat ~/project/ansible_demo/link_to_copied.txt
cat ~/project/ansible_demo/block.txt

你应该看到:

  • 一个名为 ansible_demo 的目录
  • 一个名为 copied.txt 的文件,其中包含指定的内容
  • 一个名为 link_to_copied.txt 的符号链接,指向 copied.txt
  • 一个名为 block.txt 的文件,其中包含由标记注释包围的文本块

最后一个命令的输出应该类似于:

## BEGIN ANSIBLE MANAGED BLOCK
This is a block of text
that will be inserted
as a single unit.
## END ANSIBLE MANAGED BLOCK

这演示了 Ansible 文件管理功能的通用性。

总结

祝贺你完成了这个 Ansible 文件管理实验。你已经学习了几个重要的概念和技术:

  1. 如何安装和配置 Ansible 以进行基本的自动化任务
  2. 使用 copy 模块创建具有特定内容的文件
  3. 使用变量使你的文件内容具有动态性
  4. 使用 Jinja2 模板进行更复杂的文件生成
  5. 设置文件权限和所有权
  6. 根据变量实现条件性文件创建
  7. 使用各种 Ansible 模块进行不同的文件管理任务

这些技能为自动化你的基础设施中的文件管理任务奠定了坚实的基础。借助 Ansible,你可以确保在多台服务器上保持一致的文件内容,以受控的方式应用更改,并维护可审计的配置记录。

要继续你的 Ansible 学习之旅,请考虑探索更高级的主题,例如角色(roles)、playbook 组织以及将 Ansible 与其他 DevOps 工具集成。