Containers from the CLI: docker & kubectl
Build and run Go images with docker locally, then debug pods in Kubernetes with kubectl logs, exec, and port-forward.
Search across all documentation pages
Build and run Go images with docker locally, then debug pods in Kubernetes with kubectl logs, exec, and port-forward.
Go's static binaries fit minimal container images, but production issues still surface through container CLIs: a pod crash loop, an image that works on your laptop but not in CI, or a health check that never goes ready.
These commands are the fastest path from symptom to process inside the cluster.
Quick-reference recipe card - copy-paste ready.
# Dockerfile (multi-stage)
FROM golang:1.26 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/api ./cmd/api
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/api /api
USER nonroot:nonroot
ENTRYPOINT ["/api"]# Local
docker build -t api:dev .
docker run --rm -p 8080:8080 api:dev
docker logs -f <container_id>
# Kubernetes
kubectl get pods -l app=api
kubectl logs deploy/api --tail=200
kubectl exec -it deploy/api -- /api -version 2>/dev/null || kubectl exec -it deploy/api -- /bin/sh
kubectl port-forward deploy/api 6060:6060When to reach for this:
CrashLoopBackOff and you need logs and exit codes fast.#!/usr/bin/env bash
set -euo pipefail
# --- docker: build and smoke test ---
cat > Dockerfile <<'EOF'
FROM golang:1.26 AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /api ./cmd/api
FROM gcr.io/distroless/static-debian12
COPY --from=build /api /api
USER 65532:65532
ENTRYPOINT ["/api"]
EOF
docker build -t api:local .
CID=$(docker run -d -p 18080:8080 api:local)
sleep 2
curl -sf localhost:18080/healthz
docker logs "$CID" | tail -20
docker rm -f "$CID"
# --- kubectl: inspect deployment (names are examples) ---
kubectl get deploy,po -l app=api
kubectl rollout status deploy/api --timeout=120s
kubectl logs deploy/api --tail=100 --timestamps
kubectl describe pod -l app=api | rg -n "State:|Reason:|Exit Code:|Liveness|Readiness"What this demonstrates:
-p host:container) and optional env (-e) mirroring K8s env vars.-f follows, --previous shows the last crashed instance.| Task | docker | kubectl |
|---|---|---|
| Build image | docker build -t name:tag . | kubectl apply -f (after push) |
| Run / deploy | docker run -p ... | kubectl rollout restart deploy/name |
| Stream logs | docker logs -f id | kubectl logs -f deploy/name |
| Shell | docker exec -it id sh | kubectl exec -it po -- sh |
| Debug port | -p 6060:6060 | kubectl port-forward po 6060:6060 |
| Inspect exit | docker inspect --format='{{.State.ExitCode}}' | kubectl describe po Events |
# Cache modules in build stage
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /out/api ./cmd/apiPin the golang image tag to the same minor your go.mod declares; align with GOTOOLCHAIN policy in CI.
linux/arm64 while cluster is amd64. Fix: docker build --platform linux/amd64 or CI native builders.kubectl exec sh fails. Fix: debug toolkit image, ephemeral debug container, or scratch + copy binary to a debug pod.USER - Container runs as root despite Go best practice. Fix: non-root USER matching Kubernetes securityContext.runAsNonRoot.initialDelaySeconds.0.0.0.0.| Alternative | Use When | Don't Use When |
|---|---|---|
| docker CLI | Laptop and CI image build | Production fleet only on Kubernetes |
| podman | Rootless containers on RHEL/Fedora | Team standardized on Docker Desktop |
| kubectl debug | Ephemeral debug containers (K8s 1.23+) | Simple log-only triage |
| Helm / GitOps | Declarative deploys | You only need one-shot log grep |
| systemd on VM | No orchestrator | Organization mandates Kubernetes |
distroless/static minimizes attack surface for pure Go binaries.
alpine adds a shell and package manager when operators want apk add debugging tools.
kubectl describe pod Events and kubectl logs --previous for the last terminated container.
Pull by digest from your registry and run with the same env vars and entrypoint.
Validates image integrity outside the cluster.
kubectl port-forward plus curl locally, or kubectl cp if the pod wrote a file to a volume.
The build stage or accidental COPY . includes test data and .git.
Use .dockerignore and multi-stage builds; runtime should only contain the binary.
kubectl config current-context before destructive commands.
Namespace flags (-n prod) prevent cross-environment mistakes.
grpcurl via kubectl port-forward to the gRPC port, or run grpcurl in an ephemeral debug pod on the cluster network.
Compose models multi-service dev stacks.
kubectl remains required for cluster behavior: probes, ConfigMaps, and network policies.
Set container env vars in the Deployment manifest - same as shell exports on VMs.
The process may log to a file or crash before writing.
Check kubectl describe exit codes and run the image with docker run --rm -it locally.
krew plugins like ctx and ns speed context switching.
Core verbs cover most Go service debugging.
kubectl rollout restart deploy/api triggers a rolling update with the same image tag if only env changed via manifest apply.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026