Vollautomatische Modularisierung

Go Modules Revisited: Aktiv by default

Jan Stamer

© Reneé French (CC BY 3.0 DE / modifiziert)

Go 1.11 hat einen Paradigmenwechsel eingeleitet. Aus Go Packages werden versionierte Go-Module. Go-Module lösen den GOPATH ab und werden fester Bestandteil der Go Toolchain. Bis jetzt mussten Go-Module explizit aktiviert werden. Mit Go 1.13 ändert sich das. Ihr lernt was Go 1.13 in Sachen Go Modules bringt und was sich seit Go 1.11 getan hat.

Mit Go 1.11 wurde Go um Module erweitert. Damit beginnt für Go eine neue Ära. Denn aus Go Packages werden versionierte Go Module. Go Module ersetzen nicht nur Packages sondern auch gleich den GOPATH. So der Plan. Denn noch sind Go Module nur experimentell, daran ändert sich auch mit Go 1.13 nichts. Aber mit Go 1.13 kommen wichtige neue Funktionen zu Go Modules hinzu: Go Module sollen durch Mirrors schneller und zuverlässiger werden. Und mit Module Authentication werden Go Module zudem noch sicherer. Klingt vielversprechend, nicht? Aber bevor wir zu den neuen Features kommen rekapitulieren wir kurz was Go Module bringen. Und wir werfen einen Blick darauf wie Go Module von der Go Community angenommen werden.

Was Go Module bringen

Go-Module machen aus Go Packages versionierte Module. Aus dem Pfad des Packages im GOPATH wird der Importpfad des Go-Moduls. Die Version des Moduls kommt neu hinzu. So wird aus dem Pfad $GOPATH/github.com/gorilla/mux des Packages Gorilla Mux ein Go-Modul mit Importpfad github.com/gorilla/mux und Version 1.6.2. Der Importpfad des Go-Moduls ersetzt den Pfad des Packages im GOPATH. Der GOPATH wird damit auf lange Sicht überflüssig.

Ein Go-Modul enthält die beiden Konfigurationsdateien go.mod und go.sum. In der Datei go.mod steht der Importpfad des Go-Moduls und alle Abhängigkeiten des Moduls (mit Importpfad und Version). Die go.sum enthält Hashes aller Modulabhängigkeiten. Anhand der Hashes wird sichergestellt, dass zukünftige Builds auch immer exakt denselben Code des Moduls erhalten.

Go-Module sind ein Teil von Go. Go unterstützt sie seit Go 1.11. Allerdings müssen Go Modules mit der Umgebungsvariable GO111MODULE=on aktiviert werden. Bestehende Tools wie go get funktionieren wie gewohnt, auch mit Go-Modulen. Neu hinzugekommen ist das Go Tool mod. Mit go mod init wird ein neues Go-Modul erstellt, mit go mod graph wird ein Graph der Modulabhängigkeiten auf der Kommandozeile ausgegeben.

Mit Go-Modulen wird die Verwaltung der Abhängigkeiten eines Projektes fester Bestandteil von Go. Go-Module sollen Community-Lösungen wie dep [1] ersetzen, aber auch das mit Go 1.5 eingeführte Vendoring überflüssig machen. Go-Module sind somit eines der wichtigsten Features auf dem Weg zu Go 2. Eine ausführliche Einführung in Go Module findet Ihr unter [2].

Wie Go Modules ankommen

Die Einführung von Go-Modulen hätte kaum schlechter starten können. Googles Go-Team hat zu lange hinter den Mauern des Googleplex gearbeitet und zu wenig mit der Go Community außerhalb von Google kooperiert und kommuniziert. Aber ohne die Go Community geht es nicht. Die Verbreitung und das Angebot an Modulen entscheiden über Erfolg oder Misserfolg der Go-Module. Und die Mehrzahl der Module kommt eben aus der Go Community. Schauen wir also, wie weit die Umsetzung von Go-Modulen in großen Open-Source-Projekten gediehen ist.

Die Akzeptanz und Umsetzung in der Go Community betrachten wir am Beispiel der vier großen Go-Open-Source-Projekte Kubernetes [3], Packer [4], CockroachDB [5] und Flynn [6], mit Stand August 2019.

Kubernetes nutzt Go-Module seit der Version 1.15 von Juni 2019 [7]. Die Datei go.mod von Kubernetes ist 474 Zeilen groß und enthält viele direkte und indirekte Modul-Imports und 294 Modul-Replacements. Die erste Version der go.mod stammt aus dem Januar 2019. Das erste Ticket zu Go-Modulen gab es im August 2018. Das Kubernetes-Projekt hat also 12 Monate für den Umstieg auf Module benötigt. Für ein Projekt mit 1.4 Millionen Zeilen Go Code finde ich das erstaunlich schnell. Ein Blick in die go.mod zeigt jedoch, dass die Datei derzeit über ein Shell-Skript erzeugt wird, das im Verzeichnis hack liegt. In Kubernetes gibt es auch weiterhin ein vendor-Verzeichnis, das viele Package-Abhängigkeiten enthält. Scheint so, als gebe es noch ein paar Workarounds zu lösen, bis alles auch sauber implementiert ist.

DevOpsCon Istio Cheat Sheet

Free: BRAND NEW DevOps Istio Cheat Sheet

Ever felt like service mesh chaos is taking over? As a follow-up to our previous cheat sheet featuring the most important commands and functions, DevOpsCon speaker Michael Hofmann has put together the 8 best practices you should keep in mind when using Istio.

Hashicorp Packer unterstützt Go-Module seit dem Release 1.4.0 von April 2019. Die go.mod stammt aus dem November 2018. Sie ist 135 Zeilen groß, enthält 130 Imports und keine Replacements. Packer hat 1.4 Millionen Zeilen Go Code und brauchte für die Umstellung auf Go Modules 6 Monate.

CockroachDB hat Go-Module noch nicht umgesetzt. Es gibt ein Ticket dazu [8], das derzeit für Version 19.2 geplant ist (im Moment im Status Alpha, Release-Datum nicht bekannt). Das CockroachDB Repository enthält 810.000 Zeilen Go Code.

Flynn umfasst 550.000 Zeilen Go Code. Noch setzt Flynn auf die Community-Lösung dep, um die Abhängigkeiten zu verwalten. Aktivitäten in Richtung Go-Module konnte ich nicht erkennen.

Einige der großen Go-Open-Source-Projekte haben schon auf Go Modules umgestellt. Der Zeitraum für die Umstellung erscheint angemessen. Die Tatsache, dass überhaupt schon so viele Projekte auf Go-Module umstellen zeigt, dass ein Bedarf für Go Module da ist und sie von der Community angenommen werden. Schließlich sind Go-Module noch in einem experimentellen Stadium und werden es auch bis Go 2 bleiben. Go-Module werden behutsam und vorsichtig eingeführt. Damit bleiben Stabilität und Langfristigkeit gewährleistet. Das ist dem Go-Team sehr wichtig.

Was bringt Go 1.13 für Modules

Mit Go 1.13 gehen Go-Module in die nächste Stufe der Umsetzung. Sie müssen nun nicht mehr explizit aktiviert werden. Wenn das Kommando go im aktuellen Verzeichnis eine go.mod-Datei findet, sind Go-Module automatisch aktiviert. Egal ob im GOPATH oder außerhalb.

Um Go-Module schneller und robuster zu machen, werden mit Go 1.13 Module Mirrors und Module Authentication eingeführt, um das Ökosystem der Go Modules sicher zu machen. Mehr Infos zu Module Mirrors und Authentication folgen den nächsten beiden Abschnitten.

Go Module Mirrors

Aktuell lädt Go Packages direkt von dem Server herunter, der das Package veröffentlicht. Das Package mit dem Gorilla Mux liegt auf GitHub, es wird also direkt von https://github.com/gorilla/mux heruntergeladen. Das hat einen Nachteil: Beim Build bestimmt der langsamste und unzuverlässigste Server, von dem eine Abhängigkeit benötigt wird, die Performance. Dafür funktioniert es dezentral, das ist ein Vorteil. Bisher gibt es dafür nur eine Lösung: alle Abhängigkeiten ins vendor-Verzeichnis packen und mit einchecken.

Go 1.13 bringt mit Go Module Mirrors eine weitere Lösung, die das vendor-Verzeichnis ablösen soll. Abhängigkeiten auf Go-Module lädt Go jetzt immer über Mirrors herunter. Mirrors sind zentrale Registrys für Go-Module. Go Module Mirrors entsprechen den Maven Repositorys von Java oder den npm Repositorys von Node. Ein Module Mirror ist eine zentrale Instanz, die Go-Module herunterlädt, in einem Cache hält und somit schnell und effizient zum Download bereitstellen kann. Über die Umgebungsvariable GOPROXY wird gesteuert, welcher Go Module Mirror verwendet wird. Der Google Proxy proxy.golang.org ist die Standardeinstellung, und seit dem 29. August auch für den produktiven Einsatz freigegeben (siehe [9]).

Der Proxy kann auch für gewisse Module übersprungen werden. Das wird über die Umgebungsvariable GONOPROXY gesteuert. Es können mehrere Modul-Importpfade mit Komma getrennt konfiguriert werden, auch Wildcards sind möglich. Ein Beispiel ist GONOPROXY=*. comdirect.de,remast.io/private, um die Module-Importpfade *. comdirect.de und remast.io/private nicht über den Proxy herunterzuladen (mit * als Wildcard).

Laut Tests des Go-Teams [10] wird der Download von Go-Modulen über den Go Module Mirror in schnellen Netzwerken bis zu 3-mal so schnell und in langsamen bis zu 6-mal so schnell wie bisher. Das klingt doch vielversprechend. Ein weiterer Vorteil der Go Module Mirrors ist, dass größere Unternehmen einen eigenen Module Mirror betreiben können, der all ihre Go-Module speichert. In Java ist das schon so. Größere Unternehmen betreiben in der Regel ein eigenes Maven Repository.

Es gibt noch andere Gründe, die dafür sprechen, einen Go Module Mirror als Proxy zu verwenden. Eine gute Übersicht gibt Fatih Aslan (der Entwickler von vim-go) in seinem Blog [11].

Go Module Authentication

Go-Module sollen nicht nur schnell sein, sondern auch sicher. Aber was heißt schon sicher? Sicher heißt folgendes: Wir können uns darauf verlassen, genau den Stand eines Moduls zu bekommen, den wir auch haben wollten. Und zwar genau den. Bit für Bit. Aber dazu gibt es doch noch die Datei go.sum, oder nicht?

Die Datei go.sum enthält einen Hash für jede Modulabhängigkeit. Beim Download prüft Go, ob der Hash des soeben heruntergeladenen Moduls dem Hash aus der go.sum entspricht. Ist das der Fall, ist alles in Ordnung. Ist das nicht der Fall, beschwert sich Go mit einem Fehler. Dann stimmt nämlich das soeben heruntergeladene Modul nicht mehr überein mit dem erstmalig heruntergeladenen (und in die go.sum eingetragenen) Modul. Das Modul könnte also seit dem erstmaligen Download kompromittiert oder manipuliert worden sein. In den Hash eines Moduls gehen alle Verzeichnisse und Dateien ein. Jede Abweichung fliegt also unweigerlich auf.

So weit so gut, es gibt nur ein Problem: Kommt eine neue Abhängigkeit auf ein Modul hinzu, steht diese noch nicht in der go.sum. Für die neue Moduläbhängigkeit kann also nicht geprüft werden, ob der richtige Stand heruntergeladen wurde. Genau hier brauchen wir die Go Module Authentication. Die Go Module Authentication stellt nämlich einen Server bereit, der für jedes Go-Modul den korrekten Hash kennt. Beim Download der neuen Modulabhängigkeit prüft Go den Hash des soeben heruntergeladenen Moduls gegen den Hash des Module-Authentication-Services. Stimmt der Hash überein, ist alles bestens. Falls nicht, wurde das Modul verändert und Go meldet einen Fehler.

Analog zur Umgebungsvariable GONOPROXY gibt es die Umgebungsvariable GONOSUMDB, um den Go Module-Authentication-Service für gewisse Module zu überspringen. Ein Beispiel ist GONOSUMDB=*. comdirect.de,remast.io/private.

Der Go Module-Authentication-Service ist die Quelle der Wahrheit. Ihm müssen wir vertrauen. Damit wir ruhigen Gewissens vertrauen können, hat Russ Cox einen Vorschlag [12] für die Implementierung eines sicheren Module-Authentication-Services gemacht. Googles stellt mit sum.golang.org auch schon einen Module-Authentication-Service bereit, der für den produktiven Einsatz geeignet ist [9].

Gopher ante portas: Go hält Einzug auf JAXenter!

Wenige (relativ) neue Programmiersprachen erfreuen sich derzeit einer so großen Belibtheit wie Go. Googles Alternative für „C“ ist immer häufiger Zentrum interessanter Anwendungen und mittlerweile im Mainstream angekommen. Grund genug, sich ein wenig eingehender mit der Sprache zu befassen. Folgende Artikel, Kolumnen und Infografiken sind Teil unserer aktuellen Go-Aktion auf JAXenter:

Happy Gophing!

Private Go Modules

Eine kleine Kleinigkeit fehlt noch, um Go Module Mirrors und Go Module Authentication auch für größere Unternehmen rund zu machen. Nämlich private Module. Private Module dürfen weder von einem Modul-Mirror gecachet werden, noch darf der Hash eines privaten Moduls in einem Module-Authentication-Server landen. Kein Problem. Das erreichen wir, indem wir die Umgebungsvariablen GONOPROXY und GONOSUMDB auf den gleichen Wert setzen, also GONOPROXY =*. comdirect.de,remast.io/private und GONOSUMDB=*. comdirect.de,remast.io/private. Aber einfacher geht es mit GOPRIVATE=*. comdirect.de,remast.io/private, denn genau dazu ist die Umgebungsvariable GOPRIVATE da.

Tool Support für Go-Module

Auch in Sachen Tooling für Go-Module hat sich einiges getan. Es gibt verschiedene Server, die als Mirror Go-Module cachen und bereitstellen. Schon jetzt recht ausgereift ist Athens [13], ein Open-Source-Server, der unter anderem von Microsoft durch Entwickler unterstützt wird.

Als kommerzieller Hersteller eines Repository-Servers unterstützt JFrog Go-Module unter dem Namen „Go Registry“ [14]. Das ist vor allem für Unternehmen interessant. Denn der JFrog Repository-Server kommt zwar aus der Java-Ecke, kann aber inzwischen auch als npm oder Docker Container Registry eingesetzt werden. Der ebenfalls kommerzielle Repository-Server Nexus von Sonatype unterstützt Go-Module [15] laut Webseite des Herstellers Sonatype seit Version 3. Auch Nexus hat als Maven-Repository-Server angefangen und unterstützt inzwischen auch Node, Ruby oder RPM.

Größere Unternehmen nutzen oft schon JFrog oder Nexus als Repository-Server. Sie können direkt loslegen mit Go Module Mirrors, ohne dass sie weitere Infrastruktur benötigen.

Die GitHub Package Registry [16] unterstützt leider keine Go-Module. Ob und wann das geplant ist, ließ sich nicht herausfinden.

Neben den Repository-Servern gibt es auf der FAQ-Seite zu Go-Modulen unter Community Tooling [17] noch weitere Tools aus der Community, um die Arbeit mit Go-Modulen zu erleichtern. Auch die Security-Plattform snyk unterstützt bereits Go-Module [18] und hilft unsichere Package-Abhängigkeiten zu finden.

Erste Schritte in Sachen Tooling für Go-Module sind also gemacht. Allerdings stehen die vorhandenen Tools noch recht am Anfang und da kommt sicher auch noch einiges. Das ist auch völlig in Ordnung, denn Go-Module sind bis dato ein experimentelles Feature. Und das bleibt auch noch eine Weile so.

Wie es weitergeht

Für Go Modules sind bereits weitere neue Funktionen geplant. Das Go-Team arbeitet aktuell daran, Go-Module einfacher auffindbar und durchsuchbar zu machen. Das ist wichtig, damit jeder, der ein Go-Modul braucht, dies auch findet. Sofern es denn bereits vorhanden ist. Dazu wird https://godoc.org noch im Laufe dieses Jahres vollständig überarbeitet. Es ist auch ein Index für Go-Module vorgesehen, der per API die Daten für godoc.org bereitstellt. Also einen Feed von Modul-Updates und neuen Modulen.

Go-Module sind ein riesiger Schritt für Go. Und wie es scheint ein Schritt in die richtige Richtung. Go-Module werden von der Go Community akzeptiert. Viele Projekte steigen schon jetzt auf Go-Module um und nutzen sie zur Verwaltung der Abhängigkeiten anstelle von dep oder Vendoring. Für Projekte ist der Umstieg auf Go Modules in der Regel recht einfach. Falls nicht, ist ein langsamer und behutsamer Migrationspfad vorgesehen. So versöhnt sich das Go-Team nach und nach wieder mit der Community.

Wir dürfen auf jeden Fall gespannt sein, wie es mit Go Modules weitergeht und ob sie wie geplant ihren Weg in Go 2 schaffen.

Verwandte Themen:

Geschrieben von
Jan Stamer
Jan Stamer
Jan Stamer ist Senior-Softwareentwickler bei red6 in Hamburg, einem Spin-off der Hanse-Merkur-Versicherung. red6 entwickelt innovative Insurance-Lösungen mit zeitgemäßen Technologien mit Schwerpunkt auf Java und Node.js.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
4000
  Subscribe  
Benachrichtige mich zu: