Ansible Series Part 1: Intro and Getting Set Up

dos2unix

Well-Known Member
Joined
May 3, 2019
Messages
3,295
Reaction score
3,043
Credits
29,330
Ansible is a huge subject, there is no way I can begin to cover all of it in a single post. So, my thinking here, is this will likely contain a number of posts. I usually tend to write simple basic tutorials, but this one will be pretty advanced.

What is ansible? It's a python based automation tool, you can deploy software, change configurations, add users, virtually do anything you can do from the command line. Ok, then if I can already do this from the command line, why do I need ansible?

First of all, it puts it in a repeatable script. Some commands are dangerous. What if I accidentally erase a program, bring down a network interface or delete a user. By scripting it and automating it, I reduce the chances of making mistakes.

Ansible is "the" hot skill today. This is the kind of post that can change someone's career path. If you get a job because of this thread let me know and I'll send you my address so you can send me a commission check every payday :) But seriously, this is a skill in high demand right now. Some ansible admins are making anywhere from $150,000 to $200,000 (US) a year.

But the real power in ansible, is not just automation, but enterprise automation. If you are only managing one or two computers, enterprise automation may not make sense for you. But what if you are managing dozens, or hundreds of computers? I could login to all my 50 or computers and add a couple of users by manually by hand, typing in the same commands over and over 50 times and hope I don't make a typing mistake, misspell a password, or misspell their username. Adding a couple of users is just one example, what if I needed to install a program on all 50 computers? Or do a security patching update?

Ansible will let me type in something called a playbook and run it on 50 computers at the same time. I don't have to worry making mistakes on some of them, because they all ran the same exact script. Also, think of how much time this saved me. How long would it take to log in to 50 computers and add users, add patches, and install programs? It could take an entire day or longer. With ansible, I could do this in a few minutes.

I don't really want to spend a lot of time talking about how to install ansible, it's slightly different for different distros. I will breifly mention it here. For my distro it looks like this.

Code:
 dnf install -y ansible ansible-builder ansible-collection-ansible-netcommon ansible-collection-ansible-utils ansible-collection-community-general ansible-collection-kubernetes-core  ansible-collection-containers-podman ansible-packaging python3-ansible-compat python3-ansible-compat python3-ansible-lint python3-ansible-pylibssh vim-ansible  vim-syntastic-ansible ansible-core sshpass

There are more packages I didn't install, and chances are, you won't need all of these. Your distro may name some of these packages slightly differently. The only 3 packages you absolutely need here are ansible, python3-ansible-lint and sshpass. Don't worry about the others for right now. If your distro doesn't have ansible as a package, you can install it with something called pip or pip3.
Warning:: DO NOT mix vendor and pip installs of ansible. Pick one and stick with it. Mixing the two will break things. (ask me how I know)

Once you get those three installed, run this command. For now just run it on your local ansible computer.

Code:
 ansible -m setup localhost

This will probably return over 1200 lines of information, this is just some of the stuff ansible know about your computer.
Congratulations, you just ran your first ansible command. This type of output is called json. More about that later.

Now maybe 1200 lines of information is a bit much, what if I just want to see some specific information?
You can filter what you want to see.

Code:
ansible localhost -m setup -a 'filter=ansible_hostname'

Code:
ansible localhost -m setup -a 'filter=ansible_distribution*'

Code:
 ansible localhost -m setup -a 'filter=ansible_kernel'

You can even put all 3 filters in the same command.

Code:
ansible localhost -m setup -a 'filter=ansible_hostname,ansible_distribution,ansible_distribution_version,ansible_kernel'

Ok, that's it for today. We haven't even gotten to the fun stuff and playbooks yet.
 
Last edited:


You'' need two (or more) computers for this next part.

Ansible relies on two things. ssh, and python3. If you don't have those two things on the client computer, ansible won't be of much use to you. This can be two VMs, or two physical computers, or a physical computer and a VM, it really doesn't matter.
They don't have to be the same distro, but I recommend something released within the last 3 or 4 years.

You'll need to setup password-less logins for ssh.


You don't absolutely have to go password-less, but it'll make things a lot easier.

Also, you'll need either root account permissions, or sudo privileges on the client computer.
Sudo is better than root for this, but either will work.

It seems like when I first was using ansible, python2 would work, but these days you really need python3.

Finally, when you installed ansible, it should have created an /etc/ansible directory. If you're lucky
there's already an ansible.cfg here. You can look through it, but don't change anything yet.

In this /etc/ansible directory, we will create a file simply called hosts.
All it has in it, is I.P. addresses of your client computers.

Code:
cat /etc/ansible/hosts

10.0.3.5
10.0.3.7
10.0.3.22
10.0.3.45

For now that's good enough.
 
Alright, where were we. You should have an ansible server with ansible installed on it, and another computer you can ssh to with python3 on it. For now, it'll work best if they are both Linux. They don't always have to be, but there are limitations.

ansible uses something called playbooks. These are yaml files. Yaml is just the way certain things are laid out in a text file.

Here is an example. Name this gather_server_info.yml
Code:
---
- name: Gather Server Information
  hosts: 10.0.0.193
  gather_facts: yes

  tasks:

    - name: Get Uptime
      command: "uptime -p"
      register: uptime_result

    - name: Get Video Card
      shell: "lspci | grep VGA | cut -f3 -d:"
      register: shell_output
    - set_fact:
        video_card: "{{ shell_output.stdout }}"

    - name: Get Boot Disk Size
      set_fact:
        disk_size_bytes: "{{ ansible_mounts[0].size_total }}"

    - set_fact:
        disk_size_gb: "{{ (disk_size_bytes | float / 1024**3) | round(2) }}"

    - name: Create JSON Output
      set_fact:
        server_info_json: |
          {
            "hostname": "{{ ansible_nodename }}",
            "cpu_model": "{{ ansible_processor[2] }}",
            "cpu_cores": "{{ ansible_processor_vcpus }}",
            "date_time": "{{ ansible_date_time.date }}.{{ ansible_date_time.time }}",
            "disk_size": "{{ disk_size_gb }}gb",
            "ip_address": "{{ ansible_default_ipv4.address }}",
            "interface": "{{ ansible_default_ipv4.interface }}",
            "netmask": "{{ ansible_default_ipv4.netmask }}",
            "gateway": "{{ ansible_default_ipv4.gateway }}",
            "mac_address": "{{ ansible_default_ipv4.macaddress }}",
            "distro": "{{ ansible_distribution }}_{{ ansible_distribution_version }}",
            "kernel": "{{ ansible_kernel }}",
            "selinux": "{{ ansible_selinux.status }}",
            "uptime": "{{ uptime_result.stdout }}",
            "memory": "{{ ansible_memtotal_mb }}mb",
            "video": "{{ video_card }}",
            "python_version": "{{ ansible_python_version }}",
          }

    - name: Print JSON Output
      debug:
        var: server_info_json

Every playbook will look similar to this.

Code:
---
- name: Name of my playbook
  hosts:  ip addresses of the clients I want to run this on.
  tasks:
    - name: Name of this task

That's the minimum you have to have in a playbook.

I usually name my playbooks something like add_a_user.yml or install_httpd.yml or maybe system_update.yml
They don't have to end in yml. Some people use yaml. It's interesting some people name their files with 4 letter
extensions, and some use three letter extensions. jpeg or jpg, htm or html, txt or text, and yml or yaml.
Ansible doesn't really care, it's just whatever your preference is.

However yaml itself is a little bit picky. Pay attention, this part is important.
You can't use tabs in a yaml file. (There are exceptions, but for now don't use tabs)

Whenever there is a new level of a section, it is indented.
Usually the section will begin with a dash "-".
The indent must be 2 spaces. (no tabs!) If there is a new section under that, it must be indented 2 more space,
a new section after that would be indented 2 more space (6 spaces, no tabs!)

A yaml file will normally start with this line.
Code:
---

3 dashes.

Now technically I am told you could three spaces, but whatever you choose you have to keep
it consistent, you can't mix 2 spaces and 3 spaces or 4 spaces. Also if you decide to use 3 spaces.
Then the next section indent would be 6 space, and the next would be 9 spaces, etc...

A playbook can go in any directory. I usually put mine in /home/username/playbooks.
They don't really need any special permissions; they shouldn't be set to executable.

If you're running this as root, the script above should work as is. However, if you're running it as a sudo
user, you need to change it a little. Obviously, you will need to change the IP address to the IP of your
client computer(s)

Change this section...
Code:
---
- name: Gather Server Information
  hosts: 10.0.0.193,10.0.0.22,10.0.0.31
  gather_facts: yes

  tasks:

..to this...

Code:
---
- name: Gather Server Information
  hosts: 10.0.0.193,localhost
  become: yes
  become_method: sudo
  gather_facts: yes

  tasks:

Notice the two new lines that start with "become". This is how you sudo in a playbook.
If you want to run against more than one IP address, just separate them with a comma.
You can use "localhost" to run a playbook against your ansible server.

Now, how do we actually run the playbook?

Code:
ansible-playbook gather_server_info.yml -v

The -v is the verbosity you want to see. You can actually run this will no -v, or -vv, or -vvv.
Go ahead and try all three just to see the difference.

Now this particular playbook didn't do a lot, it just gave us some information about our remote computer.
It didn't change anything. But still, congratulations, you just ran your first playbook. We all have to start
somewhere.

That's enough for now, but our next playbook will actually change something on the remote computer.
 
Last edited:
Now we will actually do something to the client computer.

We will add some user accounts.

Name this file add_wheel_users.yml
Code:
---
- name: Add users and add them to the wheel group
  hosts: all
  become: yes  # Run tasks with elevated privileges

  vars:
    users:
      - username: monica
        password: "{{ 'ch@ndl3r' | password_hash('sha512') }}"
        comment: "Monica"
      - username: rachel
        password: "{{ 'r0s$sux' | password_hash('sha512') }}"
        comment: "Rachel"
      - username: phoebe
        password: "{{ 'c@tsAndD0gs' | password_hash('sha512') }}"
        comment: "Phoebe"
      - username: joey
        password: "{{ 'HowYuDoin?' | password_hash('sha512') }}"
        comment: "Joey"

  tasks:
    - name: Add users
      user:
        name: "{{ item.username }}"
        password: "{{ item.password }}"
        comment: "{{ item.comment }}"
        groups: wheel
      with_items: "{{ users }}"

To run this...
Code:
ansible-playbook add_wheel_users.yml -v

There is a more secure way to do the passwords, you can even do it with hashes, so that you won't
know what their password is. I will try to do one of those in the future.
The double curly brackets (braces) are called jinja2. Notice we can use variables defined
in our playbook if we enclose them within the double brackets.

..and just like that, before you even knew it, you're a playbook running machine.
Nothing to this ansible stuff. But we've barely scratched the surface so far.
 
Last edited:
How do you know the name of the modules you should use? How do you know the options
of the modules? How do you know the syntax for the module?

The truth is, for most of them... I don't. I cheat, I look them up.


Let's say I want to add, remove or update a package using apt.


How about Portage for Gentoo?


How about dnf for fedora and redhat?


How about adding or removing users, as I did in the previous post. How did I know about the users module?


As you can see, there are hundreds and hundreds of these modules. I just look at the module
I want to use, and near the bottom they usually have some examples. More often than not, one of the
examples will be exactly what I want to do.

But what if I want a custom playbook or module that's not listed here.
Another popular place to get playbooks is...


Well now the cats out of the bag. You know the basics. Try writing your own playbook.

But again, this is just the basics, we need to talk about roles, permissions, the ansible_vault,
there is even a web GUI for ansible, but first we need to learn the basics.
 
Last edited:
Back in post #2, I briefly mentioned the /etc/ansible/hosts file.

This is the default location for this, but you don't have to use this file if for some reason you don't want to or can't.

I could create a hosts file in my home directory with IP addresses in it.

Code:
cat /home/username/hosts

192.168.2.2
192.168.2.5
192.168.2.7

Now to use this hosts file, I run my playbook like this...

Code:
anible-playbook add-motd-file.yml -i hosts -v

The only difference is, I put a "-i hosts" to include the hosts file.

But wait, there's more!!

One of the cool things about this hosts file, is you can divide computers up logically.
Here is an example.

Code:
cat /etc/ansible/hosts

[webservers]
10.10.2.2
10.10.2.4
10.10.2.6
[fedora]
10.10.3.4
10.10.3.8
10.10.3.10
[ubuntu]
10.10.4.2
10.10.4.5
[dnsservers]
10.10.1.3
10.10.1.6

Now, in my playbook.yml file I can change my hosts section to this.

Code:
hosts: webservers

I can even have multiple groups.
Code:
hosts: webservers,dnsservers,database

This is nice because if I want to run a playbook that uses dnf to install a package, I only put in my fedora or redhat servers.

If I want to run a playbook that uses apt to install a package, I can run it only on my debian or ubuntu servers.
 
I mentioned back in post#2 that password-less logins work best for ansible.
But you don't have to use password-less ssh keys.

You can run playbooks like this.

Code:
 ansible-playbook get_facts.yml -u root --ask-pass

Just replace "root" with whatever user you want to login to remote computer as.
The "--ask-pass" option requires that you have the sshpass package installed.
But if you run your playbook like this, it will ask for the password of the user you are logging in as.

The downside to this is... unless all your passwords are the same on every computer, you'll
have to run this multiple times as different users with different credentials.

Note: you can combine options when running playbooks.

Code:
ansible-playbook get_facts.yml -i hosts -u root --ask-pass

Notice I used the -i and -u flags above.
 

Members online


Top