Aller au contenu principal

Construire des images Docker avec Ansible

· 5 minutes de lecture
Stéphane ROBERT
Consultant DevOps

logo ansible

Ansible-bender est une application développée par Tomas Tomecek qui permet de construire des images de container à partir de playbooks ansible plutôt que des fichiers Dockerfile. Ansible-bender s'appuie sur le moteur de container Podman plutôt que docker.

Podman et Buildah

Podman est une solution de containérisation comme l'est Docker développée par RedHat. Il utilise le même interpréteur de ligne de commande que Docker et donc les principales commandes de Docker fonctionne avec Podman. Podman fonctionne sans daemon comme instance de gestion pour gérer ses pods. Cela permet d’accéder aux différentes applications virtualisées sans droits root. Podman est devenu le moteur de conteneur par défaut sous RHEL8.

Buildah est un outil complémentaire à Podman qui permet de créer des images au format Open Container Initiative (OCI). Ces images sont compatibles avec la plupart des runtimes de containers, ceux compatible avec la norme OCI: docker, containerd, runc, ... et donc kubernetes. Il utilise aussi les fichiers Dockerfile pour décrire les images.

Installation d'Ansible-bender et de ses prérequis

Provisionnement d'une VM avec vagrant

Je vais utiliser une machine provisionnée avec vagrant pour faire mes tests en prenant une box oracle8.

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
config.vm.box = "generic/oracle8"
config.vm.provider "libvirt" do |hv|
hv.cpus = "2"
hv.memory = "2048"
end
config.vm.synced_folder '.', '/vagrant', disabled: true

config.vm.define "bender" do |bender|
bender.vm.network :private_network, ip: "192.168.3.11"
bender.vm.hostname = "bender"
bender.vm.provision "ansible" do |a|
a.verbose = "v"
a.playbook = "provision-playbook.yml"
end
end
end

Comme vous pouvez le remarquer, il fait appel à playbook ansible pour configurer la vm produite, qui permet surtout de lancer des playbooks sans à spécifier le user vagrant et d'installer podman, buildah et ansible-bender. Pour ceux qui ne connaissent pas l'écriture de playbooks ansible je vous renvoie sur mon billet.

N'oubliez pas de changer le chemin de votre clé ssh !

---
- hosts: all
gather_facts: no
become: true
tasks:
- name: Install packages
package:
name:
- python3-pip
- podman
- buildah

- name: Install ansible-bender and ansible
pip:
name:
- ansible-bender
- ansible

- name: Replace a localhost entry with our own
lineinfile:
path: /etc/hosts
regexp: '^127\.0\.0\.1'
line: 127.0.0.1 localhost
owner: root
group: root
mode: '0644'

- name: Allow password authentication
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^PasswordAuthentication"
line: "PasswordAuthentication yes"
state: present
notify: restart sshd

- name: Set authorized key took from file
authorized_key:
user: vagrant
state: present
key: "{{ lookup('file', '/home/vagrant/.ssh/id_ed25519.pub') }}"

handlers:
- name: restart sshd
service:
name: sshd
state: restarted

Pour se connecter à notre vm il suffit de :

ssh 192.168.3.11
[vagrant@bender ~]$

Construction d'une image docker avec ansible-bender

Le fonctionnement est assez simple. On utilise un playbook classique auquel on ajoute une variable ansible-bender pour indiquer :

  • l'image de base
  • le nom de l'image (tag) produit
  • les volumes
  • ...

La seule contrainte est d'utiliser des images sources contenant déja python3.6 au minimun (ex: python:3-alpine)

Par exemple:

---
- name: Demonstration of ansible-bender functionality
hosts: all
vars:
ansible_bender:
base_image: python:3-alpine

working_container:
volumes:
- '{{ playbook_dir }}:/src'

target_image:
name: a-very-nice-image
working_dir: /src
labels:
built-by: '{{ ansible_user }}'
environment:
FILE_TO_PROCESS: README.md
tasks:
- name: Run a sample command
command: 'ls -lha /src'
- name: Stat a file
stat:
path: "{{ lookup('env','FILE_TO_PROCESS') }}"

Construction de notre propre image

Je vais créer une image installant apache2 et affichant un simple fichier. Créer les deux fichiers suivant dans votre vm.

Le fichier file.html :

<h1>hello world!</h1>

Le fichier playbook.yml

---
- name: Serve file using apache
hosts: all
vars:
ansible_bender:
base_image: "docker.io/library/python:3-alpine"
target_image:
name: test:0.1
cmd: httpd -DFOREGROUND
ports: ["80"]
squash: true

- name: Serve our file using httpd
hosts: all
tasks:
- name: Install httpd
package:
name:
- apache2
- libxml2-dev
- apache2-utils
state: installed
- name: Copy
copy:
src: file.html
dest: /var/www/html/

Vous remarquez que j'ai ajouté quelques variables à ansible-bender permettant d'exposer le port 80 (un tableau de string), la commande du container et squash qui permet d'aplatir l'image produite à un seul layer. La liste des toutes ces options se trouve ici

Lançons la construction de l'image:

ansible-bender build playbook.yml

Qui retourne :

PLAY [Serve file using apache] *************************************************

TASK [Gathering Facts] *********************************************************
ok: [test-0-1-20210415-073450224792-cont]

PLAY [Serve our file using httpd] **********************************************

TASK [Gathering Facts] *********************************************************
ok: [test-0-1-20210415-073450224792-cont]

TASK [Install httpd] ***********************************************************
loaded from cache: 'c4211dd45723cd1caafaa3037aed2325666d8159dbbfc207a8bbf806c62a4530'
skipping: [test-0-1-20210415-073450224792-cont]

TASK [Copy] ********************************************************************
changed: [test-0-1-20210415-073450224792-cont]

PLAY RECAP *********************************************************************
test-0-1-20210415-073450224792-cont : ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0

Getting image source signatures
Copying blob sha256:5d0c4fd59dd60a3b05d6fd9c099f6791ca4358e2c1685929da8f4ab23774da61
Copying config sha256:fca2397b32294275d3c86dde9e1fbf7873febd63b9a541e1cb78d641516669ff
Writing manifest to image destination
Storing signatures
fca2397b32294275d3c86dde9e1fbf7873febd63b9a541e1cb78d641516669ff
Image 'test:0.1' was built successfully \o/
[vagrant@bender ~]$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/test 0.1 fca2397b3229 11 seconds ago 62.9 MB

Lançons l'image construite :

podman run -p 80:80 -d test:0.1

Vérifions qu'elle fonctionne :

curl http://localhost:8080
<html><body><h1>It works!</h1></body></html>

Mais combien a t'elle de layers ?

podman image inspect test:0.1

...

"RootFS": {
"Type": "layers",
"Layers": [
"sha256:5d0c4fd59dd60a3b05d6fd9c099f6791ca4358e2c1685929da8f4ab23774da61"
]
},
...

Un seul comme demandé.

Conclusion

Je trouve ansible-bender plutôt sexy et je pense même l'intégrer dans un runner gitlab pour construire quelques-unes de mes images. Un beau couple ansible docker !