Difference between revisions of "Ansible"

From Indie IT Wiki
Line 252: Line 252:
 
       state: touch
 
       state: touch
 
       modification_time: '<nowiki>{{ "%Y%m%d%H%M.%S" | strftime(usr.stat.ctime) }}</nowiki>'
 
       modification_time: '<nowiki>{{ "%Y%m%d%H%M.%S" | strftime(usr.stat.ctime) }}</nowiki>'
 +
 +
=== Copying SSH Keys ===
 +
 +
https://medium.com/@visualskyrim/ansible-playbook-deploy-the-public-key-to-remote-hosts-da3f3b4b5481
  
 
=== Advanced Usage ===
 
=== Advanced Usage ===

Revision as of 14:43, 25 March 2022

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) }}'

Copying SSH Keys

https://medium.com/@visualskyrim/ansible-playbook-deploy-the-public-key-to-remote-hosts-da3f3b4b5481

Advanced Usage

Blocks, Rescue and Always

The tasks in the block execute normally. If any tasks in the block return failed, the rescue section executes tasks to recover from the error. The always section runs regardless of the results of the block and rescue sections.

- name: Attempt and graceful roll back demo

  block:
    - name: Print a message
      ansible.builtin.debug:
        msg: 'I execute normally'

    - name: Force a failure
      ansible.builtin.command: /bin/false

    - name: Never print this
      ansible.builtin.debug:
        msg: 'I never execute, due to the above task failing, :-('
  rescue:
    - name: Print when errors
      ansible.builtin.debug:
        msg: 'I caught an error'

    - name: Force a failure in middle of recovery! >:-)
      ansible.builtin.command: /bin/false

    - name: Never print this
      ansible.builtin.debug:
        msg: 'I also never execute :-('
  always:
    - name: Always do this
      ansible.builtin.debug:
        msg: "This always executes"

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

Example - Set up a server Firewall

This is good when you want to set up a server's firewall using the UFW module. It prevents you from accidentally blocking yourself out of a server :-)

- name: Setup admin production UFW
 
  hosts: my_hosts
  gather_facts: no
 
  tasks:
 
    - block:
      - name: Reset UFW
        ufw: 
          state: reset
 
      - name: Allow outgoing
        ufw: 
          default: allow
          direction: outgoing
 
      - name: Disallow ingoing
        ufw: 
          default: deny
          direction: incoming
 
      - name: Establish regular admin rules
        ufw:
          rule: allow
          direction: in
          port: '5432'
          proto: tcp
          from_ip: '{{ item }}'
        loop:
          - 123.456.789/32
          - 987.654.321/32
 
      always:
        - name: Grant ssh access
          ufw:
            rule: allow
            direction: in
            port: '22'
            proto: tcp
            from_ip: 321.456.987/32
         
         - name: Enable Firewall
           ufw: 
            state: enabled

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