Go dan Docker: Perfect Match
Salah satu keunggulan Go untuk production adalah binary-nya yang standalone dan small. Tidak ada runtime dependency seperti JVM atau Node.js. Ini membuat Docker image-nya sangat kecil bisa under 10MB! Saya pernah buat Go app dengan Docker image hanya 7MB dibandingkan 200MB+ untuk app Node.js sejenis.
Dockerfile Multi-Stage Build
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server
# Stage 2: Production
FROM alpine:3.19
RUN apk --no-cache add ca-certificates tzdata
ENV TZ=Asia/Jakarta
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]
Optimization Tips
# Build flags untuk binary lebih kecil
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-w -s" -o server ./cmd/server
# -w: remove DWARF debugging info
# -s: remove symbol table
# Hasil: binary 30-40% lebih kecil!
Health Check untuk Production
type HealthStatus struct {
Status string `json:"status"`
Services map[string]string `json:"services"`
Timestamp time.Time `json:"timestamp"`
}
func HealthCheck(db *gorm.DB) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error {
status := HealthStatus{
Status: "healthy",
Services: make(map[string]string),
Timestamp: time.Now(),
}
sqlDB, _ := db.DB()
if err := sqlDB.Ping(); err != nil {
status.Services["database"] = "unhealthy"
status.Status = "degraded"
} else {
status.Services["database"] = "healthy"
}
statusCode := 200
if status.Status != "healthy" { statusCode = 503 }
return c.Status(statusCode).JSON(status)
}
}
Docker Compose untuk Development
version: "3.8"
services:
app:
build: .
ports:
- "8080:8080"
environment:
- DB_HOST=postgres
- DB_PORT=5432
- DB_USER=dev
- DB_NAME=myapp_dev
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
POSTGRES_DB: myapp_dev
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
pgdata:
Image Go yang di-containerize dengan benar itu sangat efisien. Ini salah satu alasan kenapa Go mendominasi cloud-native ecosystem. Docker + Go adalah kombinasi yang powerful untuk SaaS deployment.
Security Best Practices untuk Docker
Security di Docker sering dilupakan. Ini beberapa practices yang saya terapkan:
- Jangan pakai root user di container:
FROM alpine:3.19
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
- Scan image untuk vulnerabilities dengan trivy atau snyk
- Minimal permissions hanya mount volumes yang benar-benar diperlukan
- Read-only filesystem tambahkan --read-only flag di production
Docker Build Cache Optimization
Build cache yang baik bisa mengurangi build time dari 5 menit menjadi 30 detik. Kuncinya adalah layer ordering taruh layer yang jarang berubah di atas, yang sering berubah di bawah:
# Good ordering for cache
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./ # Changes rarely
RUN go mod download # Cached if go.mod unchanged
COPY . . # Changes often
RUN go build -o server .
# If only source code changed, go mod download is cached!
Optimasi cache ini terutama penting untuk CI/CD pipeline yang menjalankan build berkali-kali setiap hari.