The following post discusses the Ansible architecture and Ansible deployment architecture and provides an Ansible architecture diagram. As a best practice, you don’t want your Ansible architecture that consists of playbooks and Inventory to be too specific. But on the other hand, you need to have a certain level of abstraction and keep out precise information. Therefore, to develop flexible code, you must separate site-specific information from the code, and this is done with variables in Ansible.
Keep in mind that when you develop dynamic code along with your static information, you can use this on any site with minor modifications to the variables themselves. However, there are different places you can have variables, and where you place variables, such as a play header or Inventory, will take different precedence. So, to provide site-specific code, variables can be used in your Ansible deployment architecture. However, keeping ansible variables in the Inventory itself may not be a flexible solution for the greenfield and brownfield network automation efforts.
Before you proceed, you may find the following posts helpful for pre-information:
Ansible Deployment Architecture.
- A key point: Video on Ansible automation and Ansible architecture.
In this video, we will discuss Ansible automation and Ansible architecture. In particular, Ansible Engine is run from the CLI. This is compared to a different Ansible deployment architecture with Ansible Tower, a platform approach to security. We will discuss the challenging landscape forcing us to move to automation. At the same time, it introduces Ansible playbooks, ansible variables, and other main components.
Ansible Architecture: The Drive for Automation
To move to an Ansible architecture has been driven by several megatrends. Firstly, the rise of distributed computing made the manual approach to almost anything in the IT environment obsolete. Not only because this causes many errors and mistakes, but the configuration drift from desired to the actual state was considerable. Not only is this an operational burden but also a considerable security risk. Today it’s common to deploy applications by combining multiple services that run on a distributed set of resources. As a result, there is a lot more complexity to configuration and maintenance than what we had in the past.
You have two options to implement all of this. First, you can connect up these services by, for example, manually: spinning up the servers, installing the necessary packages, and SSHing to each one, or you can go down the path of automation, in particular, automation with Ansible. So with Ansible deployment architecture, we have both the Automation Engine, the CLI, and Ansible Tower, which is more of an automation platform for enterprise-grade automation. This post focuses on Ansible Engine.
As a quick note, if you have environments with more than a few teams automating, I recommend Ansible Tower or the open-source version of AWX. This is because Ansible Tower has a 60-day trial license, while AWX is fully open-sourced and does not require a license. The open-source version of AWX could be a useful tool for your open networking journey.
A Key Point: Risky: The Manual Way.
Let me put it this way. If you are configuring manually, you will likely maintain all the settings manually. Or, more importantly, what about mitigating vulnerabilities and determining what patches or packages are installed in a large environment? With the manual approach, how can you be sure that all your servers are patched and secured? Manipulating configuration files by hand is a tedious and error-prone task. Not to mention time-consuming. Equally, performing pattern matching to make changes to existing files is risky.
A Key Point: The issue of Configuration Drift
The manual approach will result in configuration drift, where some servers will drift from the desired state. Configuration drift is caused by inconsistent configuration items across devices, usually due to manual changes and updates and not following the path of automation. Ansible is all about maintaining the desired state and eliminating configuration drift.
Components of Ansible Deployment Architecture
The Ansible architecture is based on a configuration management tool that can help alleviate these challenges. Ansible replaces the need for an operator to manually tune configuration files and does a good job in application deployment and orchestrating multi-deployment scenarios. It can also be integrated into CI/CD pipelines. In reality, Ansible is relatively easy to install and operate. However, it is not a single entity. Instead, it comprises tools, modules, and software-defined infrastructure that form the ansible toolset configured from a single host that can manage multiple hosts.
We will discuss the value of idempotency with Ansible modules later in mind. Even with the idempotency nature of modules, you can still have users of Ansible automate over each other. Ansible Tower or AWS is the recommended solution for multi-team automation efforts.
Pre-deployed infrastructure: Terraform
Ansible does not deploy the infrastructure; you could use other solutions like Terraform that are best suited for this. Terraform is infrastructure as a code tool. Ansible Engine is more of a configuration as code. The physical or virtual infrastructure needs to be there for Ansible to automate, compared to Terraform, which does all of this for you. Ansible is an easy-to-use DevOps tool that manages configuration as code has in the same configuration through any sized environment. Therefore, the size of the environment is irrelevant to Ansible.
As Ansible connectivity uses SSH that runs over TCP, there are multiple optimizations you can use to increase performance and optimize connectivity which we will discuss shortly. Ansible is often described as a configuration management tool and is typically mentioned along the same lines as Puppet, Chef, and Salt. However, there is a considerable difference in how they operate. Most notably, the installation of agents.
Ansible architecture: Agentless
The Ansible architecture is agentless and requires nothing to be installed on the managed systems. In addition, its architecture is serverless and agentless, so it has a minimal footprint. Some configuration management systems such as Chef and Puppet are “pull-based” by default. Where agents are installed, periodically check in with the central service and pull-down configuration. Ansible is agentless and does not require the installation of an agent on the target for Ansible to communicate to the target host. However, it requires connectivity from the control host to the target inventory ( which contains a list of hosts that Ansible manages) with a trusted relationship. For convenience, we can have passwordless sudo connectivity between our hosts. This allows you to log in without a password and can be a security risk if someone gets to your machines; they could have escalated privileges on all the Ansible-managed hosts.
Ansible Deployment Architecture
Ansible Architecture Key Features
Key Ansible features:
- Easy-to-Read Syntax: Ansible uses the YAML file format and Jinja2 templating. Jinja2 is the template engine for the Python programming language. Ansible uses Jinja2 templating to access variables and facts and extends the defaults of Ansible for more advanced use cases.
- Not a full programming language: Remember that Ansible is not a full-fledged programming language, but it has several good features. One of the most important of these is variable substitution or using the values of variables in strings or other variables. In addition, the variables in Ansible make the Ansible playbooks, which are like executable documents, very flexible. Variables are a powerful construct within Ansible and can be used in various ways. Nearly every single thing done in Ansible can include a variable reference. We also have dynamic variables known as facts.
- Jinja2 templating language: The defaults of Ansible are extended by the use of Jinja2 templating language. In addition, Ansible’s use of Jinja2 templating adds more advanced use cases to Ansible. And one great benefit is that it is self-documenting, so when someone looks at your playbook, it’s easy to understand, unlike a Python code or a Bash script. So not only is Ansible easy to understand, but with just a few lines of YAML, which is the language used for Ansible, you can install, let’s say, web servers on as many hosts as you like.
- Ansible Architecture: Scalability: Ansible can scale. For example, Ansible uses advanced features such as SSH multiplexing to optimize SSH performance. Some use cases manage thousands of nodes with Ansible from a single machine.
- SSH Connection: Parallel connections: We have three managed hosts, web1, web2, and web3. Ansible will make SSH connections parallel to web1, web2, and web3. It will then execute the first task on the list on all three hosts simultaneously. In this example, the first task is installing the Nginx package, so the task in the playbook would look like this. Except for Windows hosts, Ansible uses the SSH protocol to communicate with hosts. This SSH service is normally integrated with the operating system authentication stack, enabling you to take advantage of things such as Kerberos to improve authentication security. Ansible uses the same authentication methods that you will already be familiar with. SSH keys are normally the easiest way to proceed as they remove the need for users to input the authentication password every time a playbook is run.
- A key point: Optimizing SSH
Ansible uses SSH to manage hosts, and establishing an ssh connection takes time. However, you can optimize SSH with several features. Because the SSH protocol runs on top of the TCP protocol, when you make a connection to a remote host with SSH, you need to make a new TCP connection. You don’t want to open a new SSH connection for every activity. Here you can use Control Master, which allows multiple simultaneous SSH connections with a remote host using one network connection. Control Persists, also known as multiplexing, keeps a connection option for xx seconds. The pipeline allows more commands to use simultaneous SSH connections. If you recall how Ansible executes a task?
- It generates a Python script based on the module being invoked
- It then copies the python script to the host
- Finally, it executes the python script
The pipelining optimization will execute the Python scripts by piping it to the SSH sessions instead of copying git. Here we are using one SSH session instead of two. These options can be configured in Ansible.cfg, and we use the SSH_connecton section. Then you can specify how these connections are used.
A note on scalability: Ansible and modularity
Ansible scales down well because simple tasks are easy to implement and understand in playbooks. Ansible scales well because it provides mechanisms for decomposing complex jobs into smaller pieces. So we can bring the concept of modularity into playbooks as the playbook becomes more complex. I like using Tags for playbook developments that can save time and effect to test different parts of the playbook when you know certain parts are 100% working.
Security wins! No daemons and no listening agents
Once Ansible is installed, it will not add a database, and there will be no daemons to start or keep running. You only need to install it on one machine (which could easily be a laptop), and it can manage an entire fleet of remote machines from that central point. No Ansible agent is listening on a port. Therefore, when you use Ansible, there is no extra attack surface for a bad actor to play with.
This is a big win for security following one of the main security principles of reducing the attack surface. As soon as you run the ansible-playbook command, Ansible connects to the remote servers and carries out what you want it to do. By its defaults, Ansible is pretty streamlined out of the box, but you can enhance it by configuring Ansible.cfg file, to be even more automated.
Ansible Architecture: Ansible Architecture diagram.
- Ansible Inventory: Telling Ansible About Your Servers
The Ansible architecture diagram has several critical components. First, the Ansible inventory is all about telling Ansible about your servers. Ansible can manage only the servers it explicitly knows about. Ansible comes with one default server of the local host, which is the control host. You provide Ansible with information about servers by specifying them in an inventory. We usually create a directory called “inventory” to hold this information.
For example, a very simple inventory file might contain a list of hostnames. The Ansible Inventory is the system that a playbook runs against. It is a list of systems in your infrastructure that the automaton is executed against. In the following Ansible architecture diagram, you can see all the Ansible components, including modules, playbooks and plugins.
Ansible architecture diagram: Inventory highlights
These are a collection of hosts that commonly have hosts but can comprise other components such as network devices, storage arrays, and other physical and virtual appliances. It also has valuable information that can be used alongside our target using the execution. The Inventory can be simple as a text file or more dynamic where the Inventory is an executable where the data is sourced dynamically. This way, we can store data externally and be used it during runtime. So we can have a dynamic inventory via Amazon Web Service or create our dynamic.
Example: AWS EC2 External inventory script
In the above Ansible architecture diagram, you will see a connection to the cloud. If you use Amazon Web Services EC2, maintaining an inventory file might not be the best approach because hosts may come and go over time, be managed by external applications, or be affected by AWS autoscaling. For this reason, you can use the EC2 external inventory script. In addition, if your hosts run on Amazon EC2, then EC2 tracks information about your hosts for you. Ansible inventory is a flexible object; you can use multiple inventory sources simultaneously. When doing so, it is possible to mix dynamic and statically managed inventory sources in the same ansible run. Many are referring to this as an instant hybrid cloud.
Ansible deployment architecture and Ansible modules
Next within the Ansible deployment architecture, we have the Ansible modules, considered to be the main workhorse of Ansible. You use modules to perform various tasks such as installing a package, restarting a service, or copying a configuration file. Ansible modules cater to a wide range of system administration tasks. This list has the categories of the kinds of modules that you can use. There are over 3000 modules. So you may be thinking, who is looking after all of these modules? That’s where collections in the more recent versions of Ansible are doing.
Extending Ansible modules
The modules are the scripts ( that are written in Python) that come with packages with Ansible and Perform some action on the managed host. Ansible has an extensive list of modules covering many areas such as networking, cloud computing, server config, containerized, and virtualization. In addition, there are many modules to support the automation requirements you have. If no modules exist, you can create a custom module with the extensive framework of Ansible. So each task is a one-to-one correlation with the module. So, for example, a template task will use the template module.
A key point: Idempotency
Modules strive to be idempotent, allowing the module to be run repeatedly without having a negative impact. In Ansible, the input is in the form of command-line arguments to the module, and the output is delivered as JSON to STDOUT. Input is generally provided in the space-separated key=value syntax, and it’s up to the module to deconstruct these into usable data.
Most of the Ansible modules are also idempotent. Idempotent means running an Ansible playbook multiple times against a server is safe. For example, if the deploy user does not exist, Ansible will create it. If it does exist, Ansible will not do anything. This is a big improvement over the shell script approach, where running the shell script a second time might have different and potentially unintended effects.
The Use of Ansible Ad Hoc Commands
For instance, if you wanted to power off all of your labs for the weekend, you could execute a quick one-liner in Ansible without writing a playbook. With an Ad Hoc command, we can be good for running one command on a host, and it uses the modules. They are used for checking configuring on the host and are also good for learning Ansible.
Note that Ansible is the executable for ad hoc one-task executions, and ansible-playbook is the executable that will process playbooks to orchestrate multiple tasks. The opposable side of the puzzle is the playbook commands are used for more complex tasks and are better for use cases where the dependencies have to be managed. The playbook can take care of the entire application deployments and dependencies.
An Ansible Playbook can have multiple plays that can exist within an Ansible playbook that can execute on different managed assets. So an Ansible Play is all about “what am I automating.” And then, it connects to the hosts to perform the actions. Each playbook comprises one or more ‘plays’ in a list. The goal of a play is to map a group of hosts to some well-defined roles, represented by things Ansible calls tasks.
At a basic level, a task is nothing more than a call to an Ansible module. By composing a playbook of multiple ‘plays’, it is possible to orchestrate multi-machine deployments, running specific steps on all machines in the web servers group. For example, specific steps on the database server group, then more commands back on the web servers group, etc.
Once a playbook is parsed and the hosts are determined, Ansible is ready to execute a task. Tasks include a name, a module reference, module arguments, and task control directives. Task execution By default, Ansible executes each task in order, one at a time, against all machines matched by the host pattern. Each task executes a module with specific arguments. You can also use the “–start-at-task <task name> flag to tell the Ansible playbook to start a playbook in the middle of a task.
Each play contains a list of tasks. Tasks are executed in order, one at a time, against all machines matched by the host pattern before moving on to the next task. It is essential to understand that, within a play, all hosts will get the same task directives. This is because the purpose of a play is to map a selection of hosts to tasks.