Efficient Testing Environments with Vagrant and Ansible: Simplifying Automation


Bicycle

Automatisierte lokale Testumgebungen mit Vagrant und Ansible

Das Einrichten konsistenter Testumgebungen ist entscheidend für die Entwicklung. Die Kombination von Vagrant und Ansible ist eine leistungsstarke und flexible Lösung, um diesen Prozess auf lokalen virtuellen Maschinen zu automatisieren. Vagrant, ein Open-Source-Tool von HashiCorp, vereinfacht die Erstellung und Verwaltung virtualisierter Umgebungen, während Ansible die Konfiguration innerhalb dieser Umgebungen über Playbooks automatisiert. So kann diese Kombination den Aufbau von Testinfrastrukturen effizienter gestalten.

Warum Vagrant und Ansible zusammen verwenden?

Vagrant ist darauf ausgelegt, mit lokalen Virtualisierungstools wie VirtualBox zu arbeiten und bietet Entwicklern eine einfache Möglichkeit, VM-Umgebungen schnell aufzubauen und wieder abzubauen. Ansible ist hingegen ein Konfigurationsmanagement-Tool, das mit einfachen YAML-Playbooks Serverkonfigurationen definiert und durchsetzt.

Durch die Verwendung von Vagrant zur Erstellung der Basis-VM und Ansible zur Bereitstellung von Konfigurationen können Sie:

  1. Konsistenz sicherstellen: Jede Umgebung kann identisch eingerichtet werden, was das „Es funktioniert nur auf meinem Rechner“-Problem reduziert.
  2. Geschwindigkeit erhöhen: Testumgebungen schnell und ohne manuellen Aufwand aufbauen.
  3. Skalierbarkeit verbessern: Mehrere VMs mit spezifischen Rollen oder Konfigurationen nach Bedarf bereitstellen.

Einrichtung von Vagrant und Ansible für lokale Tests

Ein Ansible-Inventar mit erweiterten Optionen definieren

Im YAML-Format lässt sich ein Inventar mit den virtuellen Maschinen definieren, die wir für unser Test-Setup benötigen. Ein Ansible-Inventar kann auch benutzerdefinierte Variablen für bestimmte Hosts und Gruppen definieren. Neben den vordefinierten Ansible-Konfigurationswerten im Inventar können wir Variablen hinzufügen, um beispielsweise Folgendes zu definieren:

  • Weitergeleitete Ports
  • Synchronisierte Ordner
  • Initialisierungsbefehle
 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:

Ansible-Inventar zur Definition von Vagrant-Virtualisierung

Da Vagrant Ansible-Provisionierungsaufgaben ausführen kann, ist die Kombination dieser Technologien direkt verfügbar. Der logische nächste Schritt ist die Verwendung des Ansible-Inventars, um eine einzige Definition für Aktionen und Maschinen für unsere Anwendungsfälle zu haben. Vagrantfiles werden in Ruby geschrieben, was uns ermöglicht, zusätzliche Ruby-Code-Funktionen hinzuzufügen. Hier ist ein Beispiel, wie ein Ansible-Inventar mit einem Vagrantfile kombiniert wird:

 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

Vorteile und Anwendungsfälle

Die Kombination von Vagrant mit Ansible eignet sich hervorragend für:

  • Tests komplexer Multi-VM-Umgebungen, die Produktionsumgebungen simulieren.
  • Entwicklung und Tests von Ansible-Playbooks vor der Produktionseinführung.
  • Erstellung kurzlebiger Umgebungen, die leicht zerstört und neu erstellt werden können.

Diese Kombination bietet eine flexible und effiziente lokale Testinfrastruktur, die Produktionsumgebungen genau nachahmt – eine wertvolle Lösung für Entwickler und DevOps-Ingenieure, die an Konfigurationsmanagement und Automatisierung arbeiten.

Zurück Unsere Trainings entdecken

Wir sind für Sie da

Sie interessieren sich für unsere Trainings oder haben einfach eine Frage, die beantwortet werden muss? Sie können uns jederzeit kontaktieren! Wir werden unser Bestes tun, um alle Ihre Fragen zu beantworten.

Hier kontaktieren