官术网_书友最值得收藏!

Breaking down the Ansible components

Ansible allows you to define policies, configurations, task sequences, and orchestration steps in playbooks—the limit is really only your imagination. A playbook can be executed to manage your tasks either synchronously or asynchronously on a remote machine, although you will find that most examples are synchronous. In this section, you will learn about the main components of Ansible and understand how Ansible employs those components to communicate with remote hosts.

In order to understand the various components, we first need an inventory to work from. Let's create an example one, ideally with multiple hosts in it—this could be the same as the one you created in the previous section. As discussed in that section, you should populate the inventory with the hostnames or IP addresses of the hosts that you can reach from the control host itself:

remote1.example.com
remote2.example.com
remote3.example.com

To really understand how Ansible—as well as its various components—works, we first need to create an Ansible playbook. While the ad hoc commands that we have experimented with so far are just single tasks, playbooks are organized groups of tasks that are (usually) run in sequence. Conditional logic can be applied and in any other programming language, they would be considered your code. At the head of the playbook, you should specify the name of your play—although this is not mandatory, it is good practice to name all your plays and tasks as without this, it would be quite hard for someone else to interpret what the playbook does, or even for you to if you come back to it after a period of time. Let's get started with building our first example playbook:

  1. Specify the play name and inventory hosts to run your tasks against at the very top of your playbook. Also, note the use of ---, which denotes the beginning of a YAML file (Ansible playbooks that are written in YAML):
---
- name: My first Ansible playbook
hosts: all
  1. After this, we will tell Ansible that we want to perform all the tasks in this playbook as a superuser (usually root). We do this with the following statement (to aid your memory, think of become as shorthand for become superuser):
  become: yes
  1. After this header, we will specify a task block that will contain one or more tasks to be run in sequence. For now, we will simply create one task to update the version of Apache using the yum module (because of this, this playbook is only suitable for running against RHEL-, CentOS-, or Fedora-based hosts). We will also specify a special element of the play called a handler. Handlers will be covered in greater detail in Chapter 4, Playbooks and Roles, so don't worry too much about them for now. Simply put, a handler is a special type of task that is called only if something changes. So, in this example, it restarts the web server, but only if it changes, preventing unnecessary restarts if the playbook is run several times and there are no updates for Apache. The following code performs these functions exactly and should form the basis of your first playbook:
  tasks:
- name: Update the latest of an Apache Web Server
yum:
name: httpd
state: latest
notify:
- Restart an Apache Web Server

handlers:
- name: Restart an Apache Web Server
service:
name: httpd
state: restarted

Congratulations, you now have your very first Ansible playbook! If you run this now, you should see it iterate through all the hosts in your inventory, as well as on each update in the Apache package, and then restart the service where the package was updated. Your output should look something as follows:

$ PLAY [My first Ansible playbook] ***********************************************

TASK [Gathering Facts] *********************************************************
ok: [remote2.example.com]
ok: [remote1.example.com]
ok: [remote3.example.com]

TASK [Update the latest of an Apache Web Server] *******************************
changed: [remote2.example.com]
changed: [remote3.example.com]
changed: [remote1.example.com]

RUNNING HANDLER [Restart an Apache Web Server] *********************************
changed: [remote3.example.com]
changed: [remote1.example.com]
changed: [remote2.example.com]

PLAY RECAP *********************************************************************
remote1.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remote2.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remote3.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

If you examine the output from the playbook, you can see the value in naming not only the play but also each task that is executed, as it makes interpreting the output of the run a very simple task. You will also see that there are multiple possible results from running a task; in the preceding example, we can see two of these results—ok and changed. Most of these results are fairly self-explanatory, with ok meaning the task ran successfully and that nothing changed as a result of the run. An example of this in the preceding playbook is the Gathering Facts stage, which is a read-only task that gathers information about the target hosts. As a result, it can only ever return ok or a failed status, such as unreachable, if the host is down. It should never return changed.

However, you can see in the preceding output that all three hosts need to upgrade their Apache package and, as a result of this, the results from the Update the latest of an Apache Web Server task is changed for all the hosts. This changed result means that our handler variable is notified and the web server service is restarted.

If we run the playbook a second time, we know that it is very unlikely that the Apache package will need upgrading again. Notice how the playbook output differs this time:

PLAY [My first Ansible playbook] ***********************************************

TASK [Gathering Facts] *********************************************************
ok: [remote1.example.com]
ok: [remote2.example.com]
ok: [remote3.example.com]

TASK [Update the latest of an Apache Web Server] *******************************
ok: [remote2.example.com]
ok: [remote3.example.com]
ok: [remote1.example.com]

PLAY RECAP *********************************************************************
remote1.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remote2.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
remote3.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

You can see that this time, the output from the Update the latest of an Apache Web Server task is ok for all three hosts, meaning no changes were applied (the package was not updated). As a result of this, our handler is not notified and does not run—you can see that it does not even feature in the preceding playbook output. This distinction is important—the goal of an Ansible playbook (and the modules that underpin Ansible) should be to only make changes when they need to be made. If everything is all up to date, then the target host should not be altered. Unnecessary restarts to services should be avoided, as should unnecessary alterations to files. In short, Ansible playbooks are (and should be) designed to be efficient and to achieve a target machine state.

This has very much been a crash course on writing your first playbook, but hopefully, it gives you a taste of what Ansible can do when you move from single ad hoc commands through to more complex playbooks. Before we explore the Ansible language and components any further, let's take a more in-depth look at the YAML language that playbooks are written in.

主站蜘蛛池模板: 南雄市| 威信县| 莎车县| 确山县| 三穗县| 仪征市| 绍兴市| 西畴县| 高安市| 连州市| 城固县| 榆林市| 井陉县| 客服| 东乡| 平利县| 柳州市| 响水县| 静海县| 隆子县| 蒙城县| 陆良县| 顺昌县| 白河县| 和顺县| 孟津县| 西充县| 酒泉市| 忻州市| 盘锦市| 汉寿县| 曲松县| 高碑店市| 平度市| 岳阳市| 那坡县| 保山市| 曲阳县| 岳阳市| 平利县| 横山县|