Vagrant - Multi-Group Ansible Provisioning

2 minute read

Refreshed June 2026: the Vagrant ansible.groups mechanism shown here still works the same way, so the core of the post is unchanged. What needed updating was the example playbook (FQCN, list arguments, community.mysql modules, current PHP packages instead of the long-dead php5) and the generated inventory, which modern Vagrant writes with ansible_host rather than the old ansible_ssh_host.

Background

I keep a common Vagrantfile across scenarios and only adjust variables per scenario. One of those variables defines the Ansible groups each box lands in. This post spins up 5 boxes and places them into several Ansible groups. If you want the full base Vagrantfile, see my complex Vagrantfile post.

Defining The Groups

Bump the node count from 1 to 5:

N = 5

Then define the group mapping. A node can appear in more than one group:

ansible_groups = {
  "db-nodes" => [
    "node0"
  ],
  "test-nodes" => [
    "node3"
  ],
  "random-nodes" => [
    "node[4:#{N-1}]"
  ],
  "mixed-nodes" => [
    "node1",
    "node4"
  ],
  "renamed-nodes" => [
    "node1"
  ]
}

After vagrant up, the generated Ansible inventory looks like this. Note the modern connection variables (ansible_host, ansible_port, ansible_user); older Vagrant emitted the now-deprecated ansible_ssh_host forms:

## Generated by Vagrant

node0 ansible_host=127.0.0.1 ansible_port=2222 ansible_user='vagrant' ansible_ssh_private_key_file='~/projects/Vagrant/ansible/.vagrant/machines/node0/virtualbox/private_key'
node1 ansible_host=127.0.0.1 ansible_port=2200 ansible_user='vagrant' ansible_ssh_private_key_file='~/projects/Vagrant/ansible/.vagrant/machines/node1/virtualbox/private_key'
node2 ansible_host=127.0.0.1 ansible_port=2201 ansible_user='vagrant' ansible_ssh_private_key_file='~/projects/Vagrant/ansible/.vagrant/machines/node2/virtualbox/private_key'
node3 ansible_host=127.0.0.1 ansible_port=2202 ansible_user='vagrant' ansible_ssh_private_key_file='~/projects/Vagrant/ansible/.vagrant/machines/node3/virtualbox/private_key'
node4 ansible_host=127.0.0.1 ansible_port=2203 ansible_user='vagrant' ansible_ssh_private_key_file='~/projects/Vagrant/ansible/.vagrant/machines/node4/virtualbox/private_key'

[db-nodes]
node0

[test-nodes]
node3

[random-nodes]
node4

[mixed-nodes]
node1
node4

[renamed-nodes]
node1

Provisioning By Group

With the groups in place, the playbook targets them. Here it is modernized to FQCN, list arguments, and the community.mysql modules:

- hosts: db-nodes
  become: true
  vars:
    install_django: true
    mysql_root_password: root
    pri_domain_name: test.vagrant.local
  roles:
    - role: ansible-django
      when: install_django
    - role: ansible-mariadb-mysql
  tasks:
    - name: Install prerequisites
      ansible.builtin.apt:
        name:
          - curl
          - libapache2-mod-php
          - php-curl
          - php-sqlite3
          - php-mbstring
          - sqlite3
        state: present
        update_cache: true
      when: ansible_os_family == "Debian"

    - name: Allow root login to MySQL from anywhere
      community.mysql.mysql_user:
        name: root
        host: "%"
        password: "{{ mysql_root_password }}"
        priv: "*.*:ALL,GRANT"

    - name: Create the Django database
      community.mysql.mysql_db:
        name: django_db
        state: present
      when: install_django

    - name: Install Django related apps
      ansible.builtin.pip:
        name:
          - django-markdown-deux
          - django-tables2
        state: present
      when: install_django

- hosts: mixed-nodes
  become: true
  vars:
    pri_domain_name: test.vagrant.local
  roles:
    - role: ansible-nginx

- hosts: all
  become: true
  vars:
    enable_manage_ssh_keys: true
    manage_ssh_keys:
      - remote_user: vagrant
        state: present
        keys:
          - "~/.ssh/id_rsa.pub"
  roles:
    - role: ansible-manage-ssh-keys

A few notes on the changes:

  • ansible.builtin.apt and ansible.builtin.pip take a list directly, so the old with_items loops are gone.
  • The php5 packages (libapache2-mod-php5, php5-curl, php5-mcrypt) are long retired. The current equivalents are libapache2-mod-php, php-curl, and php-mbstring. php-mcrypt was removed from PHP entirely in 7.2, so it is dropped.
  • mysql_user and mysql_db now live in community.mysql, and the single-item with_items on the MySQL user is replaced with host: "%" directly. Heads up: these modules are being promoted to a new ansible.mysql collection, and community.mysql will drop them in its 6.0.0 release, so expect to switch the namespace to ansible.mysql before long.

Conclusion

The grouping trick is the same as it was: define ansible_groups in the Vagrantfile, let Vagrant generate the inventory, and target groups in your plays. Only the playbook contents needed a modern coat of paint.

Enjoy!

Comments