Go HTTP service deployed to a local Kubernetes cluster via kind, with full CI-style automation through a single Makefile.
All pipeline tools (golangci-lint, Trivy, kind, kubectl) run inside a Docker container — only Docker and make are required on the host.
| Method | Path | Response |
|---|---|---|
| GET | /health |
{"status":"ok"} (200) |
| GET | /api/time |
{"time":"<RFC3339>"} (200) |
| any | any + X-Debug: fail header |
{"error":"forced failure"} (500) |
- Docker Desktop — running
- make — GNU Make (included with Git Bash / WSL on Windows)
No other tools need to be installed. The Makefile automatically builds a CI toolchain image containing golangci-lint, Trivy, kind, and kubectl.
Windows: all commands must be run in a bash terminal (Git Bash, WSL, or MSYS2). PowerShell and cmd are not supported.
make all # ci-image → lint → test → build → scan → cluster-up → deploy
make smoke-test # verify endpoints on http://localhost:30080| Target | Description |
|---|---|
make all |
Full pipeline: ci-image → lint → test → build → scan → cluster-up → deploy |
make ci-image |
Build CI toolchain image (golangci-lint + trivy + kind + kubectl) |
make lint |
Run golangci-lint (inside CI container) |
make test |
Run unit tests (inside CI container) |
make build |
Build Docker image (multi-stage, distroless) |
make scan |
Scan image with Trivy (inside CI container) |
make cluster-up |
Create kind cluster (inside CI container) |
make deploy |
Load image into kind and apply via Kustomize (dev overlay) |
make smoke-test |
curl checks against localhost:30080 |
make run |
Run service locally (requires Go on host) |
make clean |
Delete kind cluster and Docker volumes |
The Dockerfile includes a ci stage that bundles all pipeline tools:
| Tool | Version |
|---|---|
| golangci-lint | v1.63.4 |
| trivy | v0.69.0 |
| kind | v0.27.0 |
| kubectl | v1.32.0 |
The image is built automatically as the first step of make all. All targets that need these tools run inside this container with the project source mounted.
cmd/server/main.go # Entry point
internal/handler/handler.go # HTTP handlers + tests
internal/middleware/logging.go # Request logging middleware + tests
k8s/
base/ # Kustomize base (shared manifests)
configmap.yaml # APP_PORT config
secret.yaml # APP_SECRET
deployment.yaml # 2 replicas, probes, resource limits, securityContext
service.yaml # NodePort 30080
networkpolicy.yaml # Ingress/Egress rules
kustomization.yaml # Kustomize resource list
overlays/
dev/ # Namespace: devops-test (used by make deploy)
staging/ # Namespace: devops-test-staging, 1 replica, lower limits
production/ # Namespace: devops-test-production, 3 replicas, higher limits
kind/cluster.yaml # kind cluster config
Dockerfile # 3-stage build: builder → ci toolchain → distroless final
Makefile # Full automation (all tools via Docker)
ARCHITECTURE.md # Design decisions, production readiness, risks, monitoring
- Multi-stage build: build toolchain excluded from final image
- Distroless base:
gcr.io/distroless/static-debian12:nonroot— no shell, no package manager - Non-root user:
USER 1000 - Minimal binary:
CGO_ENABLED=0,-ldflags="-s -w",-trimpath - Image scanning: Trivy blocks on HIGH/CRITICAL CVEs
- K8s hardening:
readOnlyRootFilesystem,capabilities.drop: [ALL],seccompProfile: RuntimeDefault - NetworkPolicy: ingress limited to port 8080, egress limited to DNS
- Namespace isolation: dedicated namespace per environment via Kustomize overlays
| Overlay | Namespace | Replicas | CPU | Memory |
|---|---|---|---|---|
dev |
devops-test |
2 | 100m | 128Mi |
staging |
devops-test-staging |
1 | 50m | 64Mi |
production |
devops-test-production |
3 | 200m | 256Mi |
# Deploy to a specific environment:
kubectl apply -k k8s/overlays/dev # default for make deploy
kubectl apply -k k8s/overlays/staging
kubectl apply -k k8s/overlays/productionSee ARCHITECTURE.md for:
- Stack rationale
- Production readiness roadmap
- Risk analysis
- Monitoring strategy (4 Golden Signals with PromQL)
- GitOps approach with ArgoCD