de DevOps Software Gitlab Pipelines

Golang Binaries bauen in Gitlab mit Goreleaser

Es gibt verschiedene Möglichkeiten eine Golang Binary (Programm) zu compilieren und anderen zur Verfügung zu stellen. Wir wollen uns hier einmal anschauen wie man das ganze macht mit hilfe des build Tools goreleaser.

Was ist goreleaser?

Goreleaser ist ein Tool um Golang Programme zu bauen. Der Fokus dabei liegt auf einfachheit, so kann man mittels goreleaser in einem Durchlauf für mehrere Plattformen und Architekturen bauen. Goreleaser unterstützt auch das Veröffentlichen auf den gängigsten Code Plattformen wie Gitlab und Github und ermöglicht es uns auch Docker-Images und Pakete für Debian oder RedHat zur Verfügung zu stellen. Die Seite von dem tool lautet wie folgt: https://goreleaser.com/ Für mehr Informationen rund um das Tool gibt es auch hier einen weiteren Artikel wo es nur um Goreleaser geht:

Die erstellung der Konfigurationsdatei

Natürlich brauchen wir für einen Lauf innerhalb einer Pipeline auch eine Konfigurationsdatei. Wir benutzen hier eine sehr einfache Datei und gehen kurz durch unsere Datei durch:

Die Konfiguration von goreleaser

 1version: 1
 2before:
 3  hooks:
 4    - go mod tidy
 5builds:
 6  - env:
 7      - CGO_ENABLED=0
 8    goos:
 9      - linux
10      - windows
11      - darwin
12    goarch:
13      - amd64
14      - arm64

Hier haben wi den ersten Abschnitt unserer Datei

Abschhnitt Sub Erklärung
version - Versioniert die eigentliche Konfigurationsdatei
before - Hier wird alles rein geschrieben, was vor dem Starten des Build Prozesses ablaufen soll
before hooks hier kann man hooks anlegen die vor dem starten des bau Prozesses ablaufen. Oft wird hier einmal das build enviroment aufgeräumt
builds env Welche Umgebungsvariablen möchte man hinzufügen
builds goos Für welche Betriebssysteme gebaut werden soll
builds goarch In welche Architekturen gebaut werden soll
gitlab_urls use_package_registry Hier wird die Registry für Releases direkt von gitlab genutzt. Wir wollen ja auf gitlab releasen
gitlab_urls use_job_token Der Job Token wird für die authentifizierung mit der registry genutzt

Ein weiterer Abschnitt wäre das changelog und das archives.

 1archives:
 2  - format: tar.gz
 3    # this name template makes the OS and Arch compatible with the results of `uname`.
 4    name_template: >-
 5      {{ .ProjectName }}_
 6      {{- title .Os }}_
 7      {{- if eq .Arch "amd64" }}x86_64
 8      {{- else if eq .Arch "386" }}i386
 9      {{- else }}{{ .Arch }}{{ end }}
10      {{- if .Arm }}v{{ .Arm }}{{ end }}      
11    # use zip for windows archives
12    format_overrides:
13      - goos: windows
14        format: zip

Hier werden die Endungen für das gebaute binary festglegt und kann auch bei bestimmten Systemen überschrieben werden

1changelog:
2  sort: asc
3  filters:
4    exclude:
5      - "^docs:"
6      - "^test:"
7

Es wird automatisch ein changelog angelegt und es kann hier definiert werden wie genau das geschieht.

Wenn unsere Konfiguration fertig ist sieht unsere Beispiel datei genau so aus:

 1version: 1
 2
 3before:
 4  hooks:
 5    - go mod tidy
 6
 7builds:
 8  - env:
 9      - CGO_ENABLED=0
10    goos:
11      - linux
12      - windows
13      - darwin
14    goarch:
15      - amd64
16      - arm64
17gitlab_urls:
18  use_package_registry: true
19  use_job_token: true
20
21archives:
22  - format: tar.gz
23    # this name template makes the OS and Arch compatible with the results of `uname`.
24    name_template: >-
25      {{ .ProjectName }}_
26      {{- title .Os }}_
27      {{- if eq .Arch "amd64" }}x86_64
28      {{- else if eq .Arch "386" }}i386
29      {{- else }}{{ .Arch }}{{ end }}
30      {{- if .Arm }}v{{ .Arm }}{{ end }}      
31    # use zip for windows archives
32    format_overrides:
33      - goos: windows
34        format: zip
35
36changelog:
37  sort: asc
38  filters:
39    exclude:
40      - "^docs:"
41      - "^test:"

.goreleaser.yaml

Damit wäre auch die Konfiguration von goreleaser abgeschlossen

Unser Go-Programm

Wir benutzen hier als Beispiel ein gannz kleines und einfaches Programm, da es nur dazu dient den Build-Prozess zu zeigen.

1package main
2
3import "fmt"
4
5func main() {
6	fmt.Println("Hello World")
7}
8

main.go

Die Pipeline Konfiguration

Unsere Pipeline halten wir auch kurz und konzentrieren uns lediglich auf das bauen und veröffentlichen des Programms. Wir definieren uns also lediglich eine Stufe in der Pipeline

1stages:
2  - release

Und hier verwenden wir das docker-image von goreleaser (wenn kein docker vorhanden ist, muss die CLI aufgerufen werden) und definieren den entrypoint als leer.

1release:
2  stage: release
3  image:
4    name: goreleaser/goreleaser
5    entrypoint: [""]

Wir wollen das die Pipeline lediglich läuft, wenn wir auch was zu releasen haben. Das ganze können wir gut durch Tags managen. Ein Git Tag ist eine Möglichkeit einem bestimmten Stand des Codes einem Namen zu geben, der normalerweise wie eine Versionsnummer gehandhabt wird. Damit würde unsere Pipeline immer laufen, wenn wir vorher folgendes gemacht haben als Beispiel

1git tag v1.0.0
2git push origin v1.0.0

macht einen neuen tag und schickt diesen tag an gitlab

Als Variablen nehmen wir den gitlab job token, der von goreleaser ja benutzt wird zur authentifizierung. Zum Schluss müssen wir nur noch beim script unser goreleaser CLI Tool anweisen, dass es was releasen soll

1  only:
2    - tags
3  variables:
4    # Disable shallow cloning so that goreleaser can diff between tags to
5    # generate a changelog.
6    GIT_DEPTH: 0
7    GITLAB_TOKEN: $CI_JOB_TOKEN
8  script:
9    - goreleaser release --clean

Damit sieht die komplette .gitlab-ci.yml Datei wie folgt aus.

 1stages:
 2  - release
 3
 4release:
 5  stage: release
 6  image:
 7    name: goreleaser/goreleaser
 8    entrypoint: [""]
 9  only:
10    - tags
11  variables:
12    # Disable shallow cloning so that goreleaser can diff between tags to
13    # generate a changelog.
14    GIT_DEPTH: 0
15    GITLAB_TOKEN: $CI_JOB_TOKEN
16  script:
17    - goreleaser release --clean

die .gitlab-ci.yml Datei

Die Pipeline

Die Pipeline läuft nun immer wenn wir ein Tag pushen. Das ganze kann sich angeguckt werden unter der Gitlab Instanz > Build > Pipelines und die Ausgabe der Releases sollte nun unter Deploy > releases zu finden sein. Hier wird immer die Versionsnummer (unser Tag), alle Dateien die wir gebaut haben und zusätzlich auch unser kleines Changelog zu sehen sein mit den Commit Nachrichten die in dem Tag bzw. Release dazu gekommen sind.