ansible

Project structure

Ansible project primarily consists of

Modules

Main component of playbooks. Least degree of separation of actions. Get compiled into python code and ran on remote. Offer alternatives to many common commands.

Roles and collections

Use ansible-galaxy to install or package them. Can be organized in collections. Many vendors like Grafana and Prometheus provide official collections for their products.

Inventory

Multiple hosts organized by groups. Has the following syntax:

[my_group]
1.2.3.5
1.2.3.4 ansible_user=root ansible_port=2201

Or a yaml version:

all:
  hosts:
    1.2.3.5:
    1.2.3.4:
      ansible_user: root
      ansible_port: 2201

Alongside host defenitions inventory contains host and group variables, stored in host_vars and group_vars dirs in yaml files with names corresponding to hosts or groups. These vars will be expanded in modules, templates and roles.

Vault

A builtin solution for keeping and distributing secrets. In the simplest mode of operation functions just like git-crypt encrypted with a password. Has a whole ton of configurations. Example setup:

ansible-vault create secrets.yml
echo "pass" > ./.vault-pass

After that add vault_password_file=.vault_pass to defaults in your config.

Facts

docs

Variables related to remote systems are called facts, while variables related to ansible itself are called magic variables. You can access facts in the ansible_facts var and some in top-level ansible_ variables.

Default facts include info about:

Templating

Ansible uses jinja2 for templating, you can read about it (in the context of flask) here.

Caveats

Root access

Most acions require root access. Easiest way to achieve this is to login as root using public keys. Alternatively you can become with predefined password. Passwords can be stored in ansible-vault or provided at runtime with --ask-pass for ssh and --ask-become-pass for become.

Tips

Test environment

To test a playbook on a docker container you can use the following command:

See below for a systemd enabled version!

docker run --rm -it \
  -l "ansible_playground" \
  --mount type=bind,src=$HOME/.ssh/id_ed25519.pub,dst=/root/.ssh/authorized_keys \
  hlabs/ssh-python \
  sh -c "/usr/sbin/sshd -o StrictModes=no; exec bash"

With this inventory file (you need community.docker playbook):

plugin: community.docker.docker_containers
docker_host: unix:///var/run/docker.sock
filters:
  - include: >-
      "ansible_playground" in docker_config.Labels
  - exclude: true

(Or just use container's IP address in a normal inventory)

With systemd

Most ansible roles rely on systemd for starting stuff, so for a complete test you most often would need it working. Since docker doesn't play nice with cgroups v2 (or so I've heard), simplest (or only) solution is to switch to podman (which runs systemd by default). Notice /usr/sbin/init being PID 1, this is required.

podman run --rm -it \
  -l "ansible_playground" \
  -v $HOME/.ssh/id_ed25519.pub:/root/.ssh/authorized_keys:ro \
  -p 2022:22 \
  --name ansible_playground \
  hlabs/ssh-python \
  /usr/sbin/init

With something similar to this in your inventory:

localhost ansible_user=root ansible_port=2022