Project

General

Profile

Actions

Stage4 - Provisioning the base images with Ansible

Ansible is a configuration management and orchestration framework which, similar to packer, focuses on reproducibility.
It communicates to remote machines using various remote access protocols, such as SSH, and provides a range of builtin modules (see Modules Index) to perform tasks on the remote machines. Common tasks include installing packages, editing configuration files, enabling/disabling startup services, etc.

These tasks can be organized in so-called playbooks to . The tasks therein are executed sequentially and any failure would cause the whole playbook to fail.
Since playbooks quickly grow rather large, roles were introduced as a mechanism to externalize functionality. Think of it as kind of more flexible includes. (Regular include mechanism exists too).

See ansible-roles git repository for real examples.

Manual setup

This describes how to quickly setup ansible with a remote host to try out ansible's functions.
This aims to give a basic understanding of how ansible works.

Obviously, install ansible and ssh and create a ssh key pair for ansible.
Install the generated public key under the ~/.ssh/authorized_keys of the ansible_user's home directory on the remote machines.

Hosts configuration

Configure the hosts ansible needs to communicate with in /etc/ansible/hosts.
Several hosts can be grouped together (in the example below, [clients]).

[clients]
target_host_1 ansible_host=1.2.3.4 ansible_user=root ansible_ssh_private_key_file=~/.ssh/ansible.id_rsa
target_host_2 ...
...

Test connection with a simple command, e.g., gathering information about the host with the setup module:

# run only on target_host_1
ansible target_host_1 -m setup

# run on all the group's machines
ansible clients -m setup

This should print a large JSON containing all sort of information about the target host.

Basic usage

Directly executing a module on a host or a group of hosts:

ansible [hostname|groupname] -m [module] -a [module_args]

Example: check if lighttpd service is running.

# Note: The service module detects which service system (sysvinit, systemd, ..)
ansible target_host -m service -a "name=lighttpd state=started" 

Refer to Modules Index for a full list.

Playbooks

Playbooks are realizing workflows by executing a series of tasks on the target hosts.
Here is a simple playbook to checkout our dracut repository, build the initramfs with it and copy it and the running kernel back to the playbook's working directory.
While only the Ubuntu packages names are shown in the example, it can obviously be generalized to support other distros.

# build-dracut-initramfs.yml
---
  - hosts: "clients" 
    vars:
      gitsource: git://git.openslx.org/openslx-ng/systemd-init
      gittarget: /opt/systemd-init
    tasks:
      - name: Install dependecies for dracut
        package: name={{ item }} state=installed
        with_items:
          - libfuse-dev
          - libglib2.0-dev
          - libpixman-1-dev
          - libewf-dev
          - libafflib-dev
          - dmsetup
          - git
          - build-essential
          - cmake
          - iputils-arping
          - curl
      - name: Checkout systemd-init git repo
        git:
          repo: "{{ gitsource }}" 
          dest: "{{ gittarget }}" 
          depth: 1
      - name: Build initramfs with dracut
        shell: "{{ gittarget }}/builder/build-initramfs.sh -s -d -p {{ gittarget }}/initramfs-{{ timestamp }}" 
      - name: Fetch running kernel and initramfs
        fetch:
          src: "{{ item }}" 
          dest: "{{ playbook_dir }}/gen_files/" 
          fail_on_missing: yes
          flat: yes
        with_items:
          - "{{ gittarget }}/initramfs" 
          - "{{ ansible_cmdline.BOOT_IMAGE }}" 
      - name: Remove git checkout
        file:
          path: "{{ gittarget }}" 
          state: absent

Provided the host group is configured properly on the machine calling ansible, the playbook can be executed with:

ansible-playbook build-dracut-initramfs.yml

Note that hosts are specified inside the playbook and do not need to be specified on the command line (but can be overriden if need be).

Packer integration

Provisioning base images generated by packer can be elegantly solved with the ansible provisioner:

  "builders": [{ ... }],
  "provisioners": [{
    "type": "ansible",
    "playbook_file": "{{ template_dir }}/build-dracut-initramfs.yml",
    "extra_arguments": [ "-vvv" ]
  }]

Updated by Jonathan Bauer about 7 years ago · 23 revisions