Puppet Development Workflow mit Vagrant

Wir von VSHN wollen unsere Kunden bei einem sauberen Lifecycle Management ihrer Software unterstützen. Dafür stellen wir ihnen mit Hilfe von Puppet mehrere Umgebungen zur Verfügung. Dies kann mit einer Testmaschine für die Entwickler beginnen,Integrations-Systemen, Q&A, einer Preprod-Umgebung, um das Deployment zu testen, und zu guter Letzt eine Produktionsinfrastruktur. All diese Umgebungen müssen grundsätzlich die Konfiguration der Produktion widerspiegeln und nur in den gewünschten Punkten des aktuellen Lifecycles davon abweichen.

Puppet Workflow

Diese Synchronisation der Konfigurationen stellen wir mit Hilfe von Puppet sicher. Wir verwenden das Roles and Profiles Pattern. Dazu verwenden wir Puppet Environments mit r10k um die Module zu verwalten, eine Hiera-Hierarchie für die Konfigurationen der Rollen und Yaml Files als External Node Classifier (ENC), um einem Server eine Rolle zuordnen zu können.

Grundsätzlich können nun sowohl Puppet Base Module als auch Customer Module mit Profilen in einer Testumgebung entwickelt werden. Die weiteren Umgebungen bleiben davon unberührt, da die Modulversion im Puppetfile festgelegt werden kann. Doch schon hier fangen die Probleme an. Ich muss jede kleine Änderung ins Git Repository einchecken, Puppet ausführen, die Fehlermeldung analysieren und den Typo korrigieren. Dies ist nicht nur umständlich, es ergibt auch viele unnütze Git commits und macht so die Übersicht im Git Log zunichte.

Was, wenn nun aber mehrere von uns für den selben Kunden etwas machen müssen? Müssen wir uns einen Testserver teilen? Oder was, wenn ich ein Bugfix für die Produktion implementieren muss, mein Kollege aber schon an der neuen Version des Modules arbeitet?

Local Development

Diese und ähnliche Fragen haben uns sehr schnell aufgezeigt, dass es von Vorteil wäre, mit einer lokalen Umgebung zu arbeiten. Doch einfach eine Virtuelle Maschine zu erstellen birgt einige Probleme:

  • Ich muss mich gegenüber dem Puppetmaster registrieren (Cert Sign).
  • Ich brauche ein ENC.
  • Ich muss immer noch alle Änderungen im Git einchecken.
  • Ich kann nicht einfach Hiera-Daten verändern, ohne die Produktion zu tangieren.
  • Ich brauche ein eigenes r10k Environment.
  • Ich muss aufräumen, wenn ich die Maschine nicht mehr brauche.

All diese Probleme führten uns zum Schluss: Jeder braucht seinen eigenen Master.

My First Puppet Master

Um jedem von unseren DevOps Engineers möglichst einfach einen Puppet Master zur Verfügung zu stellen, haben wir ein eigenes Puppet Modul geschrieben. Dies kann nicht nur den Puppet client einrichten, sondern auch mit „Puppet Apply“ einen Master provisionieren. Unsere Vagrant Umgebung nutz dies um beim ersten start einen Master zu erstellen.

Die Vagrant Umgebung

Unsere Entwicklungsumgebung besteht aus einem Pupppet Master und zusätzlichen Client VMs, welche wir als Testumgebungen verwenden können.

Der Master

Den Puppetmaster definieren wir als normale Vagrant Maschinen. Von aussen werden aber einige Ordner in die virtuelle Umgebung gemounted. Wir können so sowohl die Module an welchen wir arbeiten, als auch die Hiera- und ENC-Daten von der Hostmaschine aus editieren. So kann der Master bei allen Technikern gleich aussehen und trotzdem kann jeder mit seinem bevorzugten Editor, respektive seinen eigenen Einstellungen und Workflow arbeiten.

Das eigentlich Bootstrapping des Masters geschieht mithilfe von Bash Scripts, welche Puppet und r10k installieren. Als zweiten Provider verwenden wir anschliessend Puppet selbst als local apply.

So kann sich jeder selbst einfach einen funktionierenden Puppetserver einrichten, ohne in Konflikt mit den anderen DevOps zu kommen oder gar ein produktives System zu beeinträchtigen.

Die Client VMs

Ich möchte nur einen Master auf meinem Laptop haben. Aber je nachdem was ich gerade entwickle, brauche ich einen oder mehrere Clients zur gleichen Zeit. Ich will auch nicht jedes Mal, wenn ich kurz etwas für einen Kunden erledigen will, die gesamte Umgebung eines anderen Kunden wieder löschen.

Natürlich kann ich jede Maschine im Vagrantfile erstellen. Doch viel schöner ist es, einfache yaml definitions zu schreiben. Dieses Yaml brauchen wir zugleich auch als ENC data für den lokalen Puppet master. So muss jede Test-VM nur an einem einzigen Ort definiert werden.

---
fqdn: 'vagrant.dev'
cores: 1
memory: 512
forwarded_ports:
  - guest: 80
    host: 8081
  - guest: 443
    host: 8044
private_networks:
  default:
    type: 'static'
    ip: '192.168.215.11'
    auto_config: true
aliases:
  - agent1a
  - agent1b
disks:
  - name: 'data1'
    size: 1

Private Entwicklung

Mit dem DevOps Gedanken kommt die Idee von Infrastructure as code. Es braucht neue Tools und Wege, um so etwas zu entwickeln, testen und deployen. Wir haben unser Tool mit dieser Vagrant-Umgebung gefunden. Wir sind in der Lage, schnell und gezielt neue Features zu implementieren, aber auch ein bestehendes System zu Debugging-Zwecken zu erstellen. Dies bringt uns die nötige Flexibilität, um unseren Kunden den bestmöglichen Service zu bieten.