How Docker works (namespaces, cgroups, layered images), containers vs VMs, passing env vars and secrets, COPY vs ADD, ENTRYPOINT vs CMD, volumes (named vs anonymous), docker-compose and container networking, shrinking images, scanning images for vulnerabilities; Kubernetes Pods vs Deployments vs Services, ConfigMaps and Secrets, readiness vs liveness (and startup) probes, autoscaling on CPU/memory, Helm, StatefulSet vs Deployment, Ingress, and secret rotation.
Published September 25, 2026
Show that you understand what containers are (Linux primitives, not tiny VMs), and how Kubernetes objects map to operational concerns: rollout, discovery, configuration, health and scaling. Tie everything back to running a JVM service well in a container.
Short answer: A container is a normal Linux process isolated by kernel features:
The image is a stack of read-only layers (a union filesystem, overlayfs), each produced by a Dockerfile instruction. A container adds a thin writable layer on top. The Docker Engine (dockerd → containerd → runc, following the OCI runtime specification) pulls images from registries, and creates and manages containers, networks and volumes. On macOS and Windows, Docker Desktop runs a Linux VM, and the containers run inside it.
Learn it in depth → Docker Fundamentals
Short answer:
| Container | Virtual machine | |
|---|---|---|
| Isolation | Process-level (namespaces, cgroups), sharing the host kernel | Hardware-level, through a hypervisor, with its own kernel |
| Size | MBs (app + dependencies) | GBs (a full OS) |
| Startup | Milliseconds to seconds | Tens of seconds to minutes |
| Density | Many per host | Fewer |
| Security boundary | Weaker (a kernel exploit affects every container) | Stronger |
| OS | Must match the host kernel (Linux containers on Linux) | Any guest OS |
Hybrids (Firecracker microVMs, Kata Containers, gVisor) give container-like speed with stronger isolation. They're used for multi-tenant and serverless workloads.
Short answer:
docker run -e SPRING_PROFILES_ACTIVE=prod, --env-file prod.env, the Compose environment:/env_file:, and Kubernetes env/envFrom (ConfigMaps). Never bake environment-specific values into the image.ENV in the Dockerfile, or build args: they're persisted in the image layers and history;/run/secrets/… as files), Kubernetes Secrets mounted as files (preferred over environment variables), or injected from Vault or cloud secret managers (the CSI driver, External Secrets Operator, sidecars);--mount=type=secret (for private repository tokens during the build, never stored in the layers).spring.config.import=configtree:/run/secrets/, or through environment variable binding.COPY and ADD in a Dockerfile?Short answer:
COPY copies files and directories from the build context into the image. It's simple and predictable, so prefer it.ADD does the same, plus it auto-extracts local tar archives, and can fetch remote URLs. That's "magic" behaviour, which surprises readers, and remote fetches aren't cached well or verified (use curl/wget with checksums instead, or ADD --checksum= in newer BuildKit).Use ADD only when you specifically need tar extraction. Use COPY --chown=app:app, and COPY --from=build in multi-stage builds.
ENTRYPOINT and CMD?Short answer:
ENTRYPOINT: the executable that always runs (the container's "command"), for example ["java", "-jar", "/app/app.jar"].CMD: default arguments for the entrypoint (or the default command if there's no entrypoint). It's easily overridden by docker run image <args>.ENTRYPOINT ["java","-jar","/app/app.jar"] plus CMD ["--spring.profiles.active=default"] means the arguments can be swapped at run time./bin/sh -c, so SIGTERM doesn't reach the JVM, and graceful shutdown breaks. With shell scripts as the entrypoint, use exec java …, so the JVM becomes PID 1 (or use --init/tini for signal forwarding and zombie reaping).Short answer: Volumes store data outside the container's writable layer, so it survives container removal, and performs better than the overlay filesystem:
-v pgdata:/var/lib/postgresql/data): managed by Docker, referenced by name, persist until explicitly removed, and are reusable across containers. Use them for databases in development and Compose.-v /data, or a VOLUME in a Dockerfile): get a random name, are easy to lose track of, and are removed with docker rm -v.-v ./src:/app/src): map host paths, for development hot-reload and configuration files. They depend on the host layout.In Kubernetes, the equivalents are PersistentVolumes/PersistentVolumeClaims (with StorageClasses), emptyDir, and ConfigMap or Secret volumes.
Short answer: Docker Compose defines multi-container applications in compose.yaml (services, networks, volumes, environment, health checks, depends_on with conditions), and runs them with docker compose up. It's used for local development environments, integration and e2e testing, demos, and small single-host deployments. (Spring Boot 3.1+ can start the Compose services automatically, with spring-boot-docker-compose.)
Networking:
jdbc:postgresql://db:5432/shop).ports:) for the host-facing services.depends_on: condition: service_healthy, the application waits for the database's health check.services:
db:
image: postgres:16-alpine
environment: { POSTGRES_DB: shop, POSTGRES_PASSWORD: example }
volumes: [ "pgdata:/var/lib/postgresql/data" ]
healthcheck: { test: ["CMD-SHELL", "pg_isready -U postgres"], interval: 5s, retries: 10 }
app:
build: .
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/shop
SPRING_DATASOURCE_PASSWORD: example
depends_on: { db: { condition: service_healthy } }
ports: [ "8080:8080" ]
volumes: { pgdata: {} }
Learn it in depth → docker-compose for Local Development
Short answer:
jlink: only the JDK modules you use (jdeps --print-module-deps).RUN steps, cleaning the package caches in the same layer..dockerignore, to keep .git, target and IDE files out of the context.Measure it: docker history, dive.
Learn it in depth → Multi-Stage Builds
Short answer:
Short answer:
orders.shop.svc.cluster.local) that load-balances across the ready Pods selected by labels. Types:
Learn it in depth → Core Objects
Short answer:
envFrom) or mounted files. Mounted files update automatically when the ConfigMap changes (after a delay); environment variables need a pod restart.spring.config.import=configtree:/etc/secrets/, environment variable binding, or Spring Cloud Kubernetes (reload on change).Learn it in depth → Config & Secrets
Short answer:
management.endpoint.health.probes.enabled=true exposes /actuator/health/liveness and /readiness, backed by ApplicationAvailability (readiness goes to REFUSING_TRAFFIC during shutdown).initialDelaySeconds, periodSeconds, failureThreshold and timeoutSeconds. Keep the endpoints cheap.Learn it in depth → Probes & Autoscaling
Short answer:
minReplicas for availability, and pre-scale for known peaks.Short answer: Helm is Kubernetes' package manager. A chart is a set of templated manifests (Go templates) plus values.yaml defaults, and metadata (Chart.yaml, dependencies). helm install/upgrade renders the templates with the environment-specific values, and applies them as a versioned release, with helm rollback support and hooks (pre-upgrade jobs for migrations). Why use it:
The alternatives: Kustomize (patch-based overlays, with no templating), and CDK8s. Often both are combined with GitOps (Argo CD renders Helm charts).
Short answer:
kafka-0, kafka-1) and stable DNS through a headless Service;volumeClaimTemplates) that follows the pod identity across rescheduling;Running databases in Kubernetes is possible with operators (CloudNativePG, Strimzi for Kafka), but many teams use managed cloud databases, and keep Kubernetes for stateless services.
Short answer: Ingress defines HTTP(S) routing from outside the cluster to Services: host and path rules, TLS termination (certificates through cert-manager), and features configured through annotations. An Ingress controller (NGINX, Traefik, HAProxy, a cloud load balancer controller like the AWS Load Balancer Controller) implements it, usually behind a cloud load balancer. It lets one external entry point serve many services, instead of a LoadBalancer Service each. The newer Gateway API (Gateway, HTTPRoute) is the more expressive, role-oriented successor, with traffic splitting, header matching, and cross-namespace delegation.
Learn it in depth → Services & Ingress
Short answer:
Q: Why do JVMs in containers get OOMKilled, and how do you prevent it?
A: The container memory limit covers heap plus non-heap memory (metaspace, threads, code cache, direct buffers, GC). Set -XX:MaxRAMPercentage around 70–75, cap metaspace and direct memory, set memory requests equal to limits, and use Native Memory Tracking to size them.
Q: What is a PodDisruptionBudget?
A: A policy limiting how many pods of an application can be voluntarily evicted at once (node drains, upgrades), for example minAvailable: 2, so maintenance doesn't take the service below capacity.
Q: How do you do graceful shutdown in Kubernetes for Spring Boot?
A: server.shutdown=graceful plus spring.lifecycle.timeout-per-shutdown-phase, a preStop hook with a short sleep (so endpoints deregister before SIGTERM processing), and a terminationGracePeriodSeconds longer than the drain time.
Q: What are resource requests vs limits? A: Requests reserve capacity for scheduling, and define the QoS. Limits cap usage: exceeding a memory limit gets the container killed, and CPU limits throttle it. For JVM services, set memory requests equal to limits, and be cautious with tight CPU limits (throttling hurts latency and GC).