使用 lineinfile 和 blockinfile 编辑文件还是使用模板复制整个文件?

Edit files using lineinfile and blockinfile or just copy the entire file using template?

我开始使用 Ansible 来编写一个剧本,为我们的应用程序部署一个暂存环境。 我试图了解对文件应用更改的最佳做法是在控制机器上本地更改它们,然后将它们传播到远程服务器,还是应该在剧本中操作文件。

在可读性和文档方面,通过 playbook 操作文件似乎更好,并且在整个配置过程中将整个配置过程保持在一个工具中。 另一方面,更改本地服务器上的文件更容易、更快捷。

解决这些问题的最佳方法是什么?

谢谢, 亚龙.

欢迎使用 Ansible!

我认为您应该看看模板。切勿在本地更改文件并部署它们。您的部署不应在本地更改任何文件!

如果您有一个配置文件,请为此文件编写一个模板并在其中呈现一些变量以更改已部署应用程序的配置。模板模块会将文件直接呈现到您的服务器。

使用 lineinfileblockinfile (ansible > 2.0)。它更清洁、便携,并且可以 运行 从任何控制机器。但是当块很大时会有例外。

模板应该是您的首选。它们使用起来更简单,而且您知道一旦剧本 运行.

主机将具有准确的配置

当我有一个遗留系统对我需要保留的许多主机上的文件进行了许多更改时,我发现自己会使用 lineinfileblockinfile 作为后备。

尽可能将模板渲染到 linux 上的配置目录。例如。不要在 /etc/sudoers 上使用 lineinfile 来添加管理员帐户,将带有帐户的模板渲染到 /etc/sudoers.d/administrators

正如其他答案已经告诉您的那样,copytemplate 模块是使用 Ansible 操作配置文件的首选方式。

它们允许您预先准备整个文件,然后将其移动到您的服务器(它们之间的区别是 template 模块允许您使用变量,而 copy 模块复制文件原样)。

由于您可以完全控制该文件,因此没有任何意外。

但是,有些情况(通常)禁止使用这些模块:

  • 不同角色操作同一个文件
  • 处理遗留系统
  • 不同服务器需要不同版本的文件(在某种程度上)

在这种情况下,我喜欢以防弹的方式使用lineinfile模块:

  • 首先删除除您要添加的指令之外所有出现的指令
  • 然后在特定的地方添加该行

sshd_config文件为例。您可能需要确保您的服务器只侦听 IP 地址 1.2.3.4:

- name: Remove lines with unwanted occurrences of ListenAddress
  lineinfile: dest=/etc/ssh/sshd_config
              regexp="^ListenAddress (?!1\.2\.3\.4)"
              state=absent

- name: Listen on 1.2.3.4
  lineinfile: dest=/etc/ssh/sshd_config
              line="ListenAddress 1.2.3.4"
              insertafter="^#?AddressFamily"

第一个任务删除所有未指定我们想要的 IP 的 ListenAddress(使用称为 negative lookahead 的正则表达式结构)。

然后第二个任务直接在以 AddressFamily 开头的行之后插入正确的指令 (ListenAddress 1.2.3.4)(注释或不注释)。

这样,您的任务保持幂等,并且您可以确定文件中没有您不知道的 ListenAddress 指令。

如果您需要更多详细信息,我写了 an article about this topic. And in case the application you are trying to deploy is written in Rails, you may be interested in Efficient Rails DevOps,我写了一本关于这个主题的书。