Skip to main content

Ansible: Example Playbooks and ad hoc commands

1155 words·
Ansible Ansible-Playbook Docker Nginx
Ansible - This article is part of a series.
Part 1: This Article

This was my first experience with Ansible and I utilized the same manifests for the tasks, variables, and playbooks.

For a more comprehensive approach to using Ansible with Collections and Roles, check out my other blog post: “Create Ansible Collection with Roles and Playbooks for User Management and SSH Daemon Configuration”

Install Ansible on Server
#

Install Ansible
sudo apt update Update Package Manager
sudo apt install software-properties-common -y Install apt utilities
sudo add-apt-repository --yes --update ppa:ansible/ansible Add repository
sudo apt install ansible -y Install Ansible

Ansible inventory:
sudo vi /etc/ansible/hosts

Should look like this:

[jklug]  # no "-" allowed
192.168.30.100
192.168.30.101
192.168.30.102

Verify Ansible inventory:
ansible all --list-hosts

Before running Ansible commands on an host, it’s necessary to establish a SSH connection to the host:

ssh-keygen -t rsa -b 4096 Create SSH key
cat id_rsa.pub Add key to authorized_keys on Ansible host
ssh ubuntu@192.168.30.100 SSH into Ansible host
exit Exit SSH connection

Check connection to Ansible host:
ansible all -m ping ansible jklug -m ping

Should look like this:

18.184.196.36 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

Ansible Playbooks
#

Run Ansbible Playbook
#

ansible-playbook playbookname.yml Run playbook
ansible-playbook playbookname.yml --list-hosts List hosts affected by playbook
ansible-playbook playbookname.yml --limit hostgroup Run Playbook for specific hostgroup
ansible-playbook playbookname.yml -u username -b true Run Playbook for specific user
ansible-playbook playbookname.yml -u username -b true --ask-pass Prompt for pw

Ansible Playbooks: System
#

Reboot Server
#

---
- name: Ubuntu server reboot
  hosts: jklug
  become: true
  
  tasks:
  - name: Reboot
    reboot:
      reboot_timeout: 60
      msg: "Reboot initiated by Ansible"

Apt update & apt upgrade
#

---
- name: Apt update, apt upgrade
  hosts: jklug
  become: true
  tasks:
    - name: Apt update
      apt:
        update_cache: yes

    - name: Apt upgrade
      apt:
        upgrade: yes
        autoremove: no
        autoclean: no

Create User
#

The following playbook creates a new user (tested on Ubuntu) and adds the user the one or more groups:

---
 - hosts: all
   become: yes

   vars:
   - user: user1 # username
   - password: password  # password

   tasks:
    - name: Create User
      user: 
        name: "{{ user }}"
        password: "{{ password | password_hash('sha512') }}"  
    
    - name: Add user to group # Optional
      user:
        name: "{{ user }}"
        shell: /bin/bash
        groups: docker,sudo # Add User to groups
        append: yes

Delete User
#

This playbook delets an user (tested on Ubuntu), the deletion of the users home directory is optional:

---
 - hosts: all
   become: yes

   vars:
   - user: user1 # username

   tasks:
    - name: Delete User
      user: 
        name: "{{ user }}"
        state: absent
        remove: no # Don't remove Home directory

Ansible Playbooks: Docker Compose
#

Install Docker & Docker-Compose
#

This playbook installs Docker and Docker Compose with apt (tested on ubuntu):

---
- name: Install Docker on Ubuntu
  hosts: all
  remote_user: ubuntu # Run Playbook as specific user
  become: true
  tasks:
    - name: Update apt
      apt:
        update_cache: yes

    - name: Install dependencies
      apt:
        name: ca-certificates,curl,gnupg,lsb-release
        state: present

    - name: Create Docker keyring directory
      file:
        path: /etc/apt/keyrings
        state: directory

    - name: Add Docker GPG key
      shell: curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

    - name: Add Docker repository to apt sources
      shell: echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

    - name: Update apt again
      apt:
        update_cache: yes

    - name: Install Docker
      apt:
        name: docker-ce,docker-ce-cli,containerd.io,docker-buildx-plugin,docker-compose-plugin
        state: present

    - name: Add ubuntu user to docker group
      user:
        name: ubuntu
        groups: docker
        append: yes

Start Docker-Compose file
#

Run a Container from a docker-compose.yml file in a defined directory:

- name: Docker Compose up -d
  hosts: jklug
  remote_user: ubuntu # Run Playbook as specific user
  become: true
  become_user: ubuntu
  become_method: sudo # optional
  tasks:
    - name: Docker Compose up -d
      shell: |
        cd ~/Docker-Compose
        docker compose up -d        

Create and start Docker-Compose file
#

This playbook creates a docker-compose.yml file for an apache webserver in a defined directory and starts the container:

---
- name: Create and start Docker Compose file
  hosts: jklug
  remote_user: ubuntu # Run Playbook as specific user
  become: true
  become_user: ubuntu
  become_method: sudo # optional
  gather_facts: no

  vars:
    directory_path: "~/docker-compose"
    file_name: "docker-compose.yml"
    config_contents: |
      version: '3'

      services:
        web:
          image: httpd:latest
          ports:
            - "8080:80"
          volumes:
            - ./html:/usr/local/apache2/htdocs/      

  tasks:
    - name: Create directory for docker-compose.yml
      file:
        path: "{{ directory_path }}"
        state: directory
        mode: '0755'

    - name: Create docker-compose.yml file
      file:
        path: "{{ directory_path }}/{{ file_name }}"
        state: touch
        mode: '0644'

    - name: Copy config into docker-compose.yml file
      lineinfile:
        path: "{{ directory_path }}/{{ file_name }}"
        line: "{{ config_contents }}"

    - name: Start Container
      shell: |
        cd {{ directory_path }}
        docker compose up -d        

Ansible Webserver
#

Install and configure Nginx
#

This playbook Installs Nginx, creates a custom configuration file in /etc/nginx/sites-available and links it to /etc/nginx/sites-enabled. It also deletes the default configuration file in the sites-enabled directory:

---
- name: Install and configure Nginx
  hosts: jklug  # Define hosts group from /etc/ansible/hosts
  remote_user: ubuntu # Run Playbook as specific user
  become: true  # sudo privileges
  tasks:
    - name: Apt update
      apt:
        update_cache: yes

    - name: Install Nginx
      apt:
        name: nginx     # Package Name
        state: present  # Insall

    - name: Create Nginx Config
      copy:
        content: |
          server {
              listen 80;
              listen [::]:80;

              server_name jklug.work;

              root /var/www/html;
              index index.html index.nginx-debian.html;

              location / {
                  try_files $uri $uri/ =404;
              }
          }          
        dest: /etc/nginx/sites-available/jklug.work
        owner: root
        group: root
        mode: 0644

    - name: Create symbolic link to sites-enabled
      file:
        src: /etc/nginx/sites-available/jklug.work
        dest: /etc/nginx/sites-enabled/
        state: link
    
    - name: Delete default config file
      file:
        path: /etc/nginx/sites-enabled/default
        state: absent

    - name: Restart Nginx
      service:
        name: nginx
        state: restarted

Ansible Playbook Parts
#

List Directory Content
#

---
- name: Run shell command
  hosts: all
  tasks:
    - name: List contents of /tmp directory
      shell: ls -la /tmp
      register: result  # Register shell output in result variable
      
    - name: Display output
      debug:
        var: result.stdout_lines # Display result variable on Ansible server

Ad hoc commands
#

Files & Folder
#

Create or delete file:
ansible jklug -m ansible.builtin.file -a "dest=/tmp/file3 state=touch"
ansible jklug -m ansible.builtin.file -a "dest=/tmp/file3 state=absent"

Create or delete folder:
ansible jklug -m ansible.builtin.file -a "dest=/tmp/folder1 state=directory"
ansible jklug -m ansible.builtin.file -a "dest=/tmp/folder1 state=absent"

Copy file “/tmp/file1” from server to “tmp” on host:
ansible jklug -m ansible.builtin.copy -a "src=/tmp/file1 dest=/tmp/"

Copy file with permissions (“become” necessary for root permissions):
ansible jklug -m ansible.builtin.copy -a "src=/tmp/file2 dest=/tmp/ mode=600 owner=root group=root" --become

System & Services
#

Reboot host:
ansible jklug -a "/sbin/reboot" --become

Install apt package, for example “nginx”:
ansible jklug -m apt -a "name=nginx state=present" --become or
ansible jklug -m ansible.builtin.apt -a "name=nginx state=present" --become
Install apt package & run apt update:
ansible jklug -m apt -a "name=nginx state=present update_cache=true"

Start, Stop & Restart Services: systemd
ansible jklug -m systemd -a "name=nginx state=started" --become
ansible jklug -m systemd -a "name=nginx state=stopped" --become
ansible jklug -m systemd -a "name=nginx state=restarted" --become

Start, Stop & Restart Services: systemctl
ansible jklug -m ansible.builtin.service -a "name=nginx state=started" --become
ansible jklug -m ansible.builtin.service -a "name=nginx state=stopped"
ansible jklug -m ansible.builtin.service -a "name=nginx state=restarted"

Ansible - This article is part of a series.
Part 1: This Article