Skip to content

Containerization & deployment

Why it matters

Every language path's Month 5 (production) is followed by Month 6 (capstone). Between "write the code" and "users use the code" is deployment - the part most curricula skip. This page bridges the language paths and the Container/Kubernetes paths.


The deployment stack, layer by layer

A modern deployment is roughly:

Source code → Build artifact → Container image → Image registry →
  Cluster manifest → Cluster (Kubernetes / Nomad / docker-compose) →
  Runtime → Users

Each layer is a tool category covered somewhere on this site.


The lens, per path

Go - single static binary, then deploy

Month 5 - Production & Distributed. Go's killer deployment feature: go build produces a single static binary. No JVM, no Python runtime, no NPM modules. Copy the binary to a server (or into a container) and it runs.

Result: the smallest deployment story of any path. A 10MB binary in a 10MB distroless image. Cold start in milliseconds.

What's unique: Go's design directly optimizes for "ship a CLI or service binary."

Month 5 - Production. Three deployment shapes:

  • Fat JAR + JVM image - the traditional approach. ~200MB image with the JVM bundled. Slow cold start (1-3s).
  • JLink runtime image - bundle only the JDK modules you need. Smaller (~80MB), still JVM.
  • GraalVM native-image - AOT-compile to a native binary like Go. ~30MB, milliseconds startup. Trades: reflection requires hints; build time is slow.

What's unique: the breadth of options. Same Java code, three deployment shapes with different trade-offs.

Rust - native binary, smallest images

Month 5 - Production Architecture. cargo build --release produces a native binary. With RUSTFLAGS="-C target-feature=+crt-static" it's static; copy to a scratch container; smallest possible image.

What's unique: Rust + scratch image gives the smallest deployable container of any path - single-digit megabytes is common. No runtime, no GC, no JVM, no Python.

Python - wheels + virtualenvs + Docker

Month 1 packaging week, Month 3. Build wheels for your platform; install into a virtualenv; bundle into a container. Multi-stage Docker builds for image size (build wheels in a stage with build tools; copy wheels-only into the final image).

What's unique: the "matrix of Python version × CUDA version × OS" complexity. A scientific Python image easily reaches 5GB. Tools like uv (modern Rust-implemented installer) and cibuildwheel (cross-platform wheel-building) ease this.

Containers - the lingua franca

Container Internals (senior) - full senior reference. Containers From Scratch (beginner) - the beginner path.

Every language above eventually deploys via containers because: - One image format works across clouds, on-prem, laptops. - Layered storage shares common bytes across services. - The container ecosystem (registries, scanners, runtime tools) is mature.

Kubernetes - orchestration

Kubernetes (senior) and Kubernetes From Scratch (beginner).

Beyond a single host, you need orchestration: scheduling pods across nodes, restarting failed ones, rolling updates, service discovery. Kubernetes is the de-facto standard. Alternatives (Nomad, ECS) exist for specific cases.


The CI/CD pattern

The repeatable workflow across all languages:

git push → CI builds → tests pass → image built → image pushed to registry →
  manifest update → cluster reconciles → deploy complete

Tools at each step:

Step Tools
CI GitHub Actions, GitLab CI, CircleCI, Jenkins
Tests language-specific (page 10 of each beginner path)
Image build docker buildx, BuildKit, ko (Go-specific), jib (Java-specific), Buildah
Registry Docker Hub, GHCR, ECR, GAR, ACR
Manifest update manual, or GitOps (Argo CD, Flux)
Cluster Kubernetes, Nomad, ECS, docker-compose for small

For first contributions, the GitHub Actions → GHCR → Kubernetes path is the most common.


GitOps: the modern pattern

Rather than "CI deploys to the cluster," GitOps says:

  1. The cluster's desired state lives in a git repo (YAML manifests, Helm values).
  2. A controller in the cluster (Argo CD, Flux) watches the repo.
  3. The controller reconciles: actual cluster state → match git.

Push to git → controller picks up → cluster converges. Auditable, reproducible, rollback = git revert.

The two big tools: - Argo CD - UI-driven, popular in enterprises. - Flux - CLI-driven, popular in startup-shape orgs.

Both wrap Helm or Kustomize. Beyond beginner; mentioned because every production K8s deployment in 2026 uses one.


Progressive delivery

Beyond "deploy this version":

  • Rolling update - replace pods one at a time. Kubernetes default. Safe for backward-compatible changes.
  • Blue-green - run two parallel deployments; switch traffic atomically. Fast rollback.
  • Canary - route a small % of traffic to the new version; verify; gradually shift. Catches problems before all users see them.
  • Feature flags - deploy code "off" (behind a flag); flip the flag separately from deploy. Decouples deploy risk from release risk.

Argo Rollouts and Flagger automate canary patterns on Kubernetes. Feature flags via LaunchDarkly, GrowthBook, Unleash.


Observability after deployment

Deployment isn't done until you can see your service running. The Observability cross-topic page covers logs, metrics, traces. Production deployments include:

  • Health endpoints (/healthz, /readyz) for the orchestrator to probe.
  • Metrics endpoint (/metrics Prometheus format) for scrape.
  • Structured logs to stdout (let the container runtime ship them).
  • Traces to an OTel collector.

Every senior reference path's Appendix A covers the per-language wiring.


The contrasts that teach

Aspect Go Java (post-Loom) Rust Python
Build artifact static binary JAR + JVM, JLink, or native static binary wheels + venv
Image base scratch / distroless distroless/java or *-slim scratch / distroless python:3-slim or distroless
Image size (typical) 5-30MB 80-250MB JVM, 30-50MB native 5-30MB 100-500MB
Cold start <1s 1-3s (JVM), <100ms (native) <1s 100-500ms
CI build complexity low moderate moderate (longer builds) moderate (matrix of deps)
K8s ecosystem fit excellent (kubectl, operators in Go) excellent (Spring Boot + Helm) growing (operator-rs) excellent (data + ML workloads)

The single most clarifying read: build a small service in two languages, deploy both to the same Kubernetes cluster. The Kubernetes parts are identical; the build/image differences teach the per-language ecosystem trade-offs.


What to read first

  • You ship Go services → Go Month 5 + Containers From Scratch. The simplest, most-direct stack.
  • You ship Java services → Java Month 5 + Containers + Kubernetes From Scratch. Pick blocking-on-virtual-threads + Spring Boot 3 + Buildpacks for the easiest path.
  • You write infrastructure (operators, controllers) → Kubernetes (senior) + Go from Scratch / Mastery. Most Kubernetes infrastructure code is Go.
  • You ship ML / data systems → AI Systems + Containers/K8s. The image-size problem matters more here than anywhere else.
  • You're operating someone else's deployed software → Kubernetes (senior) + Observability cross-topic + Performance methodology cross-topic.