mcpField
G
go-containers

go-containers

github.com/laurigatesCloud & DevOps5962 installsUpdated 1d ago
Repository

About go-containers

go-containers is a container optimization skill for Go developers. It covers static builds, minimal base images, and Go build flags for writing or auditing Dockerfiles.

Key features

  1. 01Configure static Go binary builds
  2. 02Choose scratch, distroless, or Alpine
  3. 03Reduce binaries with linker flags
  4. 04Handle CA certificates and CGO dependencies
  5. 05Separate build and runtime with multi-stage builds

Use cases

  1. 01Reduce production image size for Go services
  2. 02Audit a Go application's Dockerfile
  3. 03Choose an image for applications using C libraries
  4. 04Check binary size and dynamic dependencies

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/laurigates/claude-plugins --skill go-containers

After installing, type/go-containersin Claude Code to confirm it loaded.

Details

From the project README

Go Container Optimization

Expert knowledge for building minimal, secure Go container images using static compilation, scratch/distroless base images, and Go-specific build optimizations.

When to Use This Skill

Use this skill when...Use container-development instead when...
Building or auditing a Dockerfile for a Go applicationWriting language-agnostic multi-stage build patterns
Choosing between scratch, distroless, and Alpine for a Go binaryHardening any container against non-root / least-privilege standards
Driving down a Go image from hundreds of MB to single-digit MBComposing services with Docker Compose
Resolving CGO / static-link issues specific to GoOptimizing a Node.js (nodejs-containers) or Python (python-containers) image

Core Expertise

Go's Unique Advantages:

  • Compiles to single static binary (no runtime dependencies)
  • Can run on scratch base (literally empty image)
  • No interpreter, VM, or system libraries needed at runtime
  • Enables smallest possible container images (2-5MB)

Key Capabilities:

  • Static binary compilation with CGO_ENABLED=0
  • Binary stripping with ldflags (-w, -s)
  • Scratch and distroless base images
  • CA certificate handling for HTTPS
  • CGO considerations when C libraries are required

The Optimization Journey: 846MB → 2.5MB

This demonstrates systematic optimization achieving 99.7% size reduction:

Step 1: The Problem - Full Debian Base (846MB)
# ❌ BAD: Includes full Go toolchain, Debian system, unnecessary tools
FROM golang:1.23
WORKDIR /app
COPY . .
RUN go build -o main .
EXPOSE 8080
CMD ["./main"]

Issues:

  • Full Debian base (~116MB)
  • Complete Go compiler and toolchain (~730MB)
  • System libraries, package managers, shells
  • None of this is needed at runtime

Image size: 846MB

Step 2: Switch to Alpine (312MB)
# ✅ BETTER: Alpine reduces OS overhead
FROM golang:1.23-alpine
WORKDIR /app
COPY . .
RUN go build -o main .
EXPOSE 8080
CMD ["./main"]

Improvements:

  • Alpine Linux (~5MB base vs ~116MB Debian)
  • Still includes full Go toolchain (unnecessary at runtime)

Image size: 312MB (63% reduction)

Step 3: Multi-Stage Build (15MB)
# ✅ GOOD: Separate build from runtime
# Build stage
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go build -o main .

# Runtime stage
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

Improvements:

  • Build artifacts excluded from final image
  • Only Alpine + binary in final image
  • Faster deployments and pulls

Image size: 15MB (95% reduction from 312MB)

Step 4: Strip Binary & Optimize Build Flags (8MB)
# ✅ BETTER: Optimized build flags
# Build stage
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# Optimized build with stripping
RUN CGO_ENABLED=0 GOOS=linux go build \
    -a \
    -installsuffix cgo \
    -ldflags="-w -s" \
    -trimpath \
    -o main .

# Runtime stage with CA certificates
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

Build Flag Explanations:

FlagPurposeImpact
CGO_ENABLED=0Disable CGO, create static binaryRemoves dynamic library dependencies
-aForce rebuild of all packagesEnsures clean build
-installsuffix cgoSeparate output directoryPrevents cache conflicts
-ldflags="-w -s"Strip debug info and symbol tableReduces binary size significantly
-wOmit DWARF debug information~30% size reduction
-sOmit symbol table and debug infoAdditional ~10% reduction
-trimpathRemove file system pathsSecurity: no local path leakage

Additions:

  • CA certificates for HTTPS requests
  • Fully static binary (no dynamic dependencies)

Image size: 8MB (47% reduction from 15MB)

Step 5: Scratch or Distroless (2.5MB)

Option A: Scratch (Absolute Minimum)

# Build stage
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# Optimized static build
RUN CGO_ENABLED=0 GOOS=linux go build \
    -a \
    -installsuffix cgo \
    -ldflags="-w -s" \
    -trimpath \
    -o main .

# Runtime stage - scratch (empty image)
FROM scratch

# Copy CA certificates from builder
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Copy binary
COPY --from=builder /app/main /main

EXPOSE 8080
CMD ["/main"]

Image size: 2.5MB (68% reduction from 8MB)

Option B: Distroless (Slightly Larger, Easier Debugging)

# Build stage (same as above)
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \
    -a \
    -ldflags="-w -s" \
    -trimpath \
    -o main .

# Runtime stage - distroless
FROM gcr.io/distroless/static-debian12

COPY --from=builder /app/main /main
EXPOSE 8080
CMD ["/main"]

Distroless advantages:

  • Includes CA certificates automatically
  • Minimal OS files (passwd, nsswitch.conf)
  • No shell (security benefit)
  • Slightly larger (~2-3MB more) but includes useful metadata

Image size: ~4-5MB

Performance Impact

MetricDebian (846MB)Alpine (15MB)Scratch (2.5MB)Improvement
Image Size846MB15MB2.5MB99.7% reduction
Pull Time52s4s1s98% faster
Build Time3m 20s2m 15s1m 45s47% faster
Startup Time2.1s1.2s0.8s62% faster
Memory Usage480MB180MB128MB73% reduction
Storage Cost$0.48/mo$0.01/mo$0.001/mo99.8% reduction

Security Impact

Image TypeVulnerabilitiesAttack Surface
Debian-based63 CVEsFull OS, shell, package manager, utilities
Alpine-based12 CVEsMinimal OS, shell, package manager
Scratch0 CVEsBinary only, no OS
Distroless0-2 CVEsBinary + minimal runtime, no shell

Security benefits of scratch/distroless:

  • No shell → no shell injection attacks
  • No package manager → no supply chain attacks
  • No OS utilities → minimal attack surface
  • No unnecessary libraries → fewer vulnerabilities

When to Use Each Approach

Use CaseRecommended BaseReason
Production servicesScratch or DistrolessMinimal size, maximum security
Services with C dependenciesAlpine (with CGO)Requires system libraries
Development/debuggingAlpineNeed shell access for troubleshooting
Legacy appsDebian slimCompatibility requirements

Go-Specific .dockerignore

# Version control
.git
.gitignore
.gitattributes

# Go artifacts
vendor/
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
go.work
go.work.sum

# Development files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Documentation
README.md
*.md
docs/
LICENSE

# CI/CD
.github/
.gitlab-ci.yml
.travis.yml
Jenkinsfile

# Environment files
.env
.env.*
*.env

# Build artifacts
dist/
build/
bin/
tmp/
temp/

# Logs
*.log
logs/

# Test files (if not needed in image)
*_test.go
testdata/

# Docker files
Dockerfile*
docker-compose*.yml
.dockerignore

Binary Size Analysis

# Build with different optimization levels
go build -o main-default .
go build -ldflags="-w" -o main-w .
go build -ldflags="-s" -o main-s .
go build -ldflags="-w -s" -o main-ws .

# Compare sizes
ls -lh main-*

# Typical results for a medium Go app:
# main-default: 12.5MB (with debug info + symbols)
# main-w:        8.7MB (no debug info)
# main-s:       10.2MB (no symbol table)
# main-ws:       7.8MB (both stripped)

# Further analyze binary
go tool nm main-default | wc -l  # Count symbols
file main-ws                      # Verify static linking
ldd main-ws                       # Should show "not a dynamic executable"

Advanced: CGO Considerations

When your Go application uses CGO (C libraries, database drivers like SQLite, etc.), you cannot use scratch base images.

# When CGO is required (database drivers, C libraries)
FROM golang:1.23-alpine AS builder

# Install C dependencies
RUN apk add --no-cache gcc musl-dev

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .

# Build with CGO enabled
RUN CGO_ENABLED=1 GOOS=linux go build \
    -ldflags="-w -s -linkmode external -extldflags '-static'" \
    -o main .

# Runtime needs musl
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/main .
CMD ["./main"]

Note: With CGO, Alpine is the minimal option (~7-10MB final image).

Common Go Database Drivers

DriverCGO RequiredMinimum Base
github.com/lib/pq (PostgreSQL)NoScratch
github.com/go-sql-driver/mysqlNoScratch
github.com/mattn/go-sqlite3YesAlpine
modernc.org/sqlite (pure Go)NoScratch

Agentic Optimizations

Go-specific container commands for fast development:

ContextCommandPurpose
Quick buildgo build -ldflags="-w -s" -o app .Build stripped binary
Check sizels -lh appVerify binary size
Test staticldd appVerify no dynamic deps
Container buildDOCKER_BUILDKIT=1 docker build -t app .Fast build with cache
Size checkdocker images app --format "{{.Size}}"Check final image size
Layer analysisdocker history app:latest --humanSee layer sizes

Best Practices

Always:

  • Use CGO_ENABLED=0 unless you need C libraries
  • Strip binaries with -ldflags="-w -s"
  • Use -trimpath to remove filesystem paths
  • Prefer scratch or distroless for production
  • Version pin Go and base images (never use latest)

Never:

  • Ship the Go compiler in production images
  • Use full Debian/Ubuntu bases for Go apps
  • Include debug symbols in production binaries
  • Run as root user (even in scratch, use USER 65534)

Related Skills

  • container-development - General container patterns, multi-stage builds, security
  • nodejs-containers - Node.js-specific container optimizations
  • python-containers - Python-specific container optimizations

Comments

Markdown supported