Stage 3 · Build
Go Fundamentals for SREs
Project Layout & Modules
Go modules, internal packages, and CLI project structure that scales.
Go Modules
Go modules are the standard dependency management system. A module is a collection of packages with a go.mod file that defines the module path, Go version, and dependencies.
go mod init github.com/myorg/kube-guard
go get k8s.io/client-go@v0.29.0
go get github.com/prometheus/client_golang@v1.18.0
go mod tidygo mod init creates the module. go get adds dependencies. go mod tidy cleans up unused dependencies and adds missing ones. Always run tidy before committing.
Use your repository path as the module path: github.com/org/repo. This makes imports predictable and allows go get to resolve packages directly from version control.
Directory Structure
Go projects follow a conventional layout. There is no enforced structure, but the community has converged on patterns that work well for most projects.
kube-guard/
cmd/
kube-guard/
main.go
internal/
controller/
controller.go
controller_test.go
config/
config.go
pkg/
api/
types.go
api/
v1/
types.go
zz_generated.deepcopy.go
deploy/
manifests/
Makefile
Dockerfile
go.mod
go.sumcmd/ holds entrypoints, internal/ holds private packages, pkg/ holds public libraries, api/ holds API type definitions. This structure scales from small tools to large operators.
Internal Packages
The internal/ directory enforces package privacy. Any code inside internal/ can only be imported by code in the parent directory tree. This prevents accidental exposure of implementation details.
The cmd/ Pattern
For projects with multiple binaries, each binary gets its own directory under cmd/. Each main.go should be minimal — just enough to wire dependencies and call into internal packages.
Versioning and Tags
Use git tags for versioning. Semantic versioning (v1.2.3) works well. The go toolchain respects tags when resolving module versions, and your CI can use them to set binary versions.
git tag -a v1.2.0 -m "Release v1.2.0"
git push origin v1.2.0
# Embed version at build time
go build -ldflags "-X main.version=v1.2.0" ./cmd/serverUsing -ldflags with -X injects variables at build time. This is the standard way to embed version information without hardcoding it in source files.
Add generated files like zz_generated.deepcopy.go and vendor/ to .gitignore if you regenerate them. Generated code should be built in CI, not stored in version control.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.