The purpose of this project is to use Vagrant and Ansible to easily generate and provision virtual machines based on configuration files. These machines are not to be used on any serious production environment, but for training and testing.
Initialize a project using template configuration files.
manage.sh init -n "myfirstconfiguration"
This will create a directory in a defined location (by default,
~/ephemeral-machines/<project name>
).
Then, all future commands should be launched from within this directory. So the next step is to change directory to the newly created:
cd ~/ephemeral-machines/myfirstconfiguration/
Then create the vagrant.yaml
(or vagrant.toml
if you prefer TOML syntax)
file, and optionnaly ansible/playbook.yaml
file. You can use the templates
provided into config-templates
and ansible/
directories.
Editing the local Vagrantfile or any other file should not be necessary.
Finally, the following command will download the required box images if not already present, create the machines described on the configuration, start them, and optionnally launch the provisioning using the specified Ansible playbook file:
vagrant up
Then, the following command will allow to check these machines status:
vagrant status
To connect to any machine, use this command (<machine name>
is required in a
multi-machines deployment):
vagrant ssh <machine name>
- Vagrant (tested with version 2.2.3)
- Ansible (for provisioning actions, tested with version 2.7.6)
- libvirt (tested with version 5.0.0)
- or virtualbox (untested)
If you want to use the TOML configuration file format instead of YAML format,
installing toml-rb
parser is also required (tested with version 1.1.2):
vagrant plugin install toml-rb
Using libvirt as a provider is not yet supported by Vagrant. One must install vagrant-libvirt plugin to make it work (tested with version 0.0.45). To find libvirt compatible boxes on Vagrant cloud, use this link.
If using both firewalld and libvirt on the host, one must ensure that the
firewall backend used is iptables and not nftables (which is the default).
See this article for
details. Symptoms: DHCP
not working with NATed virtual network (like default
), guest machines not
getting IP address.
This script is provided to easily deploy new virtual machines configuration directories, or manage existing ones.
One simple way to use this script is to configure an alias:
alias ephman='/var/lib/git/ephemeral-machines/manage.sh'
- Main script usage:
manage.sh <ACTION> <OPTIONS>
ACTIONS (must provide only one, and it must be the first argument):
list: List existing configurations
init: Initialize new configuration
upgrade: Upgrade configuration to installed project version
help: Print this help
To show detailed usage for a specific action, type:
manage.sh <ACTION> -h
- Initialize new configuration directory:
manage.sh init <OPTIONS>
MANDATORY OPTIONS:
-n <configuration_name> Name of the configuration, used to name the final
directory
OPTIONAL OPTIONS:
-d <global_dir> Main directory used for the configurations
-f Erase configuration directory if it already exists
-h Print this help
- Upgrade configuration directory to current project version:
manage.sh upgrade <OPTIONS>
MANDATORY OPTIONS (mutually exclusives):
-n <configuration_name> Name of the configuration to be upgraded
-A Upgrade all configurations into the main directory
OPTIONAL OPTIONS:
-d <global_dir> Main directory used for the configurations
-f Force upgrade, even if the version is already installed
-h Print this help
- List configuration directories:
manage.sh list <OPTIONS>
OPTIONAL OPTIONS:
-d <global_dir> Main directory used for the configurations
-h Print this help
-v Also print configurations files, size, version.
To start machines configuration, first initialize a configuration directory
using the manage.sh
script. Then, you can create a new vagrant.yaml
configuration file at the root of this directory. The configuration files use
YAML syntax. Sadly, this syntax is not very user
friendly, specifically regarding indentation, so always double-check your
syntax. TOML syntax is also supported,
but the toml-rb parser must be installed as a vagrant plugin. The parser to
use is determined from the configuration file extention (.yaml
or .toml
).
The configuration file is separated in the following sections (root keys in the
machines
dictionnary).
This section defines configuration related to machines to be created, grouped
under the machines
main key. This is a dictionary, so several machines can
be defined under it.
Each machine configuration is created as a separate dictionnary. The key name used for this dictionnary entry will be used to name the created machine in Vagrant.
Under this key will be the parameters that describe the machine. These are the list of parameters supported directtly by Vagrant without provisioning (there are also other parameters supported by Ansible playbooks, see the next sections).
The following apply specifically to Vagrant creation of the virtual machines:
hostname
: Mandatory, name that will be used as the hostname (usually will be the same as the key name).box
: Name of the box to be used. Check the Vagrant cloud to find easy to use boxes, but you can also use your own boxes, for example using Packer. This parameter is mandatory, unless you setbux_url
below.box_url
: Full URL of the box to use.box_version
: Specific version of the box to be used.box_check_update
: Determines if Vagrant checks for newer versions of specified box. Boolean, defaults totrue
.
The following parameters are provider specific parameters (tested with Libvirt and vagrant-libvirt:
memory
: Size of RAM that will be allocated to the VM.cpus
: Number of vCPU that will be allocated to the VM.
The following parameters allow to define private networks:
private_networks
: Contains multiple dictionnaries, each describing a private network to be used by the VM. Each dictionnary can define:ip_private
: IP address to use.auto_config
: Boolean, defines if Vagrant will automatically configure the interface.type
: Network type, likedhcp
.local_domain
: Local domain name, if one is used.
NOTE: the key name of each of these dictionnaries should start with
_listitem_
. This is a limitation to allow default and include features to
work, and still be able to transform the final merged dictionary into a list.
The following parameters allow to define forwarded ports:
fw_ports
: Contains multiple dictionnaries describing ports to be forwarded between guest and host. Each dictionnary can define:guest
: Port number on the VM.host
: The port on the host machine that will be redirected.
NOTE: the key name of each of these dictionnaries should start with
_listitem_
. This is a limitation to allow default and include features to
work, and still be able to transform the final merged dictionary into a list.
The following parameters allow to define synced folders:
synced_folders
: Contains multiple dictionnaries describing directories to be shared between host and guest. Each dictionnary can define:host
: Name on the host of the folder to be shared.guest
: Path on the guest of the folder to be shared.
NOTE: the key name of each of these dictionnaries should start with
_listitem_
. This is a limitation to allow default and include features to
work, and still be able to transform the final merged dictionary into a list.
Defines one single machine, named srv1
(both internally for Vagrant and as
its hostname
):
---
machines:
srv1:
hostname: "srv1"
box: "centos/7"
memory: 1024
cpus: 1
private_networks:
ip_private: "192.168.122.11"
auto_config: true
type: "dhcp"
local_domain: "vagrant.local"
fw_ports:
_listitem_pgport
guest: 5432
host: 55431
sync_folders:
_listitem_share:
host: "share"
guest: "/share"
This section is used to define default values for some parameters. Any key
that can be specified under the machines
key can also be specified under the
defauts
key: both definitions will be merged eventually. The value specified
under defaults
key will be used by all defined machines, unless some
parameters are overwritten in one or several machines definition.
Defines two machines, the common configuration is registered under the
defaults
key (note that the configuration for srv2
overwrites the default
box
configuration):
---
defaults:
box: "centos/7"
memory: 1024
cpus: 1
private_networks:
_listitem_122:
auto_config: true
type: "dhcp"
local_domain: "vagrant.local"
sync_folders:
_listitem_share:
host: "share"
guest: "/share"
machines:
srv1:
hostname: "srv1"
private_networks:
_listitem_122:
ip_private: "192.168.122.11"
fw_ports:
_listitem_pgport
guest: 5432
host: 55431
srv2:
hostname: "srv2"
box: "debian/jessie64"
private_networks:
_listitem_122:
ip_private: "192.168.122.12"
fw_ports:
_listitem_pgport
guest: 5432
host: 55432
Vagrant supports several methods for provisioning the newly created machines. This project supports exclusively Ansible.
The ansible
key is used to define the global provisioning settings. It
supports the following parameters:
dir
: Path of the folder containing Ansible files.playbook
: Name of the playbook to use (it must be into the Ansible folder).groups
: Contains several dictionnaries named after an Ansible group used by the selected playbook. Each one defines a list of guests to include in this group.verbose
: Change Ansible verbosity, useful for debugging.extra_vars
: Allows to setup additionnal settings directly to Ansible at startup.
Depending on the playbook used, any number of additional parameters may be used. Before launching Ansible, Vagrant writes every machine's configuration into the host_vars directory. This way, any setting defined into a machine's dictionary key will be available from the playbook.
Also see the description of the playbooks templates and the supported settings.
This creates two machines, and for each on it installs PostgreSQL 11, and
creates and starts a PostgreSQL instance (note: for this to work, the
ansible/playbook.yaml
file must have been created, for example using an
existing template:
---
defaults:
box: "centos/7"
memory: 1024
cpus: 1
private_networks:
_listitem_122:
auto_config: true
type: "dhcp"
local_domain: "vagrant.local"
sync_folders:
_listitem_share:
host: "share"
guest: "/share"
postgresql:
version: "11"
repo: "https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-centos11-11-2.noarch.rpm"
packages:
- "postgresql11-server"
- "postgresql11-contrib"
settings:
listen_addresses: "'*'"
machines:
srv1:
hostname: "srv1"
private_networks:
_listitem_122:
ip_private: "192.168.122.11"
fw_ports:
_listitem_pgport
guest: 5432
host: 55431
srv2:
hostname: "srv2"
private_networks:
_listitem_122:
ip_private: "192.168.122.12"
fw_ports:
_listitem_pgport
guest: 5432
host: 55432
ansible:
dir: "ansible"
playbook: "playbook-simple.yaml"
groups:
pg:
- "srv1"
- "srv2"
This section allows to specify several files that will be read and merged with the global configuration. These files are loaded in the specified order, but after all the main configuration file has been completely loaded. If a parameter is specified more than once, the last value read is kept. While not mandatory, it is recommanded that this section is put at the end of the main file, precedence order will be more intuitive this way. This section has no effect if put into an included file (only one level of includes is supported, no nesting).
The following file could be used to separate the previous example into four files:
---
includes:
- file: "defaults.yaml"
- file: "srv1.yaml"
- file: "srv2.yaml"
- file: "ansible.yaml"
Several configuration template files are provided under the config-templates/
directory. They can be used as a basis to build your own.
The provided configuration templates include the following sub-directories:
basic-machines/
: various configuration files to define very basic machines, without provisioning.simple-machines/
: various configuration files to define simple Linux machines, provisioned using thesimple-playbook.yaml
Ansible playbook.pg/
: various configuration files to define Linux machines with an installed and configured PostgreSQL instance, provisioned using thepg-playbook.yaml
Ansible playbook.pg-repli/
: various configuration files to define Linux machines with an installed and configured PostgreSQL instance using streaming replication, provisioned using thepg-repli-playbook.yaml
Ansible playbook.
The following environment variables are supported:
EM_MAIN_DIR
: used bymanage.sh
script to set the global projects directory (defaults to~/ephemeral-machines/
).EM_VAGRANT_CONF
: used byvagrant
commands to find the main configuration file to be used within the current directory (defaults tovagrant.yaml
).
Several Ansible template playbooks are provided. This section describes what
options they support. These options are to be specified exactly like the
Vagrant options, in the main configurations files, under the
machines: { <host> }
dictionnaries, or under the defaults
dictionnary.
Note: Ansible as a provisioning system strongly relies on the
idempotency
of tasks executed by playbooks. However, these playbooks templates are
designed to work on fresh, newly created virtual machines. Idempotency is not
enforced, and executing these playbooks on an already existing machine (using
vagrant provision
or directly ansible-playbook
) is not supported. If you
want to reset a machine, you should first vagrant destroy
, then vagrant up
.
These machines are called ephemeral after all.
Note: The Ansible directory includes various tasks and scripts designed for these playbooks. Obviously, these should not be used for any other goal than provisioning newly created machines. Other uses may result in service interruption and data loss.
The template playbook ansible/simple-playbook.yaml
is designed to provision
simple Linux machines, with several added useful softwares. The supported
options to add to the machine definition are:
private_networks
: See the description on the Vagrant configuration section. These parameters are used to configure local name resolution (/etc/hosts
). Specifically, the ones used by the playbook are:ip_private
: Adresse IP privée pour cette règle de résolution.resolvname
: Nom qui va résoudre sur l'adresse IP privée spécifiée pour toutes les machines de la configuration.local_domain
: Nom de domaine qui sera ajoutée auresolvname
pour construire le FQDN.
The template playbook ansible/pg-playbook.yaml
is designed to provision Linux
machines with PostgreSQL installed and an instance created, configured and
started. The supported options to add to the machine definition are:
- The options supported by
simple-playbook.yaml
. postgresql
: Main dictionary key for specifying PostgreSQL configuration.version
: PostgreSQL major version number (ie 9.4, 11) to be installed.repo
: PostgreSQL repository name to be added.repo_url
: PostgreSQL repository full URL to be added.packages
: List of PostgreSQL packages to be installed from the repository.settings
: Dictionary of PostgreSQL settings to be modified, specified as keys and values (for example,listen_addresses: "'*'"
).hba_lines
: List of lines to be added to the PostgreSQL authentication file, specified as strings (for exemple,- "local all postgres peer"
).
The supported Ansible group is:
pg
: Machines where a PostgreSQL instance will be created.
The template playbook ansible/pg-repli-playbook.yaml
is designed to provision
Linux machines with PostgreSQL installed and an instance created, configured
and started, and others with a standby PostgreSQL instances created and
connected to the primary using streaming replication. The supported options to
add to the machine definition are:
- The options supported by the
simple-playbook.yaml
. - The options supported by the
pg-playbook.yaml
. postgresql
replication
: Dictionary of replication specifics settings.rolename
: Name of the PostgreSQL replication role.password
: Password of the PostgreSQL replication role.
The supported Ansible groups are:
pgprimary
: machines where a PostgreSQL primary instance will be created.pgstandby
: machines where a PostgreSQL standby instance will be created.
FIXME not supported yet, WIP
The template playbook ansible/pg-repli-paf-playbook.yaml
is designed to
provision Linux machines with PostgreSQL installed and an instance created,
configured and started, and others with a standby PostgreSQL instances created
and connected to the primary using streaming replication. The supported
options to add to the machine definition are:
- FIXME specific, custom package list?
- FIXME postgres
- FIXME postgres replication
The supported Ansible groups are:
pgprimary
: machines where a PostgreSQL primary instance will be created.pgstandby
: machines where a PostgreSQL standby instance will be created.