如何创建 Ansible 模板以节省配置时间

管理多台服务器和环境的配置是使用Ansible的一个巨大好处。但是当配置文件在服务器之间有所不同时会发生什么呢?与其为每台服务器或环境创建单独的配置文件,不如研究一下Ansible模板。

在本教程中,您将学习什么是Ansible模板,它们如何工作以及如何使用Ansible模板模块来节省大量时间。

先决条件

本文将是一个逐步教程。如果您想跟着做,请确保您有一个Ansible控制器主机。本教程将使用Ansible v2.9.18

什么是Ansible模板?

有时您需要将文本文件传输到远程主机。这些文本文件通常是某种配置文件。例如,如果您正在使用单个服务器,您可能需要创建一个名为app.conf的配置文件,某些服务将使用它。

该配置文件可能包含与该服务器特定的信息,如主机名、IP地址等。由于你正在使用单个服务器,你可以在Ansible控制器上创建该文件,然后使用复制模块剧本中将其复制到服务器。

但是,如果你有多个需要该配置文件的web服务器,每个服务器都有其特定的值怎么办?你不能只是将配置文件复制到所有机器;它只是为具有特定主机名、IP地址等的单个服务器构建的。你需要一个Ansible模板。

Ansible模板允许你定义带有变量的文本文件,而不是静态值,然后在剧本运行时替换这些变量。

Ansible模板是什么样子的呢?

Ansible模板是一个使用Jinja2模板语言构建的文本文件,带有j2文件扩展名。一个Jinja2模板看起来就像你想放到远程主机上的文本文件一模一样。唯一的区别是,文件包含的是变量,而不是静态值。

例如,也许您需要在所有的网络服务器上获取一个名为app.conf的配置文件,其中包含对每个相应服务器 IP 地址、Ansible 主机和 Ansible 用户的引用。单个服务器的app.conf文件可能如下所示。

my_ip    = "192.168.0.1"
my_host  = "ANSBILECONTROL"
my_user  = "ansible_user"

您不能将此文件复制到每个网络服务器上,因为每个项目将是唯一的,这取决于远程主机的 IP、Ansible 控制器的主机名和 Ansible 用户。

与其静态设置这些值,Ansible 模板允许您定义在运行时解释并替换为远程主机上的变量。

下面是app.conf.j2模板文件的示例。现在您可以看到,每个静态值都已被替换为双大括号括起的变量。在这种情况下,这些变量来自Ansible facts

模板文件始终具有J2文件扩展名,并且通常与它们在目标主机上创建的文件具有相同的名称。

my_ip    = "{{ansible_default_ipv4["address"]}}"
my_host  = "{{ansible_host}}"
my_user  = "{{ansible_user}}"

如何在远程主机上创建模板文件?

创建模板后,您需要将该模板文件传输到远程主机,并将其“转换”为其应该看起来的实际文本文件。为此,您需要在 playbook 中引用模板文件。

大多数 Ansible 管理员使用 copy 模块 将文件传输到远程主机,但如上所述,这在使用模板时并不可行。

下面你可以看到一个简单的例子,参考自一个剧本,该剧本将 app.conf 文件复制到所有剧本目标主机上的 /opt 目录中。

- name: copy file from local host to remote host
  copy:                               # Declaring Copy Module 
    src: "app.conf"                   # Source Location 
    dest: "/opt/app.conf"             # Destination Location on remote host

现在假设你已经将 app.conf 配置文件制作成了前一节中介绍的 app.conf.j2 模板文件,并放在了你的 Ansible 控制器上。现在你需要确保 app.conf 仍然传输到 /opt 目录,但变量已被实际值替换。

为了告诉剧本在 /opt 目录中创建 app.conf 文件,只需将 copy 引用替换为如下所示的 template。当你这样做时,Ansible 将调用 template 模块 来传输模板并用静态值替换变量。

- name: template file to remote host
  template:                 # Ansible template module
    src: "app.conf.j2"      # This is template src i.e source location 
    dest: "/opt/app.conf"   # Destination of Remote host

一旦剧本中的上述任务执行完毕,Ansible 将把 app.conf.j2 复制到远程主机的 /opt 目录中,用静态值替换其中的所有变量,并将文件重命名为 app.conf

当您提供带有目录路径的模板src时,Ansible会在 /<ansible_installation_directory>/files/ 目录中查找模板。如果您只提供文件名,Ansible将在 /<ansible_installation_directory>/templates/ 目录中查找模板。

渲染配置文件: 模板示例

现在,让我们通过演示来看看如何设置Ansible模板并使用Ansible模板模块动态生成配置文件。在此示例中,您将在名为app.conf的文件中创建一个文件,该文件位于服务器/etc目录中,服务器名为SRV1

本节中的步骤适用于任何类型的文本文件。本教程将使用配置文件作为单一示例。

1. 使用您通常用于管理Ansible的用户,通过SSH登录到Ansible控制主机。

2. 在您的主目录中创建一个文件夹,用于保存本教程的演示文件,并将工作目录更改为该文件夹。

mkdir ~/ansible_template_demo
cd ~/ansible_template_demo

3. 在看起来像下面的目录中创建一个名为app.conf.j2的模板文件。

my_ip = {{ansible_default_ipv4["address"]}}
my_host  = {{ansible_host}}
my_user  = {{ansible_user}}

您还可以在模板中使用特定于Ansible模板模块的各种变量

4. 在同一目录中创建一个名为my_playbook.yml的简单playbook。此playbook将在/etc目录中创建app.conf文件。


name: Ansible template example 
hosts: myserver 
remote_user: ubuntu   # Using Remote host as ubuntu 
tasks: 
 - name: Create the app.conf configuration file
   template:
     src: "~/ansible_template_demo/app.conf.j2"
     dest: "/etc/app.conf"
   become: true 

5. 调用Ansible playbook,以目标是SRV1的远程主机。

ansible-playbook my_playbook.yml --inventory SRV1
You should then see Ansible execute the playbook.

6. 现在确认/etc/app.conf配置文件是否存在并具有预期的值。

confirm the /etc/app.conf configuration file

使用模板模块更新文件权限

现在您已经了解了使用模板模块的基础知识,让我们进一步深入。在这个演示中,您将创建与之前显示的相同的app.conf文件。但是这一次,您将设置该文件的所有者和权限。

要更改模板模块创建的文件的权限,您必须在playbook内部使用三个参数:

  • owner – 文件所有者
  • group – 文件应属于的组
  • mode – 权限。该字符串可以用符号表示,也可以用八进制数字表示

在符号模式中,u表示“用户”,g表示“组”,o表示“其他”。

假设您仍然创建了〜/ansible_template_demo文件夹,请打开my_playbook.yml剧本,并将内容替换为以下内容。在此示例中,Ansible将使用连接变量将所有者和组设置为Ansible用户。然后,它将文件权限设置为0644,代表:

  • 所有者具有读/写权限
  • 组中的用户和其他所有人具有读权限
---
- name: Ansible file permission example
  remote_user: ubuntu
  tasks:
    - name: Create the app.conf configuration file and assign permissions
      template:
          src: "~/ansible_template_demo/app.conf.j2"
          dest: "/etc/app.conf"
	  owner: "{{ ansible_user }}"
          group: "{{ ansible_user }}"
          mode:  0644 ## OR  mode: u=rw, g=w,o=r       
      become: true

您可以在Ansible模板模块文档中找到所有可用的模板模块参数。

现在,再次执行剧本如下所示。

ansible-playbook my_playbook.yml --inventory SRV1

现在,您可以看到app.conf已分配了预期的文件权限。

app.conf

使用循环模板化多个文件

有时单个文件不足够;您需要在远程主机上添加多个文件。在这种情况下,您可以使用模板模块与循环。使用loop参数定义循环,可以添加存储在目录中的多个文本文件。

假设您仍然创建了〜/ansible_template_demo文件夹,您应该已经有app.conf.j2在其中。

1. 如下所示,在〜/ansible_template_demo文件夹中创建第二个模板文件,名为app2.conf.j2

 template_host = "{{ template_host }}"
 template_uid = "{{ template_uid }}"
 template_path = "{{ template_path }}"
 template_fullpath = "{{ template_fullpath }}"
 template_run_date = "{{ template_run_date }}"

2. 打开my_playbook.yml书并用下面的YAML替换所有内容。这个剧本使用{{item}}变量来表示循环处理中的每个模板文件。loop参数然后定义循环要处理的每个模板文件。

---
- name: Ansible file permission example 
  remote_user: ubuntu 
  tasks: 
   - name: Create the app.conf configuration file and assign permissions 
     template:   
        src: "~/ansible_template_demo/{{item}}.j2"    # 遍历2个模板
        dest: "/etc/{{item}}"
        owner: "{{ ansible_user }}"   
        group: "{{ ansible_user }}"   
        mode:  0644 ## 或者 模式: u=rw, g=w,o=r
     become: true     
     loop: # 告诉模板模块找到每个这样的模板并处理
      - app1.conf 
      - app2.conf 

3. 现在再次运行剧本。ansible-playbook my_playbook.yml --inventory SRV1

ansible-playbook my_playbook.yml --inventory SRV1
Notice now that Ansible sees each template file and processes them accordingly.

结论

Ansible模板和模板模块可以为你节省大量时间,并在你所有的远程主机上创建动态文本文件。复制模块提供了类似的功能,但如果需要创建动态文本文件,模板模块是你的好朋友。

Source:
https://adamtheautomator.com/ansible-template/