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"