Go for Infrastructure Engineers›01 · Why Go for platform work: toolchain, modules and layout

Lesson 01 of 9 · Part 1 — The language

Why Go for platform work: toolchain, modules and layout

Why so much infrastructure is written in Go, how to install it, and the handful of commands you use every day: modules, run, build, test, vet and fmt, plus a project layout that stays simple.

Beginner
Key wordsGoGolanggo installgo mod initgo rungo buildgo testgo vetgofmtmodulesproject layoutstatic binarycross-compile

Why Go shows up everywhere in infrastructure

Kubernetes, Docker, containerd, Terraform, Prometheus, Grafana's backend, etcd, Argo CD, Cilium, Helm: all Go. The reasons matter for the tools you write too:

Property What it means for a platform engineer
Single static binary Copy one file to a node, a container or an air-gapped site; no interpreter, no pip install
Fast start, low memory CLIs feel instant; controllers and agents stay small
Concurrency built in Talk to 500 clusters or nodes at once with goroutines
Strong standard library HTTP, JSON, TLS, crypto, templates, testing without dependencies
Easy cross-compilation Build Linux ARM64 binaries from a Mac with one environment variable
The Kubernetes ecosystem client-go, controller-runtime and Kubebuilder are Go-first

Bash is a pocket knife: always with you, great for small jobs. Python is a toolbox: lots of tools, but you need to carry the box (interpreter and packages). Go is a power tool you can hand to anyone: one solid piece that works the same everywhere.

When to keep Bash or Python: glue scripts of a few lines (Bash), data wrangling and notebooks (Python). Reach for Go when a tool is shared, long-lived, needs to be fast or concurrent, or must run where you can't install anything.

Install and check

Download from go.dev (or brew install go, or your distribution's package, which may be older). Then:

$ go version
go version go1.26.0 linux/amd64
$ go env GOPATH
/home/me/go

Your first module

$ mkdir kaudit && cd kaudit
$ go mod init github.com/me/kaudit
package main

import (
    "fmt"
    "os"
)

func main() {
    host, err := os.Hostname()
    if err != nil {
        fmt.Fprintln(os.Stderr, "error:", err)
        os.Exit(1)
    }
    fmt.Printf("hello from %s\n", host)
}
$ go run .
hello from laptop
$ go build -o bin/kaudit . && ./bin/kaudit

Every Go file starts with package; main with a main() function makes a program. Imports are package paths; unused imports and variables are compile errors, which keeps code tidy.

The tools you use every day

  • gofmt formats code (there is one style; your editor runs it on save).
  • go vet finds suspicious code (wrong printf verbs, copied locks).
  • go test runs tests (lesson 09).
  • go mod tidy keeps go.mod and go.sum in step with your imports. Commit both files.

A layout that stays simple

kaudit/
├── go.mod, go.sum
├── main.go               # or cmd/kaudit/main.go when there are several binaries
├── internal/audit/       # your packages; "internal" can't be imported by other modules
│   ├── audit.go
│   └── audit_test.go
└── Dockerfile

Start with one package; split when a file grows past a few hundred lines or a clear boundary appears. Don't copy large "standard layouts" for small tools.

Try it: one binary, three platforms

  1. Install Go and create the module above.
  2. Add a version variable and print it; build with -ldflags "-X main.version=0.1.0".
  3. Cross-compile for linux/amd64, linux/arm64 and darwin/arm64 with GOOS/GOARCH, and check each with file.
  4. Copy the Linux binary into an alpine container and run it (build with CGO_ENABLED=0 first).
  5. Run go vet and gofmt -l .; add an unused import and read the compile error.

Going deeper: dependencies

  • Prefer the standard library for HTTP, JSON, flags and logging; add dependencies when they save real work (cobra, client-go).
  • Use go list -m all to see the full dependency tree and govulncheck ./... to check it for known vulnerabilities.
  • Use workspaces (go work) only when developing several modules together.

Recap

  • Go suits infrastructure: static binaries, fast start, concurrency, a strong standard library, easy cross-compilation.
  • A module (go.mod) is your project; go run, build, test, vet, fmt, mod tidy are the daily commands.
  • Keep the layout small: main.go plus internal/ packages.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.