Building & Pushing Images
Building Container Images
Building an image takes a Dockerfile and a build context (all files in the specified directory) and produces a tagged image that you can run or push.
Basic Build Commands
# Build from current directory (uses ./Dockerfile)
docker build -t my-app:v1 .
# Build with a specific Dockerfile
docker build -t my-app:v1 -f Dockerfile.prod .
# Build with build arguments
docker build -t my-app:v1 --build-arg VERSION=2.0 .
# Build with no cache (force rebuild all layers)
docker build -t my-app:v1 --no-cache .
Build Command Breakdown
| Flag | Purpose | Example |
|---|---|---|
-t |
Tag the image (name:version) | -t my-app:v1 |
-f |
Specify Dockerfile path | -f Dockerfile.prod |
--build-arg |
Pass build-time variables | --build-arg ENV=prod |
--no-cache |
Rebuild without layer cache | --no-cache |
--target |
Build up to a specific stage | --target builder |
. |
Build context directory | . (current dir) |
What Happens During a Build
docker build -t my-app:v1 .
│ │
│ └── Build context (files sent to Docker)
└── Tag for the resulting image
Step 1/6 : FROM python:3.12-slim ← Pull (or use cached) base
Step 2/6 : WORKDIR /app ← Set working directory
Step 3/6 : COPY requirements.txt . ← Copy file from context
Step 4/6 : RUN pip install ... ← Execute command (new layer)
Step 5/6 : COPY . . ← Copy remaining files
Step 6/6 : CMD ["python", "app.py"] ← Set default command
Successfully built 4a2b3c1d5e6f
Successfully tagged my-app:v1
Build Context and .dockerignore
The build context is everything in the directory you specify (.). Large contexts slow down builds. Use .dockerignore to exclude unnecessary files:
# .dockerignore
node_modules
.git
.env
*.md
Dockerfile
docker-compose.yml
__pycache__
.pytest_cache
Tip: Always check your build context size. If you see “Sending build context to Docker daemon 500MB”, you need a .dockerignore file.
Tagging Images
Tags identify specific versions of an image. Proper tagging is essential for reliable deployments.
Tagging Conventions
# Tag during build
docker build -t my-app:v1.0.0 .
# Add additional tags to an existing image
docker tag my-app:v1.0.0 my-app:latest
docker tag my-app:v1.0.0 registry.example.com/team/my-app:v1.0.0
# Tag with Git commit SHA (common in CI/CD)
docker tag my-app:v1.0.0 my-app:sha-$(git rev-parse --short HEAD)
Common Tagging Strategies
| Strategy | Example | Use Case |
|---|---|---|
| Semantic versioning | v1.2.3 |
Production releases |
| Git commit SHA | sha-abc123 |
CI/CD pipelines |
| Branch name | main, develop |
Development builds |
| Date-based | 2025-02-09 |
Nightly builds |
latest |
latest |
Most recent build (use cautiously) |
Warning: Avoid relying on latest in production. It’s mutable — different nodes might pull different versions. Always use specific tags.
Pushing Images to a Registry
After building, push your image to a container registry so Kubernetes can pull it.
Push Workflow
Build locally → Tag for registry → Login → Push
# 1. Build the image
docker build -t my-app:v1 .
# 2. Tag for the remote registry
docker tag my-app:v1 registry.example.com/team/my-app:v1
# 3. Login to the registry
docker login registry.example.com
# 4. Push to the registry
docker push registry.example.com/team/my-app:v1
Common Registry Providers
| Registry | Domain | Example |
|---|---|---|
| Docker Hub | docker.io |
docker.io/myuser/app:v1 |
| GitHub Container Registry | ghcr.io |
ghcr.io/org/app:v1 |
| Google Container Registry | gcr.io |
gcr.io/project/app:v1 |
| Amazon ECR | <id>.dkr.ecr.<region>.amazonaws.com |
123456.dkr.ecr.us-east-1.amazonaws.com/app:v1 |
| Azure Container Registry | <name>.azurecr.io |
myregistry.azurecr.io/app:v1 |
Pushing to Docker Hub
# Login
docker login
# Tag with your Docker Hub username
docker tag my-app:v1 myusername/my-app:v1
# Push
docker push myusername/my-app:v1
Pushing to GitHub Container Registry (GHCR)
# Login with personal access token
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Tag
docker tag my-app:v1 ghcr.io/myorg/my-app:v1
# Push
docker push ghcr.io/myorg/my-app:v1
Using Podman (Alternative to Docker)
Podman is a daemonless container engine that uses the same CLI syntax as Docker. Some CKAD environments or organizations use Podman instead of Docker.
# Build an image (same syntax)
podman build -t my-app:v1 .
# Run a container
podman run -d -p 8080:80 my-app:v1
# Push to a registry
podman push my-app:v1 registry.example.com/team/my-app:v1
# List images
podman images
Docker vs Podman Comparison
| Feature | Docker | Podman |
|---|---|---|
| Daemon | Requires dockerd |
Daemonless |
| Root required | By default (rootless mode available) | Rootless by default |
| CLI syntax | docker ... |
podman ... (compatible) |
| Compose | docker compose |
podman-compose |
| Kubernetes YAML | ❌ | podman generate kube |
CKAD relevance: The exam may use either Docker or Podman. The CLI commands are interchangeable — podman build, podman push, etc. work the same way.
Listing and Inspecting Images
# List all local images
docker images
# Inspect image details (layers, config, size)
docker inspect my-app:v1
# View image history (layers)
docker history my-app:v1
# Remove an image
docker rmi my-app:v1
# Remove unused images
docker image prune
Summary
| Task | Command |
|---|---|
| Build image | docker build -t name:tag . |
| Tag image | docker tag source:tag target:tag |
| Login to registry | docker login registry.example.com |
| Push image | docker push registry/name:tag |
| List images | docker images |
| Inspect image | docker inspect name:tag |