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

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.

主站蜘蛛池模板: 老河口市| 兰州市| 洛浦县| 柏乡县| 梅河口市| 绥宁县| 汶川县| 宝兴县| 铜陵市| 南投县| 蓬安县| 潜江市| 景洪市| 阳西县| 宜良县| 洮南市| 阿荣旗| 呈贡县| 宁津县| 清水河县| 庆阳市| 项城市| 前郭尔| 巍山| 遂溪县| 西宁市| 肃南| 宜丰县| 嘉峪关市| 广平县| 阿拉善盟| 石台县| 湘阴县| 莱西市| 仁化县| 宾川县| 正镶白旗| 海宁市| 左权县| 海城市| 德兴市|