Docker Fundamentals
Package app + runtime dependencies into portable containers for consistent deployment.
Definition
Docker is a container platform. You build an image (read-only package), run containers (isolated processes from that image), and publish images to registries for reproducible deployments.
Why It Matters
- Eliminates environment drift across dev, test, and production.
- Speeds onboarding with one command to run full stack.
- Enables predictable CI/CD using same artifact everywhere.
- Improves resource efficiency versus full VMs for many workloads.
When to Use
- Microservices and backend APIs needing repeatable deployments.
- Teams with multiple environments and dependency complexity.
- CI pipelines where reproducible build/runtime is required.
When NOT to Use
- Very small one-off scripts where container overhead gives little ROI.
- Workloads requiring direct host-level customization incompatible with container model.
Code Variations
# Build stage
FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn -q -DskipTests package
# Runtime stage
FROM eclipse-temurin:21-jre
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]docker-compose.yml for app + dbyamlservices:
app:
build: .
ports: ["8080:8080"]
depends_on: [db]
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/appdb
SPRING_DATASOURCE_USERNAME: app
SPRING_DATASOURCE_PASSWORD: app
db:
image: postgres:16
environment:
POSTGRES_DB: appdb
POSTGRES_USER: app
POSTGRES_PASSWORD: app
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata: {}docker build -t myapp:1.0 .
docker run --rm -p 8080:8080 myapp:1.0
docker ps
docker logs <container-id>
docker exec -it <container-id> sh
docker push my-registry/myapp:1.0- Use non-root user in container
- Pin base image tag/version
- Scan image for vulnerabilities
- Keep image small (multi-stage)
- Add health/readiness checks
- Externalize secrets (no secrets in image)Without Docker vs With Docker
| Aspect | Without Docker | With Docker |
|---|---|---|
| Environment setup | Manual install/version mismatch risk | Declarative via Dockerfile and Compose |
| Deployment artifact | Code + docs + scripts | Immutable image with runtime baked in |
| Consistency | “Works on my machine” common | High parity across environments |
| Isolation | Shared host dependencies | Process/filesystem/network isolation |
| Rollback | Manual rollback steps | Swap to previous image tag |
Common Confusions Cleared Up
Docker runs containers; large-scale scheduling, rolling deploys, and self-healing are usually handled by orchestration platforms (e.g., Kubernetes/ECS).
If your app has memory leaks or bad retries, containerization does not fix logic issues. It just makes runtime consistent.
Variations / Implementations
Core objects you must know
Dockerfile defines image build steps. Image is immutable package. Container is running instance. Registry stores images. Docker Compose runs multi-container apps.
Typical usage flow
Write Dockerfile -> build image -> run container locally -> push image to registry -> deploy using same tag in staging/prod.
Container vs VM
Containers share host kernel and isolate processes; VMs include full guest OS. Containers are usually lighter and faster to start.
Common Mistakes / Anti-Patterns
- Using
latesttags in production. - Putting secrets directly in Dockerfile or image layers.
- Running as root without need.
- Huge images from single-stage builds with build tools included.
- Treating containers as full VMs (SSH, manual patching inside running container).