Giao diện
🚀 Deployment
"If it's not deployed, it doesn't exist."
Go's single binary deployment là một trong những điểm mạnh lớn nhất của ngôn ngữ.
Go's single binary deployment là một trong những điểm mạnh lớn nhất của ngôn ngữ.
🐳 Docker Multi-Stage Builds
Optimal Dockerfile
dockerfile
# Stage 1: Build
FROM golang:1.22-alpine AS builder
# Install git (for go mod download) and ca-certificates (for HTTPS)
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /app
# Cache dependencies
COPY go.mod go.sum ./
RUN go mod download
# Copy source
COPY . .
# Build with optimizations
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-ldflags="-w -s -X main.version=${VERSION:-dev}" \
-o /app/server \
./cmd/server
# Stage 2: Runtime
FROM scratch
# Copy certificates and timezone data
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# Copy binary
COPY --from=builder /app/server /server
# Non-root user (numeric for scratch)
USER 65534:65534
EXPOSE 8080
ENTRYPOINT ["/server"]Build Flags Explained
bash
CGO_ENABLED=0 # Disable C bindings → static binary
GOOS=linux # Target OS
GOARCH=amd64 # Target architecture
-ldflags="-w -s" # Strip debug info → smaller binary
-w # Omit DWARF symbol table
-s # Omit symbol table
-X main.version=v1.0.0 # Inject version at build time⚔️ Tradeoff: Base Image Selection
| Image | Size | Security | Features | When to Use |
|---|---|---|---|---|
| scratch | 0 MB | ★★★★★ | None | Static Go binaries |
| distroless | ~2 MB | ★★★★★ | CA certs | Need certificates |
| alpine | ~5 MB | ★★★★☆ | Shell, tools | Debugging, CGO |
| debian-slim | ~80 MB | ★★★☆☆ | Full distro | Complex deps |
Distroless (Recommended for Production)
dockerfile
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]📦 Binary Optimization
Size Reduction Techniques
bash
# Before optimization: ~15MB
$ go build -o server ./cmd/server
$ ls -lh server
-rwxr-xr-x 1 user user 15M Jan 15 10:00 server
# With ldflags: ~10MB (-33%)
$ go build -ldflags="-w -s" -o server ./cmd/server
$ ls -lh server
-rwxr-xr-x 1 user user 10M Jan 15 10:00 server
# With UPX compression: ~4MB (-73%)
$ upx --best server
$ ls -lh server
-rwxr-xr-x 1 user user 4.0M Jan 15 10:00 server🔥 UPX Tradeoffs
| Pros | Cons |
|---|---|
| Smaller binary | Slower startup (decompression) |
| Faster downloads | Anti-virus false positives |
| Less storage | Harder to debug |
Recommendation: Use UPX cho CLI tools, không cho services.
Version Injection
go
// main.go
var (
version = "dev"
commit = "unknown"
buildTime = "unknown"
)
func main() {
if len(os.Args) > 1 && os.Args[1] == "--version" {
fmt.Printf("Version: %s\nCommit: %s\nBuilt: %s\n",
version, commit, buildTime)
os.Exit(0)
}
// ...
}bash
# Build with version info
go build -ldflags="-w -s \
-X main.version=$(git describe --tags) \
-X main.commit=$(git rev-parse --short HEAD) \
-X main.buildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o server ./cmd/server☸️ Kubernetes Deployment
Deployment Manifest
yaml
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
labels:
app: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 65534
fsGroup: 65534
containers:
- name: user-service
image: myregistry/user-service:v1.0.0
ports:
- containerPort: 8080
name: http
# Resource limits
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
# Health probes
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# Environment
env:
- name: PORT
value: "8080"
- name: LOG_LEVEL
value: "info"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-credentials
key: host
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
# Graceful shutdown
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]
terminationGracePeriodSeconds: 60Service & Ingress
yaml
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- port: 80
targetPort: http
protocol: TCP
---
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: user-service
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /api/users
pathType: Prefix
backend:
service:
name: user-service
port:
number: 80⚔️ Tradeoff: Helm vs Kustomize
| Tool | Approach | Pros | Cons | When to Use |
|---|---|---|---|---|
| Helm | Templating | Rich ecosystem, charts | Complex templates | Standard apps |
| Kustomize | Overlays | Native K8s, simpler | Less flexible | Custom apps |
Kustomize Example
yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
- ../../base
patchesStrategicMerge:
- deployment-patch.yaml
images:
- name: myregistry/user-service
newTag: v1.0.0🌍 12-Factor App Configuration
Environment-Based Config
go
// internal/config/config.go
package config
import (
"os"
"strconv"
"time"
)
type Config struct {
Port int
DatabaseURL string
RedisURL string
LogLevel string
ShutdownTimeout time.Duration
}
func Load() *Config {
return &Config{
Port: getEnvInt("PORT", 8080),
DatabaseURL: mustGetEnv("DATABASE_URL"),
RedisURL: getEnv("REDIS_URL", "localhost:6379"),
LogLevel: getEnv("LOG_LEVEL", "info"),
ShutdownTimeout: getEnvDuration("SHUTDOWN_TIMEOUT", 30*time.Second),
}
}
func getEnv(key, defaultVal string) string {
if val := os.Getenv(key); val != "" {
return val
}
return defaultVal
}
func mustGetEnv(key string) string {
if val := os.Getenv(key); val != "" {
return val
}
panic(fmt.Sprintf("required env var %s not set", key))
}
func getEnvInt(key string, defaultVal int) int {
if val := os.Getenv(key); val != "" {
if i, err := strconv.Atoi(val); err == nil {
return i
}
}
return defaultVal
}
func getEnvDuration(key string, defaultVal time.Duration) time.Duration {
if val := os.Getenv(key); val != "" {
if d, err := time.ParseDuration(val); err == nil {
return d
}
}
return defaultVal
}🔄 CI/CD Pipeline (GitHub Actions)
yaml
# .github/workflows/deploy.yaml
name: Build and Deploy
on:
push:
branches: [main]
tags: ['v*']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Run tests
run: go test -race -coverprofile=coverage.out ./...
- name: Upload coverage
uses: codecov/codecov-action@v3
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,prefix=
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
VERSION=${{ github.ref_name }}
deploy:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes
uses: azure/k8s-deploy@v4
with:
manifests: |
k8s/deployment.yaml
k8s/service.yaml
images: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}💻 Engineering Example: Production Makefile
makefile
# Makefile
.PHONY: build test docker deploy
# Variables
VERSION ?= $(shell git describe --tags --always --dirty)
COMMIT ?= $(shell git rev-parse --short HEAD)
BUILD_TIME ?= $(shell date -u +%Y-%m-%dT%H:%M:%SZ)
LDFLAGS := -ldflags="-w -s \
-X main.version=$(VERSION) \
-X main.commit=$(COMMIT) \
-X main.buildTime=$(BUILD_TIME)"
# Build
build:
CGO_ENABLED=0 go build $(LDFLAGS) -o bin/server ./cmd/server
build-linux:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o bin/server-linux ./cmd/server
# Test
test:
go test -race -cover ./...
test-integration:
go test -race -tags=integration ./...
# Docker
docker-build:
docker build -t myapp:$(VERSION) --build-arg VERSION=$(VERSION) .
docker-push:
docker tag myapp:$(VERSION) myregistry/myapp:$(VERSION)
docker push myregistry/myapp:$(VERSION)
# Deploy
deploy-staging:
kubectl apply -k overlays/staging
deploy-production:
kubectl apply -k overlays/production
# Local
run:
go run ./cmd/server
dev:
air # Hot reload with air✅ Ship-to-Prod Checklist
Docker
- [ ] Multi-stage build để minimize size
- [ ] scratch/distroless base image
- [ ] Non-root user trong container
- [ ] Health check trong Dockerfile
- [ ] Version injected tại build time
Kubernetes
- [ ] Resource limits configured
- [ ] Liveness/readiness probes configured
- [ ] Secrets từ K8s Secrets hoặc Vault
- [ ] Graceful shutdown với preStop hook
- [ ] PodDisruptionBudget cho high availability
CI/CD
- [ ] Tests pass trước khi build
- [ ] Automated image tagging từ git tags
- [ ] Vulnerability scanning trên images
- [ ] Staged rollouts (staging → production)
- [ ] Rollback procedure documented
12-Factor
- [ ] Config từ environment (không hardcode)
- [ ] Stateless processes
- [ ] Logs to stdout
- [ ] Dev/prod parity
📊 Summary
| Component | Recommendation |
|---|---|
| Base Image | scratch hoặc distroless |
| Build Flags | -ldflags="-w -s" |
| K8s Manifests | Kustomize với overlays |
| Config | Environment variables |
| CI/CD | GitHub Actions + ArgoCD |
🎉 Production Section Complete!
Bạn đã master Go Production Patterns:
- ✅ Project Structure
- ✅ Testing & Benchmarks
- ✅ HTTP Services
- ✅ Database Patterns
- ✅ Observability
- ✅ Deployment
Tiếp theo: Advanced Topics - Generics, Reflection, CGO, và Performance.