Setup#
Using ansible requires:
Control node with ssh client and ansible installed.
Managed node with ssh server, and python interpreter.
Provide access from control node to managed node.
The role of the nodes in our examples will be to play docker containers. These containers require some preparation, so we’ll create images.
For the managed node, we need to install and run the ssh server.
cat << EOF > setup_files/managed_node_dockerfile
FROM python:3.10-alpine
RUN apk add -q openssh && ssh-keygen -A && mkdir /root/.ssh
CMD ["/usr/sbin/sshd", "-D"]
EOF
For control mode, we need to install the ssh client and ansible as a python package.
cat << EOF > setup_files/control_node_dockerfile
FROM python:3.10-alpine
RUN apk add openssh-client && \\
ssh-keygen -t rsa -N "" -f /root/.ssh/id_rsa && \\
pip3 install ansible && \\
# Add to the config statement that we don't need to enter if we want to save the new host.
echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
RUN echo \[myhosts\] >> inventory.ini && \\
echo managed_node ansible_python_interpreter=/usr/local/bin/python3.10 >> inventory.ini
EOF
The following cell creates images that we’ll use to consider ansible.
docker build -t ansible_managed_node \
-f ./setup_files/managed_node_dockerfile \
./setup_files &> /dev/null
docker build -t ansible_control_node \
-f ./setup_files/control_node_dockerfile \
./setup_files &> /dev/null
The role of the nodes in our examples will be to play Docker containers. The following compose files emit two computers that play roles of control and managed nodes. These containers share the ssh key through the volume to which both containers are mounted.
cat << EOF > setup_files/compose.yml
services:
managed_node:
image: ansible_managed_node
container_name: managed_node
volumes:
- ssh_keys:/root/control_ssh
command: |
sh -c "
while ! [ -e /root/control_ssh/id_rsa.pub ]; do sleep 1; done && \
cat /root/control_ssh/id_rsa.pub >> /root/.ssh/authorized_keys; \
/usr/sbin/sshd -D
"
stdin_open: true
tty: true
depends_on:
- control_node
control_node:
image: ansible_control_node
container_name: control_node
volumes:
- ssh_keys:/root/control_ssh
command:
sh -c "
cp /root/.ssh/id_rsa.pub /root/control_ssh/id_rsa.pub; \
sh
"
stdin_open: true
tty: true
volumes:
ssh_keys:
EOF
Hello world#
Here we’ll look at how to run the Ansible sandbox that was created earlier, and with it, really show the basic ideas of the Ansible.
docker compose -f setup_files/compose.yml up -d &> /dev/null
Note don’t forget to stop the container after all.
docker compose -f setup_files/compose.yml down --volumes &> /dev/null
Inventory#
Check building an inventory page of documentation.
Inventories organise managed nodes into centralised files that provide Ansible with system information and network locations. An inventory file allows Ansible to manage a large number of hosts with a single command. So it’s a file in which you list all the managed nodes.
For convenience of use, inventory was specified during container creation, here we’ll just print and explain it.
Note We have specified the python path with ansible_python_interpreter=/usr/local/bin/python3.10
, it’s not necessary but allows to avoid some warnings.
docker exec control_node cat inventory.ini
[myhosts]
managed_node ansible_python_interpreter=/usr/local/bin/python3.10
Here [myhosts]
is the name of the group of servers.
Finally, try pinging the managed nodes using the command ansible <group of servers> -m ping -i inventory.ini
.
docker exec control_node ansible myhosts -m ping -i inventory.ini
managed_node | SUCCESS => {
"changed": false,
"ping": "pong"
}
As a result, we got the message ansible_host | SUCCESS ...
, which tells us that we successfully ping the managed node.
Playbook#
Playbooks are files with instructions. So below is a playbook that creates a play called My first play
. This play will ping all hosts and then print a message.
docker exec control_node sh -c "
cat << EOF > playbook.yaml
- name: My first play
hosts: myhosts
tasks:
- name: Ping my hosts
ansible.builtin.ping:
- name: Print message
ansible.builtin.debug:
msg: Hello world"
So now you can use the ansible-playbook
command to play the playbook we have just created.
docker exec control_node ansible-playbook -i inventory.ini playbook.yaml
PLAY [My first play] ***********************************************************
TASK [Gathering Facts] *********************************************************
ok: [managed_node]
TASK [Ping my hosts] ***********************************************************
ok: [managed_node]
TASK [Print message] ***********************************************************
ok: [managed_node] => {
"msg": "Hello world"
}
PLAY RECAP *********************************************************************
managed_node : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
So there are tasks: Ping my hosts
and Print message
, just as we specified.
Modules#
Check the page introduction to modules.
Modules are discrete units of code that can be used in ansible playbooks or in the CLI as an argument to the ansible
command.
As an example, let’s consider the command
module, which enables the execution of commands on a managed node. Here, we have the following details:
The
-m
parameter specifies the module we want to execute.The
-a
parameter specifies the arguments for that module.
Sence of the command - creation a file called secret_file
.
docker exec control_node \
ansible myhosts \
-i inventory.ini \
-m command \
-a "touch /root/secret_file"
managed_node | CHANGED | rc=0 >>
Let’s check if it appeared in the managed node.
docker exec managed_node ls /root
control_ssh
secret_file