Reputation: 6765
I am starting to use Ansible in order to write a playbook that will deploy a staging environment for our application. I'm trying to understand if the best practice for applying changes to files are to change them locally on the control machine and then propagate them into the remote server, or whether the files should be manipulated inside the playbook.
Manipulating the files through the playbook seems better in terms of readability and documentation, as well as keeping the entire configuration process to one tool for the entire configuration process. On the other hand, changing the files on the local server is easier and faster.
What is the best way to approach these problems?
Thanks, Yaron.
Upvotes: 6
Views: 5965
Reputation: 1953
As the other answers already told you, the copy
and template
modules are the preferred way to manipulate configuration files with Ansible.
They allow you to prepare the entire file upfront and then move it to your server (the difference between them is the template
module allows you to use variables while the copy
module copies the file as it is).
Since you have complete control over the file, there are no surprises.
However, there are (more often than not) circumstances which prohibit the use of these modules:
In this case, I like to use the lineinfile
module in a bulletproof way:
As an example, take the sshd_config
file. You may want to make sure that your server listens only to the IP address 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"
The first task removes every occurrence of ListenAddress
which does not specify the IP we want (using a regular expression construct called negative lookahead).
The second task then inserts the proper directive (ListenAddress 1.2.3.4
) directly after the line that begins with AddressFamily
(comment or not).
This way, your tasks stay idempotent and you can be sure that there are no ListenAddress
directives in the file you do not know about.
If you need more detail, I wrote 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, a book I wrote about this topic.
Upvotes: 2
Reputation: 2613
Templates should be your go-to. They're simpler to work with and you know the host will have the accurate configuration once the playbook is run.
I find myself reaching for lineinfile
or blockinfile
as a fallback when I have a legacy system with many changes to the file on many hosts which I need to retain.
Whenever possible, render a template to a configuration directory on linux. E.g. don't use lineinfile
on /etc/sudoers
to add admin accounts, render a template with the accounts to /etc/sudoers.d/administrators
Upvotes: 1
Reputation: 52423
Use lineinfile
and blockinfile (ansible > 2.0)
. It is cleaner, portable and can be run from any control machine. But there are exception when the block is huge.
Upvotes: 2
Reputation: 1542
Welcome to Ansible!
I think you should have a look at Templates. Never change Files locally and deploy them. Your deployment should not change any file locally!
If you have a config file, write a template for this file and render some variables inside to change the config for the deployed application. The template module will render the file directly to your server.
Upvotes: 6