Introduction
I use Ansible to manage all my infrastructure. It's about 50 bare metal servers that sit in my basement.
It works well, but I have a few issues:
- It can be very slow
- YAML can be very tricky to edit
- Sometimes, it takes ages to find how to do something that seems very simple
- The output is not helpful, it is either not detailed enough, or a huge flow of debug information
The third one is the biggest pain point. I spent sometimes hours trying to get how to use some plugin to do something simple.
Ansible provides a lot of plugins, but most of them can be replaced by simple commands.
Some, which are a bit harder to replace, like lineinfile
which "ensure there
is a line in a file" I try to avoid, and instead have the whole file in my
devops system and replace it.
I started to replace a few playbooks with shell scripts. And it works wonders. Everything is so simple.
Example
Here is an example:
---
- name: Michi pdns configuration
gather_facts: false
hosts: michi
tasks:
- package:
name:
- powerdns
- entr
state: present
- service:
name: pdns_server
state: stopped
- copy:
src: pdns.conf
dest: /etc/pdns/pdns.conf
- copy:
src: check-dynupdates.lua
dest: /etc/pdns/check-dynupdates.lua
- file:
path: /var/db/pdns/
state: directory
- copy:
src: schema-sqlite3.sql
dest: /var/db/pdns/schema-sqlite3.sql
- file:
path: /var/db/pdns/pdns.sqlite3
state: absent
- shell: sqlite3 /var/db/pdns/pdns.sqlite3 < /var/db/pdns/schema-sqlite3.sql
- file:
path: /var/db/pdns/schema-sqlite3.sql
state: absent
- service:
name: pdns_server
state: started
enabled: true
- copy:
src: sync.sh
dest: /etc/pdns/sync.sh
mode: 0700
- copy:
src: sync_daemon.sh
dest: /etc/pdns/sync_daemon.sh
mode: 0700
- copy:
src: pdns_sync
dest: /etc/rc.d/pdns_sync
mode: 0700
- service:
name: pdns_sync
state: started
enabled: true
to
#!/bin/sh
set -x
cd "$(dirname "$0")"
export TERM=vt100
SSH="ssh michi doas"
$SSH pkg_add powerdns entr
$SSH rcctl stop pdns_server
cat pdns.conf | $SSH tee /etc/pdns/pdns.conf > /dev/null
cat check-dynupdates.lua | $SSH tee /etc/pdns/check-dynupdates.lua > /dev/null
$SSH mdir -p /var/db/pdns/
cat schema-sqlite3.sql | $SSH tee /var/db/pdns/schema-sqlite3.sql > /dev/null
$SSH rm /var/db/pdns/pdns.sqlite3
$SSH sh -c 'sqlite3 /var/db/pdns/pdns.sqlite3 < /var/db/pdns/schema-sqlite3.sql'
$SSH rm /var/db/pdns/schema-sqlite3.sql
$SSH rcctl start pdns_server
$SSH rcctl enable pdns_server
cat sync.sh | $SSH tee /etc/pdns/sync.sh > /dev/null
$SSH chmod 700 /etc/pdns/sync.sh
cat sync_daemon.sh | $SSH tee /etc/pdns/sync_daemon.sh > /dev/null
$SSH chmod 700 /etc/pdns/sync_daemon.sh
cat pdns_sync | $SSH tee /etc/rc.d/pdns_sync > /dev/null
$SSH chmod 700 /etc/rc.d/pdns_sync
$SSH rcctl enable pdns_sync
This is for a single host, but for multiple host, you can do something like:
HOSTS="michi kiki"
for HOST in $HOSTS
do
SSH="ssh $HOST ls"
$SSH <do something>
done
Conclusion
I converted a dozen playbook to scripts and here are a few point:
- It is much, MUCH easier to write, but this would depend on your
sh
experience. - It is much faster to run. If you have many hosts, I would look into GNU parallel because now it is sequential.
- It is more extensible without having to read documentation.
- Scripts are much shorter and easier to read (the above script has no comment for the example, but by real scripts have extensible comments)