Understanding DevOps and Cloud Maturity Models: A Guide to Elevating Your IT Strategy
In today’s fast-paced technological landscape, DevOps and Cloud practices are integral to accelerating software delivery and optimizing cloud resources. But as
Setting up consistent testing environments is essential for development, and Vagrant combined with Ansible is a powerful, flexible solution for automating this process on local virtual machines. Vagrant, an open-source tool from HashiCorp, simplifies the creation and management of virtualized environments, while Ansible automates the configuration within those environments using playbooks. Here’s a look at how this combination can streamline testing infrastructure setup.
Vagrant is designed to work with local virtualization tools like VirtualBox, providing developers with an easy way to spin up and tear down VM environments. Ansible, on the other hand, is a configuration management tool that uses simple YAML playbooks to define and enforce server configurations.
By using Vagrant to create the base virtual machine and Ansible to handle provisioning, you can:
Using the yaml inventory style to define a inventory with virtual machines that we need for our testing setup. Ansible inventory is also able to define custom variables for certain hosts and groups. So, along with the predefined ansible configuration values within the inventory, we can add variables within this configuration file to define for example:
1---
2all:
3 hosts:
4 testserver01:
5 ansible_host: 192.168.199.9
6 ansible_user: vagrant
7 ansible_ssh_private_key_file: .vagrant/machines/testserver01/vmware_fusion/private_key
8 forwarded_ports:
9 - guest: 8200
10 host: 8200
11
12 testserver02:
13 ansible_host: 192.168.199.10
14 ansible_user: vagrant
15 ansible_ssh_private_key_file: .vagrant/machines/testserver02/vmware_fusion/private_key
16 cpu: 4
17 memory: 4096
18 forwarded_ports:
19 - guest: 80
20 host: 8080
21 - guest: 8080
22 host: 8088
23
24 testclient:
25 ansible_host: 192.168.199.100
26 ansible_user: vagrant
27 ansible_ssh_private_key_file: .vagrant/machines/testclient/vmware_fusion/private_key
28 synced_folders:
29 - src: ./client
30 dest: /usr/local/client/
31 shell_always:
32 cmd: "echo VAULT_ADDR=https://192.168.199.9:8200 >> ~/.bashrc"
33
34 children:
35 vault_nodes:
36 hosts:
37 testserver01:
38
39 docker_nodes:
40 vars:
41 docker_users:
42 - vagrant
43
44 hosts:
45 testserver02:
Combining these technologies is available out of the box, because vagrant can run ansible provisioning tasks. So the logical next step is to use the ansible inventory configuration to have a single definition of actions and machines for our use case(s). Vagrantfiles are written in ruby, that allows us to write further ruby code to enhance the functionality. And this leads to following example on how to combine a ansible inventory with a vagrantfile:
1require 'rbconfig'
2require 'yaml'
3
4ENV["LC_ALL"] = "en_US.UTF-8"
5DEFAULT_BASE_BOX = 'bento/ubuntu-24.04'
6FORCE_LOCAL_RUN = false
7VAGRANTFILE_API_VERSION = '2'
8PROJECT_NAME = '/' + File.basename(Dir.getwd)
9
10inventory = YAML.load_file(File.join(__dir__, 'hosts.yml'))
11hosts = inventory['all']['hosts']
12
13def network_options(host)
14 options = {}
15
16 if host.key?('ansible_host')
17 options[:ip] = host['ansible_host']
18 options[:netmask] = host['netmask'] ||= '255.255.255.0'
19 else
20 options[:type] = 'dhcp'
21 end
22
23 options[:mac] = host['mac'].gsub(/[-:]/, '') if host.key?('mac')
24 options[:auto_config] = host['auto_config'] if host.key?('auto_config')
25 options[:virtualbox__intnet] = true if host.key?('intnet') && host['intnet']
26 options
27end
28
29def custom_synced_folders(vm, host)
30 return unless host.key?('synced_folders')
31 folders = host['synced_folders']
32
33 folders.each do |folder|
34 vm.synced_folder folder['src'], folder['dest'], folder['options']
35 end
36end
37
38def shell_provisioners_always(vm, host)
39 if host.has_key?('shell_always')
40 scripts = host['shell_always']
41
42 scripts.each do |script|
43 vm.provision "shell", inline: script['cmd'], run: "always"
44 end
45 end
46end
47
48def forwarded_ports(vm, host)
49 if host.has_key?('forwarded_ports')
50 ports = host['forwarded_ports']
51
52 ports.each do |port|
53 vm.network "forwarded_port", guest: port['guest'], host: port['host']
54 end
55 end
56end
57
58Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
59 hosts.each do |idx, host|
60 config.vm.define idx do |node|
61
62 node.vm.box = host['box'] ||= DEFAULT_BASE_BOX
63 node.vm.hostname = idx
64 node.ssh.insert_key = true
65 node.ssh.forward_agent = true
66
67 node.vm.provider :virtualbox do |vb|
68 vb.memory = host['memory'] ||= 2048
69 vb.cpus = host['cpus'] ||= 2
70 end
71 node.vm.provider :vmware_fusion do |v|
72 v.gui = true
73 v.vmx["memsize"] = host['memory'] || "2048"
74 v.vmx["numvcpus"] = host['cpu'] || 2
75 v.vmx["cpuid.coresPerSocket"] = "1"
76 node.vm.network "private_network", ip: host['ansible_host']
77 end
78
79 node.vm.network "private_network", network_options(host)
80
81 node.vm.synced_folder ".", "/vagrant", disabled: true
82 custom_synced_folders(node.vm, host)
83 shell_provisioners_always(node.vm, host)
84 forwarded_ports(node.vm, host)
85
86 end
87 end
88end
Using Vagrant with Ansible is ideal for:
This combination of tools allows for flexible, efficient local testing infrastructure that closely mirrors production setups, making it a valuable solution for any developer or DevOps engineer working on configuration management and automation.
You are interested in our courses or you simply have a question that needs answering? You can contact us at anytime! We will do our best to answer all your questions.
Contact us