Ansible Tutorial: Automate and Configure Remote Linux Servers
Tags: devops, cloud, php, linux
Published: 2022-10-25 16:45:36

What if you have to remotely automate Linux servers, maybe about 200? What options do you have? You could decide to use the following;

- Shell
- Python

If you have sufficient experience in programming, you can write a Shell script or a Python script to do that for you; what if you don't know Shell or Python? You'd have to learn either one. In most cases, you may not want to go through such stress.
In this tutorial, I will be explaining the process of automating using Ansible as you'd do to a beginner, but there are some requirements to follow;

- Linux
- Vagrant (The first article in this series)
- YAML (You can learn at [Ansible YAML](https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html#yaml-syntax))


That's just about all, let's dive right in 🎶 

We have set up three Linux servers in Virtualbox using Vagrant; they all use the Ubuntu image.
- **Nodecontroller:** This is the controller server where we'll Install Ansible.
- **target01:** As its name implies, this is the target server, we'd be automating this server and **target02**. 

Let's ssh into the `nodecontroller` and Install Ansible, we'd be following the guide at [Ansible Installation Guide](https://docs.ansible.com/ansible/latest/installation_guide/installation_distros.html)

CD into where you have your `Vagrantfile`, run `vagrant status` to verify the VMs we installed in the first article then;

```
vagrant up && vagrant ssh nodecontroller
```
It starts up the VMs **AND** ssh into the nodecontroller, now to install Ansible;

Run 

```
sudo apt install ansible
```

If it can't find the package, go ahead and follow the instruction below, otherwise skip the adding the source list part;

```
echo deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main >> /etc/apt/sources.list
```
It adds the ansible source to the sources list for Ubuntu if you see a `permission denied` error even with using sudo;

Run
```
su
```
Then run the same command and `exit` when done, next;

```
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 93C4A3FD7BB9C367 
sudo apt update
sudo apt install ansible
```
This should take a few minutes, after it's done, to verify it has been installed, run;

```
ansible --version
```
You should see something like this, and then you're good to go;
![Ansible](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4eeo5yo28fmzpkqyto5.png)
## Getting started with Ansible
Ansible has three main components, namely;
- **Control node:** This is our `nodecontroller.`
- **Managed node:** This is `target01` and `target02`
- **Inventory:** This is the list of our nodes organized on the control node, as it sounds, it stores the list of nodes we want to automate. 

### Let's create an Inventory
Get the IP addresses of `target01` and `target02` by `vagrant ssh target01` into them from your host(PC), then run `ifconfig`, note them down and exit, and now SSH into your `nodecontroller.` 

```
cat > inventory.txt
```
Then paste;
```
target01 ansible_host=192.168.56.4 ansible_ssh_pass=vagrant
target02 ansible_host=192.168.56.5 ansible_ssh_pass=vagrant
```
Press Enter, then `Ctrl C` to exit, then run `cat inventory.txt` to verify the input. 

We added the `target01 and target02` to the inventory file, the `target01 and target02` are the name of the server, `ansible_host` is a variable, and we stored each server's IP address in it, `ansible_ssh_pass` stores the SSH password for each server, this shouldn't be used in production apps as it exposes your password.

### Let's ping target01
Run
```
ansible target01 -m ping -i inventory.txt
```
You should see this output if it was successful;

![Ansible ping](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jyr3qarmk9jswwq3wlj7.png)

If you can't, verify the IP address you used for `target01`, you can try pinging target02 too in the same way.

Now we've only tried connecting to a server only one at a time, using `ansible target01 -m ping -i inventory.txt`, we want to be able to run commands on multiple servers with a single command, let's edit our inventory file.

You can use nano or VIM to edit the inventory file, if you'd like to learn about the VIM editor, check out my article, [VIM for beginners](https://dev.to/kennibravo/a-beginner-guide-on-how-to-use-the-vim-editor-on-linux-or-mac-2oc6), or use nano, by running `nano inventory.txt` and edit the file to;

```
[targets]
target01 ansible_host=192.168.56.4 ansible_ssh_pass=vagrant
target02 ansible_host=192.168.56.5 ansible_ssh_pass=vagrant
```
Then `Ctrl X` to Save and Exit.

Now run;
```
ansible targets -m ping -i inventory.txt
```
You should see;

![Ansible targets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nhx3anhbg3j2vefkwme.png)

We got two outputs, this is from each target (target01 and target02).

### Quick explanation
In the `inventory.txt`, we created a group called `targets` and added the `target01 and target02` configuration; that's why we can run `ansible targets -m ping -i inventory.txt` and it runs on all servers under the `targets` group.

But there's a better way to automate tasks on Servers!

## Introduction to Ansible Playbooks
> Based on docs.ansible.com. Ansible Playbooks offer a repeatable, reusable, simple configuration management and multi-machine deployment system that is well suited to deploying complex applications. If you need to execute a task with Ansible more than once, write a playbook and put it under source control. Then you can use the playbook to push out new configurations or confirm the configuration of remote systems.

### Let's create an Ansible Playbook
```
nano Ansible-play.yml
```

Paste this;

```
- name: Play one
  hosts: targets
  tasks:
    - name: "Execute IP Check"
      command: ifconfig
      register: command_output
    - debug : var=command_output
```
Then run the playbook and attach the inventory file to it;
```
ansible-playbook exampleplaybook.yml -i inventory.txt
```
### Explanation
The whole YAML file is the playbook, under it, we have each play (activities/tasks that run on the server); we named it `Play one`, also we used `targets` as the hosts - This is our group from the inventory file, so we targetted all servers under the `targets` group. Then we have each task that will run in the server under the `tasks` list.

### The first task explanation
```
- name: "Execute IP Check"
  command: ifconfig
  register: command_output
```
We gave it a name and used the `command` module to run the `ifconfig` command, then registered the output in a variable named `command_output`. 

### The second task explanation
```
- debug : var=command_output
```
We then used the `debug` module to redirect the `command_output` to the stdout of the host (your PC).

So, in summary, we ran all the `ifconfig` commands on all the servers under the `targets` group and got their outputs. 

> **BUT there's a better way to copy files from a source(your PC) to a destination(nodecontroller) through SSH.**
SCP is the solution.. 😉 
I was hoping you wouldn't ask me the whole meaning; I forgot, lol. 

## How to use SCP
**Secure Copy(SCP)** is used to securely transfer files through the SSH protocol from one computer to another. 

You want to be able to edit your Ansible playbook on your PC(host), so you can use a text editor like VSCode; when you're done editing it, you can transfer it to the nodecontroller VM with a single command instead of using that ugly nano or copying from your host to the VM, this is a better alternative and faster and we get to learn something more.

## Install SCP Plugin in Vagrant
```
vagrant plugin install vagrant-scp
```

That's all; now we're ready to use SCP. 
### Format of the SCP command
```
vagrant scp <source> <destination>
```
In your host(PC), change the directory to where you have your ansible playbook, then run this command;



Using it;

```
vagrant scp absolute_uri_to_playbook/playbook.plays.yaml nodecontroller:/home/vagrant
```

This copies the playbook on your host to the `nodecontroller` using just a single command, so when you make new changes to the playbook on your host, rerun that same command; SCP is not only on Vagrant; you can also use it without Vagrant.

## What are Ansible Modules?
> Based on docs.ansible.com, Modules (also referred to as “task plugins” or “library plugins”) are discrete units of code that can be used from the command line or in a playbook task. Ansible executes each module, usually on the remote managed node, and collects return values.

We've used two modules so far; we used the `command` and the `debug` module, modules is the building block you build upon on playbooks, want to install apache on 250+ Ubuntu Linux server? Use the apt module for Ansible. 

## Install PHP/MYSQL and Apache on all VMs using Ansible Playbook
It's alright if you don't know PHP, follow along. Let's assume you have to configure the LAMP stack for about 200+ systems running Linux, you can do that using Ansible with a playbook; it takes just a single command.

Create a playbook in your nodecontroller and name it `playbook.plays.yaml`, you can name it anything you like. 

### In playbook.plays.yaml
```
- name: Play one
  hosts: targets
  tasks:
    - apt_repository:
        repo: ppa:ondrej/php
        state: present
      become: yes

    - name: Install Apache2
      apt:
        name: apache2
        state: present

      become: yes
    - name: Install MySQL Server
      apt:
        name: mysql-server
        state: present
      become: yes
    - name: Install PHP and others
      become: yes
      apt:
        pkg:
          - php5
          - libapache2-mod-php5
          - php5-mysql

```

> **NOTE:** Don't use PHP5 on a production app; I only used it for illustration, I was having issues installing PHP7, so I had to go with the quick one. 

### Quick explanation
We used the `targets` group as the hosts, which contains `target01` and `target02`. The first task we added adds the `ppa:ondrej/php` repository using the `apt_repository` module, we'd have used `sudo add-apt-repository ppa:ondrej/php5` to do this on a terminal, we also used a field `become: yes`, this is used to elevate privileges, that is using sudo. 

Then we used the `apt` module to install `mysql-server`, then used a field `state: present`, this means `mysql-server should be present`, if it was already installed, it does nothing, and if it wasn't installed, it installs it, so you can run this as many times as you want.

We did same for `apache2`, in the last module, we installed a list of packages, `php5, libapache2-mod-php5, php5-mysql`.

Now you can run it. 

```
ansible-playbook playbook.plays.yaml -i inventory.txt
```
If it was successful, you should see something like;

![Ansible vagrant](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ncebnwmtrfxhymfx5y95.png)

This means you have installed PHP and MySQL on target01 and target02 without actually interacting with either of them, now imagine it was about 100 virtual machines. 

There are more to working with Ansible to this, also our PHP and MySQL setup isn't done yet, I just went through the basics in this article, maybe, just maybe in the future, I might create a complete tutorial to do that. 

This brings us to the end of this long article, I hope you enjoyed it, if you did, consider sharing and/or adding a Reaction, if you had any issues, you can also add a comment here, I would try my best to help.

Thanks for reading.