IT & Engineering

Devgun: Entwicklungsumgebungen mit Kubernetes erstellen

Als wir das erste Mal vor der Herausforderung standen, lokale Entwicklungsumgebungen zu erstellen, griffen wir auf gängige Tools wie Vagrant zurück. Aber wie bei den meisten mit Vagrant erstellten Umgebungen sind die Build-Zeiten lang. Das bedeutet, dass Vagrant-Bilder lange leben und dazu neigen, mit der Zeit abzuweichen.
Bild für Devgun: Entwicklungsumgebungen mit Kubernetes erstellen

Als wir das erste Mal vor der Herausforderung standen, lokale Entwicklungsumgebungen zu erstellen, griffen wir auf gängige Tools wie Vagrant zurück. Aber wie bei den meisten mit Vagrant erstellten Umgebungen sind die Build-Zeiten lang. Das bedeutet, dass Vagrant-Bilder lange leben und dazu neigen, mit der Zeit abzuweichen.

Unsere Dienste und Infrastruktur ändern sich ständig, daher schlug der Vagrant-Build fast immer fehl. Wir wollten das klassische „Aufnahmeritual für neues Entwicklungspersonal“ vermeiden, bei dem es leicht Tage dauert, bis Vagrant erfolgreich eine neue Entwicklungs-VM aufgebaut hat.

Im Idealfall können neue Teammitglieder schon wenige Stunden nach ihrer Einstellung produktiv arbeiten, nicht erst nach Tagen oder Wochen.

All dies wurde durch die Tatsache erschwert, dass wir viele Microservices haben, die in der Entwicklungsumgebung laufen und sich nahtlos integrieren müssen.

Die Projektziele waren einfach:

  • Eine Entwicklungsumgebung schnell und reproduzierbar einrichten und abbauen.
  • Einrichtung und Abbau der Entwicklungsumgebung in einem einzigen Schritt.
  • Dienste einschließlich ihrer Abhängigkeiten nach Belieben starten und stoppen.

Evaluierung von Orchestrierungsplattformen

Da unsere Microservices bereits in Containern liefen, war uns klar, dass wir uns für ein Orchestrierungssystem entscheiden mussten.

Einige Leute in unserem Entwicklungsteam interessierten sich für Mesos Marathon, also testeten wir das zuerst. Leider waren die Speicher- und Hardwareanforderungen, um Marathon in einer kleinen lokalen Entwicklungsumgebung auszuführen, für unsere Zwecke viel zu restriktiv. Zum Zeitpunkt unserer Tests war Minimesos außerdem nicht in der Lage, Container in Marathon korrekt mit dem lokalen Netzwerk zu vernetzen – ein großes Hindernis für unser Projekt. Diese Probleme machten deutlich, dass Mesos für unsere Anforderungen ungeeignet sein würde.

Als Nächstes evaluierten wir Kubernetes und Minikube , da uns die lebendige Community rund um diese Projekte begeisterte. Wir stellten fest, dass der Speicherbedarf minimal war und die Vernetzung reibungslos funktionierte. Die meisten Funktionen, die uns interessierten, funktionierten auf Anhieb, und unsere Drittanbieter-Anwendungen in Minikube zum Laufen zu bringen, erwies sich als einfacher als gedacht.

Mit Minikube als Plattform unserer Wahl konnten wir das Projekt schnell vorantreiben und die meiste Zeit in die Entwicklung dessen investieren, was später Devgun werden sollte.

Eine CLI entwickeln

Um unsere Projektziele zu erreichen, beschlossen wir, eine All-in-One-Befehlszeilenschnittstelle in Golang zu entwickeln. Wir wollten eine CLI, die als einzelne Binärdatei an unser Entwicklungsteam verteilt werden konnte. Deshalb haben wir eine mit dem Namen Devgun erstellt.

Minikube and Mailgun logos with plus symbol in between

Devgun trifft keine Annahmen über die Entwicklungsumgebung. Es lädt automatisch alle benötigten Tools, einschließlich Minikube, kubectl und Mailgun-spezifischer Tools, in das Verzeichnis /.devgun/bin herunter. Alles, was Sie tun müssen, ist Ihren Pfad hinzuzufügen, nachdem die anfängliche Einrichtung abgeschlossen ist. Da alles in einem einzigen Verzeichnis installiert wird, ist die Deinstallation so einfach wie rm -rf ~/devgun.

Wir haben alle Kubernetes-Manifestdateien mithilfe des go-bindata-Projekts in die statische Binärdatei kompiliert, was das Herunterladen und Ausführen einer einzigen Datei zur Installation einer Entwicklungsumgebung ermöglicht.

Die Ausführung von Devgun sieht wie folgt aus:

                                

                                    $ devgun startrnPulling kubectl                              [done]  rnPulling minikube                             [done]  rnWriting Minikube configuration               [done after 0.702698 seconds]  rnBooting Minikube environment                 [done after 77.297039 seconds]  rnWaiting for Kubernetes..                     [done]  rnINFO[0148] Setting up minikube routes -- enter your sudo password if prompted  rnModifying routes                             [done after 0.012867 seconds]  rnAdding kube-dns resolver entry               [done after 0.002070 seconds]  rnApplying kube-dns-external configuration     [done after 0.212881 seconds]  rnEnabling Heapster                            [done after 37.506335 seconds]  rn========================================================rnMinikube is now configured and running....rnrn# Set up path for our bin directory with dev toolsrnexport PATH="$PATH:/Users/thrawn/.devgun/bin"rnrnNext you should choose a mailgun service to start using <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service start</code>rnrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service list</code> to see a list of services to startrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">devgun service start</code> to start a service and its dependenciesrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl get pods</code> to list running podsrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl describe pod <pod-name></code> to inspect a pod and see the pod logrn* Use <code data-enlighter-language="generic" class="EnlighterJSRAW">kubectl log <pod-name></code> to see the container logsrn========================================================rn
                                
                            

Zusätzlich zur Erstellung einer Kubernetes-Umgebung fügt Devgun dem lokalen Rechner auch einige Netzwerkrouten hinzu. Unter OS X werden beispielsweise die folgenden Routen hinzugefügt:

route -n add 172.17.0.0/16
route -n add 10.0.0.0/24

Dies ermöglicht es unserem Entwicklungsteam, Anwendungen auf ihren lokalen Rechnern mit vollständiger Konnektivität zu Containern im k8-Cluster auszuführen und zu testen, als ob sie selbst im Cluster liefen. Wir ermöglichen außerdem DNS-Lookups, indem wir die in OS X integrierte Resolver-Funktionalität nutzen. Wir erstellen /etc/resolver/local mit dem folgenden Inhalt:

search cluster.local svc.cluster.local default.svc.cluster.local
nameserver 172.17.0.3

Dadurch wird die DNS-Auflösung von Kubernetes-Diensten ermöglicht.

                                

                                    $ devgun service start etcdrnStarting service: etcd                       [done after 7.084730 seconds]rnrn$ ping etcdrnPING etcd.default.svc.cluster.local (172.17.0.4): 56 data bytes  rn64 bytes from 172.17.0.4: icmp_seq=0 ttl=63 time=0.220 ms  rn^Crn--- etcd.default.svc.cluster.local ping statistics ---rn1 packets transmitted, 1 packets received, 0.0% packet loss  rnround-trip min/avg/max/stddev = 0.220/0.220/0.220/0.000 ms  
                                
                            

Verwaltung von benutzerdefinierten und Drittanbieter-Diensten mit einer Spezifikation

Da Devgun eine Mischung aus benutzerdefinierten und Drittanbieter-Diensten verwalten muss, haben wir eine spezielle YAML-Spezifikationsdatei entwickelt, die wir für jeden Dienst definieren. Die Spezifikationsdatei sieht in etwa so aus:

                                

                                    ervice:  rn  name: scoutrn  resources:rn    <<: *k8s_deploy_resourcesrn  depends_on:rn  - name: vulcandrn  - name: cassandrarn  - name: kafka-pixyrn  - name: kafkarn  - name: etcdrn  - name: metricsrn  hooks:rn    pre:rn      start:rn        - exec: >rn            cqlsh -e "CREATE KEYSPACE IF NOT EXISTS scout WITH REPLICATION={'class':'SimpleStrategy','replication_factor':1}" $POD_IPrn          where: service:cassandra:cassandra
                                
                            

Sie definiert einen benutzerdefinierten Dienst namens „scout“, der Ereignisse aus Kafka liest und Analysen über die Ereignisse in Cassandra aufzeichnet. Die Spezifikation teilt Devgun mit, von welchen benutzerdefinierten und Drittanbieter-Diensten er abhängt und welche Hooks auf den verschiedenen Containern ausgeführt werden sollen, bevor der Scout-Dienst gestartet wird.

Der Schlüssel resources verweist auf die Kubernetes-Manifestdateien wie ConfigMaps, Deployments und Dienstbeschreibungen, die an anderer Stelle in der Spezifikationsdatei definiert sind und die Devgun verwendet, um die Container in K8 zu starten.

Wie es weitergeht … zukünftige Arbeit

Als wir Devgun entwarfen, begannen wir von unten nach oben, ohne die größeren Entwicklungs- und Bereitstellungsszenarien zu berücksichtigen. Nachdem wir nun Zeit hatten, Devgun zu nutzen, fragen wir uns, ob wir die Abstraktionen richtig gewählt haben.

Wir begannen, uns Fragen zu stellen: Welche Erfahrung möchten wir unserem Entwicklungsteam bieten, wenn es sich daransetzt, einen neuen Dienst zu erstellen und bereitzustellen? Wo enden die Zuständigkeiten des Entwicklungsteams und wo beginnen die Aufgaben des Betriebs? Wie viel des Betriebs können wir automatisieren und wie viel erfordert menschliches Eingreifen? Wie erleichtern wir die Informationsweitergabe zwischen der Entwicklung und dem Betrieb?

Wir haben damit begonnen, User Stories und Personas zu definieren, die beeinflussen werden, wie sich Devgun in Zukunft weiterentwickelt. In meinem nächsten Beitrag werde ich einige unserer Arbeiten und Gedanken dazu teilen, wie sich die Developer Experience weiterentwickeln könnte, während wir weiterhin mit Kubernetes und Devgun arbeiten. Abonnieren Sie unseren Blog, damit Sie nichts verpassen.