Ansible

From Indie IT Wiki

Introduction

Ansible is an open-source software provisioning, configuration management, and application-deployment tool enabling infrastructure as code.

It is used to deploy and maintain many servers at once, from the command line.

  • Control Node = Admin Computer
  • Host Node = Remote Server

How To Install and Configure Ansible on Ubuntu 20.04

Requirements

Python 2.6+ or Python 3.5+

Installation

sudo apt remove ansible
python3 -m pip install ansible
echo "export PATH=$PATH:$HOME/.local/bin" >> ~/.bashrc
source ~/.bashrc
ansible-galaxy collection install community.docker

Configuration

Add your hosts...

sudo nano /etc/ansible/hosts

[servers]
myserver ansible_host=123.456.789.0

[all:vars]
ansible_python_interpreter=/usr/bin/python3

Check the config...

ansible-inventory --list -y

all:
  children:
    servers:
      hosts:
        myserver:
          ansible_host: 123.456.789.0
          ansible_python_interpreter: /usr/bin/python3
    ungrouped: {}

Check the config with hosts file specified...

ansible-inventory --list -y -i ./inventory/hosts

Testing

List Hosts

./inventory/hosts

[servers]
server1 ansible_connection=ssh ansible_user=username1
domain.uk ansible_connection=ssh ansible_user=username2
nas ansible_connection=ssh ansible_user=username3
ansible -i ./inventory/hosts servers --list-hosts

 hosts (3):
   server1
   domain.uk
   nas

Ping

ansible -i ./inventory/hosts servers -m ping
ansible -i ./inventory/hosts server1.mydomain.com -m ping

Echo

Get all hosts to output a word on the command line...

ansible all -a "/bin/echo hello" -i ./inventory/hosts

Uptime

Uptime for a single host...

ansible hostname -m command -a "uptime" -i ./inventory/hosts

Uptime for all hosts in a group...

ansible groupname -m command -a "uptime" -i ./inventory/hosts

Uptime for all hosts...

ansible all -m command -a "uptime" -i ./inventory/hosts

AWS SSH Key

ansible all -m ping -u ubuntu --private-key=~/.ssh/myserver.pem

myserver | SUCCESS => {
   "changed": false,
   "ping": "pong"
}

Commands

You can perform one off commands on a single host or multiple hosts.

Hostname

ansible all -u ubuntu --private-key=~/.ssh/myserver.pem -a "hostname -f"

Update Package Cache

ansible all -u ubuntu --private-key=~/.ssh/myserver.pem -a "sudo apt-get update"

Playbooks

Playbooks are YAML text files which contain commands and options in a text file, just like a docker compose file.

The file contains 'modules' which perform different tasks.

Examples

See if hosts are alive by using only Gather Facts

99_gather.yml

- name: gather facts
  become: true
  hosts: all

... and run it on all but 1 host (by using the limit option with an exclamation mark (!host) (!host1:!host2)...

ansible-playbook -i ~/Bin/ansible-homelab/inventory/hosts ~/Bin/ansible-homelab/playbooks/ubuntu/99_gather.yml --limit '!server1'

Update Package List and Upgrade System

Create hosts file...

./inventory/hosts

[servers]
server1 ansible_connection=ssh ansible_user=user1
server2 ansible_connection=ssh ansible_user=user2
server3 ansible_connection=ssh ansible_user=user3

Check the list of hosts is readable..

ansible -i ./inventory/hosts all --list-hosts

Create the playbook file...

./playbooks/apt.yml

- hosts: "*"
  become: yes
  tasks:
    - name: apt
      apt:
        update_cache: yes
        upgrade: 'yes'

Run the playbook command...

ansible-playbook ./playbooks/apt.yml -i ./inventory/hosts

To run this playbook on a single host or multiple hosts, you would use the -l (limit) option at the end of the command line...

ansible-playbook ./playbooks/apt.yml -i ./inventory/hosts -l server1
ansible-playbook ./playbooks/apt.yml -i ./inventory/hosts -l server1,server2

Create single directory using the 'file' module

Create the playbook...

nano mkdir.yml

- hosts: all
  tasks:
  - name: Ansible file module create directory
    file:
      path: ~/backups
      state: directory

Run the playbook (dry run)...

ansible-playbook -C mkdir.yml

Run the playbook...

ansible-playbook mkdir.yml

Create multiple directories using the 'file' module

Create the playbook...

nano mkdirs.yml

- hosts: all
  tasks:
  - name: Ansible create multiple directories with_items    
    file:
      path: ~/backups/{{item}}
      state: directory
      with_items:
      - 'mysql'      
      - 'repository'
      - 'config'

Run the playbook...

ansible-playbook mkdirs.yml

https://linuxhint.com/create-directory-ansible/

Install Apache web server software and start it on a Red Hat based system

- name: Playbook
  hosts: webservers
  become: yes
  become_user: root
  tasks:
    - name: ensure apache is at the latest version
      yum:
        name: httpd
        state: latest
    - name: ensure apache is running
      service:
        name: httpd
        state: started

Touch a file based on the date of another file

- hosts: alpine
  become: yes
  tasks:
  - name: Get stats of a file
    ansible.builtin.stat:
      path: /usr
    register: usr
  - name: Print a debug message
    ansible.builtin.debug:
      msg: "Path exists and is a directory"
    when: usr.stat.isdir is defined and usr.stat.isdir
  - name: Print a debug message
    ansible.builtin.debug:
      msg: "ctime is {{ usr.stat.ctime }}"
  - name: touch file /root/misc/system_installed
    file:
      path: /root/misc/system_installed
      state: touch
      modification_time: '{{ "%Y%m%d%H%M.%S" | strftime(usr.stat.ctime) }}'

Variables

Standard variables

{{ ansible_facts["eth0"]["ipv4"]["address"] }}

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html

Custom variables

Example 1 - run the WordPress command line tool to install or update the software...

ansible-playbook wp.yml --extra-vars "major=true installcli=true"

wp.yml

- name: Install WordPress Cli
  register: wpclidonwloaded
  become: yes
  when: installcli is defined
  get_url: 
    url: https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    dest: "{{ wpclipath }}"
    mode: '0755'
    owner: "{{ wpcliuser }}"
    group: "{{ wpcligroup }}"

- name: Update WordPress Core (Major version)
  command: "{{ wpclipath }} core update"
  when: major is defined
  args:
    chdir: '{{ projects[inventory_hostname].blog_folder }}'

Example 2 - create a folder from a one-off command line custom variable...

ansible-playbook website.yml --extra-vars "domain=mybusiness.com"

website.yml

- name: create directory for web site
  file:
    path: "/var/www/{{ domain }}"
    state: directory