Menjalankan deployment microservice Go Fiber dengan metode build manual berisiko menghasilkan artefak yang tidak konsisten dan ukuran image yang membengkak. Penggunaan base image umum seperti Alpine atau Ubuntu sering menyisakan celah keamanan (CVE) akibat adanya package manager dan shell sistem yang tidak diperlukan oleh runtime Go.

Kombinasi GoReleaser dan container image Distroless menyelesaikan masalah tersebut. GoReleaser mengotomasi kompilasi cross-platform, stripping binary, penataan tag semver, dan pembuatan changelog. Container base Distroless memangkas seluruh dependensi OS di level container, menghasilkan image produksi yang aman dan berukuran di bawah 30 MB.

1. Persiapan Kompilasi Static Go Fiber

Go secara default dapat menggunakan pustaka C lokal mesin host (via cgo) untuk fungsionalitas tertentu seperti DNS resolving atau deteksi sertifikat OS. Di dalam container Distroless atau scratch, pustaka dynamic linker (seperti glibc) tidak tersedia. Ketiadaan pustaka ini akan menghasilkan error file not found saat binary dieksekusi.

Kompilasi wajib dimatikan integrasi C-nya menggunakan instruksi CGO_ENABLED=0 agar Go menghasilkan single static binary.

// main.go
package main

import (
	"github.com/gofiber/fiber/v2"
)

var version = "dev"

func main() {
	app := fiber.New()

	app.Get("/health", func(c *fiber.Ctx) error {
		return c.JSON(fiber.Map{
			"status":  "ok",
			"version": version,
		})
	})

	_ = app.Listen(":8080")
}

2. Desain Dockerfile Berbasis Distroless

Dalam pipeline GoReleaser, Dockerfile tidak melakukan proses go build (multi-stage build standar). GoReleaser mengompilasi binary terlebih dahulu di host runner, kemudian memasukkan binary yang sudah siap pakai ke konteks build Docker.

Gunakan image gcr.io/distroless/static-debian12:nonroot. Image ini memuat sertifikat CA dan file zona waktu minimal, tanpa shell (/bin/sh) atau package manager, serta dijalankan langsung dengan User ID non-root (65532).

# Dockerfile
FROM gcr.io/distroless/static-debian12:nonroot

WORKDIR /app
COPY fiber-app /app/fiber-app

USER 65532:65532
EXPOSE 8080

ENTRYPOINT ["/app/fiber-app"]

3. Konfigurasi .goreleaser.yaml Multi-Platform

Konfigurasi berikut menangani kompilasi matrix untuk arsitektur amd64 dan arm64, optimasi linker flags, pembuatan image terpisah per arsitektur, dan penggabungan manifest multi-arch.

version: 2

before:
  hooks:
    - go mod tidy

builds:
  - id: fiber-app
    main: ./main.go
    binary: fiber-app
    env:
      - CGO_ENABLED=0
    goos:
      - linux
    goarch:
      - amd64
      - arm64
    ldflags:
      - -s -w
      - -X main.version={{.Version}}

dockers:
  - image_templates:
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-amd64"
    use: docker
    build_flag_templates:
      - "--platform=linux/amd64"
    goos: linux
    goarch: amd64
    dockerfile: Dockerfile
    files:
      - fiber-app

  - image_templates:
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-arm64"
    use: docker
    build_flag_templates:
      - "--platform=linux/arm64"
    goos: linux
    goarch: arm64
    dockerfile: Dockerfile
    files:
      - fiber-app

docker_manifests:
  - name_template: "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}"
    image_templates:
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-amd64"
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-arm64"
  - name_template: "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:latest"
    image_templates:
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-amd64"
      - "ghcr.io/{{ .Env.GITHUB_REPOSITORY_OWNER }}/fiber-app:{{ .Version }}-arm64"

changelog:
  sort: asc
  filters:
    exclude:
      - '^docs:'
      - '^test:'
Catatan Optimasi: Flag -s menghapus tabel simbol debugging dan -w menghapus informasi DWARF. Kedua flag ini memotong ukuran binary Go Fiber secara signifikan tanpa mengurangi fungsionalitas runtime.

4. Otomasi CI Menggunakan GitHub Actions

Workflow GitHub Actions di bawah dipicu secara eksklusif oleh tag Git yang valid (Semantic Versioning, misal v1.0.0). Pipeline mengautentikasi runner ke GitHub Packages (GHCR) dan menjalankan eksekusi GoReleaser.

# .github/workflows/release.yml
name: Release Pipeline

on:
  push:
    tags:
      - 'v*.*.*'

permissions:
  contents: write
  packages: write

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Go
        uses: actions/setup-go@v5
        with:
          go-version-file: 'go.mod'
          cache: true

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v6
        with:
          distribution: goreleaser
          version: latest
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}

5. Verifikasi dan Pengujian Lokal

Jangan menguji pipeline langsung pada remote repository dengan membuat fake tag berulang kali. Validasi konfigurasi secara lokal menggunakan flag --snapshot untuk memverifikasi proses build tanpa melakukan tagging atau push ke registry remote:

# Install goreleaser secara lokal terlebih dahulu
goreleaser release --snapshot --clean --skip=publish

Periksa direktori ./dist yang dihasilkan. Pastikan artefak binary terkompilasi untuk arsitektur yang ditentukan. Untuk memastikan binary benar-benar static, gunakan perintah file pada sistem Linux atau macOS:

file dist/fiber-app_linux_amd64_v1/fiber-app
# Output harus mengandung: statically linked

Setelah tag dirilis via GitHub Actions, verifikasi multi-arch manifest pada registry container target:

docker buildx imagetools inspect ghcr.io/<owner>/fiber-app:latest

Output perintah di atas wajib menampilkan dua platform target (linux/amd64 dan linux/arm64), mengonfirmasi bahwa image dapat di-pull dan dijalankan secara portabel pada VM x86_64 konvensional maupun instance berbasis ARM (seperti AWS Graviton).