Ansible - Setting up Apache web server
Ansible 2.0
Ansible is one of the competing technologies for configuration management tool, such as Chef, Puppet, Fabric, and Salt.
Unlike other alternatives, Ansible can be installed on our local machine, and uses SSH to communicate with each remote host.
This allows it to be incredibly fast at configuring new servers, as there are no prerequisite packages to be installed on each new server.
In this post, we'll briefly discuss Python technologies: Ansible and Fabric.
One difference between Fabric and Ansible is that while Fabric will get us results relatively quickly, Ansible requires a bit more steep learning curve.
"Ansible is generally much more powerful since it provides much deeper and more complex semantics for modeling multi-tier infrastructure, such as those with arrays of web and database hosts. From an operator's perspective, Fabric has a more literal and basic API and uses Python for authoring, while Ansible consumes YAML and provides a richness in its behavior."- DevOps Technologies: Fabric or Ansible
In this section, we will configure Ansible to manage our remote servers.
First, we need to tell Ansible which hosts to talk to via Ansible hosts file.
The Ansible hosts file contains groups of hosts. This is located in /etc/ansible/hosts which is applied globally across systems.
In this tutorial, we're going to use local hosts file instead of the global hosts file.
Ansible always looks for an ansible.cfg file in the local directory that it is being run from, and if found will override the global configuration with the local values.
So, we need to tell Ansible that we want to use a hosts file in the local directory, rather than the global one.
Here are the files we need in this section:
ansible-apache |-- ansible.cfg |-- apache.yml |-- hosts
ansible.cfg file:
[defaults] hostfile = hosts
The hostfile is the configurition option with the value of hosts, within the [defaults] group.
hosts file:
[apache] 172.17.0.2 ansible_ssh_user=ubuntu
It specifies a host group called apache which contains one host (172.17.0.2).
The ubuntu is our SSH username.
Now ansible should be able to connect to our server.
The ansible_ssh_user=username component is optional if we are running Ansible as the same user as the target host.
To test if ansible is working, we can check if ansible can talk to our host.
We can run a basic ansible command via ping module.
Basic usage of the ansible command accepts the host group which is apache, and the module name which is ping:
ansible <group> -m <module>
Let's run the ping command:
$ ansible apache -m ping 172.17.0.2 | SUCCESS => { "changed": false, "ping": "pong" }
In the previous section, we used one of the simplest modules, ping.
Ansible playbook allows us to run more complicated modules easily.
A very basic Ansible playbook is a single yaml file which specifies the host group and one or more tasks to be run on the hosts within the specified group.
Let's start with the simplest plabook.
apache.yml:
--- - hosts: apache tasks: - name: run echo command command: /bin/echo hello k!
- The hosts: apache declaration tells ansible that we are using the apache hosts group.
- We have one task with the name run echo command.
- The command: /bin/echo hello k! line runs the command module with the arguments /bin/echo hello k!.
The ansible-playbook command is used to run playbooks, and the simplest usage is:
$ ansible-playbook our-playbook.yml.
We can run the playbook we just created with the following command:
$ ansible-playbook apache.yml PLAY [apache] ****************************************************************** TASK [setup] ******************************************************************* ok: [172.17.0.2] TASK [run echo command] ******************************************************** changed: [172.17.0.2] PLAY RECAP ********************************************************************* 172.17.0.2 : ok=2 changed=1 unreachable=0 failed=0
Unlike the direct command we used in previous section, playbooks do not return the output of the module.
This means that playbooks are better suited for tasks where we don't need to see the output.
While the ansible does not print output, it will tell us if there was an error during the execution of a module.
Now that we can run the simple playbook, we will write the task to install the Apache web server.
To install Apache on Ubuntu, we use Ansible's apt module.
Here is the updated apache.yml:
--- - hosts: apache sudo: yes tasks: - name: install apache2 apt: name=apache2 update_cache=yes state=latest
sudo will be required to ensure the right privileges which is applied via the ansible-playbook command and on a per-task level.
The ansible's apt module options we're using are:
- name: The name of the package to be installed, either a single package name or a list of packages.
- state: Accepts either latest, absent, or present. Latest ensures the latest version is installed, present simply checks it is installed, and absent removes it if it is installed.
- update_cache: Updates the cache (via apt-get update) if enabled, to ensure it is up to date.
The apt line installs the apache2 package (name=apache2) and ensures we have updated the cache (update_cache=yes).
Let's run ansible-playbook:
$ ansible-playbook apache.yml --ask-sudo-pass
The --ask-sudo-pass flag will prompt us for the sudo password. This is necessary because the apt requires root privileges.
Note that the other commands we've run so far did not need root privileges.
Here is the output from the ansibl-playbook run:
SUDO password: PLAY [apache] ****************************************************************** TASK [setup] ******************************************************************* ok: [172.17.0.2] TASK [install apache2] ********************************************************* changed: [172.17.0.2] PLAY RECAP ********************************************************************* 172.17.0.2 : ok=2 changed=1 unreachable=0 failed=0
Now that Apache is installed, we need to enable a module to be used by Apache.
Here is our new apache.yml ansible-playbook:
--- - hosts: apache sudo: yes tasks: - name: install apache2 apt: name=apache2 update_cache=yes state=latest - name: enabled mod_rewrite apache2_module: name=rewrite state=present
The playbook makes sure that the mod_rewrite module is enabled for Apache by using a2enmod and restarting Apache via apache2_module module and a task handler to restart apache2.
The apache2_module module takes two options:
- name: The name of the module to enable, such as rewrite.
- state: Either present or absent, depending on if the module needs to be enabled or disabled.
Note that we need to restart apache2 after the module is enabled.
We can add a task to restart apache2, however, we don't want that to run every time we apply our playbook.
That's why we may want to use a task handler.
We can tell a taks to notify a handler when it has changed, and the handler only runs when the task has been changed. In this way, we can avoid restarting Apache every time we apply our playbook.
To to notify a handler we need to add the notify option into the apache2_module task, and then we can use the service module to restart apache2 in a handler.
So, updated playbook should like this:
--- - hosts: apache sudo: yes tasks: - name: install apache2 apt: name=apache2 update_cache=yes state=latest - name: enabled mod_rewrite apache2_module: name=rewrite state=present notify: - restart apache2 handlers: - name: restart apache2 service: name=apache2 state=restarted
Let's run with the new playbook:
$ ansible-playbook apache.yml --ask-sudo-pass SUDO password: PLAY [apache] ****************************************************************** TASK [setup] ******************************************************************* ok: [172.17.0.2] TASK [install apache2] ********************************************************* ok: [172.17.0.2] TASK [enabled mod_rewrite] ***************************************************** changed: [172.17.0.2] RUNNING HANDLER [restart apache2] ********************************************** changed: [172.17.0.2] PLAY RECAP ********************************************************************* 172.17.0.2 : ok=4 changed=2 unreachable=0 failed=0
Ansible 2.0
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization