Docker Interview Questions and Answers(2026) Part 01
All Interview questions related to Docker tool
🟢 Basic
Ans: Docker is a containerization platform that allows us to package an application along with all its dependencies, libraries, and configurations into a single unit called a container.
The main reason we use Docker is to ensure that the application runs consistently across different environments like development, testing, staging and production without any issues like “it works on my machine but not on yours”.
It also helps in faster deployment, better resource utilization compared to virtual machines, and makes scaling applications easier because we can quickly spin up multiple containers when needed.
For example: if I build a Docker container for a Node.js app, I can run the same container on my local system, a testing server, or in production, and it will behave exactly the same everywhere.
Ans: The main difference between a Docker image and a Docker container is that an image is a template, while a container is a running instance of that template.
A Docker image is a read-only package that includes the application code, dependencies, libraries, and environment needed to run the application. It doesn’t change and is used to create containers.
A Docker container, on the other hand, is the actual running environment created from the image. It is live, can be started or stopped, and you can run multiple containers from the same image.
In simple terms, I think of a Docker image as a blueprint and a Docker container as the actual running application created from that blueprint.
| Image | Container | |
|---|---|---|
| Definition | Read-only blueprint/template | Running instance of an image |
| State | Static (immutable) | Dynamic (can be started/stopped/deleted) |
| Storage | Stored on disk | Lives in memory + writable layer |
Ans: A Dockerfile is a script or configuration file that contains a set of instructions to build a Docker image.
In a Dockerfile, we define things like the base image, application code, dependencies, environment variables, and the commands needed to run the application.
So instead of manually setting up everything, we just write a Dockerfile, and Docker automatically builds the image from it. This makes the process consistent, repeatable, and easy to automate.
Example of Dockerfile:
FROM node:18-alpine # Base image
WORKDIR /app # Set working directory where all code build and run
COPY package*.json ./ # Copy application code files into image (/app) folder
RUN npm install # Execute command to install applicaiton dependancies during build
COPY . . # Copy remaining source code into /app folder
EXPOSE 3000 # Open 3000 Port in container to connect outside of docker container
ENV NODE_ENV=production # Set environment variable
CMD ["node", "server.js"] # Default command to run
Ans: To build a Docker image, we use the Dockerfile and run the docker build command. This command reads the instructions from the Dockerfile and creates an image.
Step 1: Build Dokcer image
# Build image (tag it with -t)
docker build -t my-app:1.0 .
Step 2: Run Docker Container
# Run a docker container
docker run -d --name my-app-container -p 8080:3000 my-app:1.0
# -d = detached mode (Container running in background)
# -p = host_port:container_port
# --name = assign a name to docker container
Ans: Docker Hub is the default public registry for Docker images. It hosts official images (like nginx, postgres, node) and allows users to publish their own images.
# Login to Docker Hub
docker login # Enter Username and Password
# Tag your image for Docker Hub
docker tag my-app:1.0 yourusername/my-app:1.0
# Push to Docker Hub
docker push yourusername/my-app:1.0
# Pull someone else's image
docker pull yourusername/my-app:1.0
Ans: There are following components:
Docker Engine: Also known as the Docker daemon, this is the core of Docker. It is a lightweight runtime and an efficient, scalable and secure containerization technology combined with a work flow for building and containerizing your applications.
Docker CLI: The Docker command-line interface (CLI) is used to interact with Docker. It allows you to build, run, and manage Docker containers and images.
Dockerfile: A Dockerfile is a text file that contains instructions for building a Docker image. It defines the environment in which the application will run, including the base image, dependencies, and runtime configuration.
Docker Images: Images are read-only templates that contain the necessary operating system, application, and runtime components. They serve as the basis for containers. You can create your own images or use pre-built images from the Docker Hub or other registries.
Docker Containers: Containers are instances of Docker images. They are lightweight and portable encapsulations of an environment in which to run applications. Containers are isolated from each other and from the host system. They can be started, stopped, and deleted, and their resources can be dynamically allocated.
Docker Compose: Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file to define services, networks, and volumes
Docker Swarm: Docker Swarm is a native clustering and orchestration tool for Docker. It allows you to create and manage a cluster of Docker nodes, and to deploy and manage services across the cluster.
Docker Hub: Docker Hub is the official registry for Docker images. It allows you to find, store, and share Docker images.
🟡 Intermediate
Ans: Docker Compose is a tool for defining and running multi-container applications using a single YAML file (docker-compose.yml). It’s ideal for local development and testing.
version: "3.9"
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pg_data:/var/lib/postgresql/data
volumes:
pg_data:
docker compose up -d # Start all services
docker compose down # Stop and remove containers
docker compose logs -f # Follow logs
docker compose ps # Status of services
Ans: Docker volumes and bind mounts are both used to persist data outside the container, but the main difference is in how they are managed.
Docker volumes are managed by Docker itself. They are stored in a specific location on the host and are easier to manage, more secure, and work well across different environments. They are generally the preferred way to persist data in production.
Bind mounts, on the other hand, directly map a file or directory from the host machine into the container. This gives more control, but it also depends on the host’s file structure, so it’s less portable and can cause issues if the path doesn’t exist.
In short, volumes are Docker-managed and more portable, while bind mounts are host-managed and more flexible but less portable
| Volume | Bind Mount | |
|---|---|---|
| Managed by | Docker | Host OS |
| Path | /var/lib/docker/volumes/ | Any path on host |
| Portability | High | Low |
| Use case | Production, databases | Local dev, live reload |
Tip: Prefer volumes in production; use bind mounts in development for live code reload.
Ans: Docker networking allows containers to communicate with each other, as well as with the host machine and external networks.
By default, Docker creates a network so that containers can talk to each other using IP addresses or container names. It basically handles isolation and communication between containers.
- Docker Network Types:
- Bridge
- Host
- None
- Overlay
| Driver | Description | Use Case |
|---|---|---|
bridge | This is the default network. Containers on the same bridge network can communicate with each other, and we can expose ports to access them from the host. | Most containers |
host | the container shares the host’s network directly, so there’s no isolation. It’s faster, but less secure because the container uses the host’s ports. | Performance-critical apps |
none | In this case, the container has no network access at all. It’s completely isolated. | Fully isolated tasks |
overlay | This is used in multi-host environments like Docker Swarm. It allows containers running on different machines to communicate with each other. | Docker Swarm / Kubernetes |
Ans: Multi-stage builds use multiple FROM statements in a single Dockerfile, allowing you to copy only the artifacts you need from earlier stages. This drastically reduces final image size.
# --- Stage 1: Build ---
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build # Produces /app/dist
# --- Stage 2: Production ---
FROM node:18-alpine AS production
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist # Only copy build output
EXPOSE 3000
CMD ["node", "dist/server.js"]
Result: The final image contains no dev dependencies, source code, or build tools — only what’s needed to run.
docker build --target production -t my-app:prod .
Ans: There are multiple ways to inject environment variables:
# 1. Inline with -e
docker run -e NODE_ENV=production -e PORT=3000 my-app
# 2. From a .env file
docker run --env-file .env my-app
# 3. In docker-compose.yml
# docker-compose.yml
services:
app:
image: my-app
environment:
NODE_ENV: production
PORT: 3000
env_file:
- .env.production
# 4. Baked into the image (not recommended for secrets)
ENV NODE_ENV=production
⚠️ Never bake secrets (passwords, API keys) into images. Use
.envfiles, Docker secrets, or a secrets manager like Vault.
Ans: Both copy files into the image, but ADD has extra functionality:
| Feature | COPY | ADD |
|---|---|---|
| syntax | COPY <source> <destination> | add |
| Purpose | Copies files and directories from the host system into the Docker image. | Copies files and directories from the host system as well as from remote urls into the Docker image |
| source | Supports local files and directories. | Supports local files and directories, URLs, and compressed files. |
| Destination | Must be a directory within the image. | Can be a directory or a file within the image. |
| Permissions | Preserves the source file permissions. | Applies default permissions of 600 (user: read/write) or 700 (directory) for files and 755 (user: read/write/execute) or 711 (directory) for directories. |
| Extracting compressed files | NA | Automatically extracts compressed files (e.g., *.tar, *.tar.gz, *.tgz, *.tar.bz2, *.tbz2, *.tar.xz, *.txz) during the copy process. |
| Caching | Does not cache remote URLs. | Caches remote URLs to avoid re-downloading the files if the URLs haven’t changed. |
| MD5 Hash | NA | Compares the MD5 hash of the local file with the hash in the cache to determine if the file has changed and needs to be downloaded again. |
| feature | Simple and straightforward. | Supports more features, such as extracting compressed files, caching remote URLs, and comparing MD5 hashes. |
| Recommendation | Use when copying local files and directories. | Use when copying local files and directories, as well as URLs or compressed files, and when you want to take advantage of caching and MD5 hash checking. |
# Preferred - explicit and predictable
COPY ./src /app/src
COPY package.json /app/
# Use ADD only when you need tar extraction
ADD app.tar.gz /app/
# Avoid ADD for URLs - use curl/wget in RUN instead
RUN curl -o /tmp/file.zip https://example.com/file.zip
Best practice: Always prefer COPY unless you specifically need ADD’s extra features.
Ans:
Note: You can use Container_id or Container_name to inspect and debug the logs
# Get a shell inside a running container
docker exec -it <container_id> /bin/sh # Alpine/minimal images
docker exec -it <container_id> /bin/bash # Debian/Ubuntu images
# View real-time logs
docker logs -f <container_id>
docker logs --tail 100 <container_id>
# Inspect container config, network, mounts
docker inspect <container_id>
# Resource usage (CPU, memory, I/O)
docker stats <container_id>
# Copy files out of a container
docker cp <container>:/app/logs/error.log ./error.log
# View processes inside container
docker top <container_id>
# View filesystem changes since container started
docker diff <container_id>
Ans:
# --- Containers ---
docker ps # List running containers
docker ps -a # List all containers (including stopped)
docker stop <name|id> # Gracefully stop a container
docker kill <name|id> # Force stop a container
docker rm <name|id> # Remove a stopped container
docker rm -f <name|id> # Force remove (even if running)
# --- Images ---
docker images # List all images
docker rmi <image_id> # Remove an image
docker image prune # Remove all unused images
# --- Cleanup everything ---
docker system prune -a # Remove all unused containers, images, networks
No, Unless you delete the container, any data stored in this docker container will not loose.Ans:
Step 01: Stop the Docker container
docker container stop <container_id or container_name>
Step 02: Remove the Docker container
docker rm <container_id or container_name>
Ans: Yes,containers can restart by themselves, but only if you configure them to do so. By default, a container does NOT auto-restart when it stops or crashes. You need a restart policy.
Docker provides built-in restart policies:
no→ (default) never restartalways→ always restart if stopped/crashedunless-stopped→ restart unless you manually stop iton-failure→ restart only if container exits with error
How to assign policy to Docker container:
docker run -d --restart=always nginx
Ans: No, you can’t remove a paused container directly. Docker won’t allow it because a paused container is still considered running (just frozen).
Correct way to remove a paused container:
Unpause → Stop → Remove
🔴 Advanced
Ans: Docker builds images in layers — each instruction in a Dockerfile creates one layer. Layers are cached and reused if the instruction and its context haven’t changed.
Cache invalidation rule: Once a layer changes, all subsequent layers are rebuilt.
# ❌ BAD - COPY . . early invalidates cache on every code change
FROM node:18-alpine
WORKDIR /app
COPY . . # Invalidated on ANY file change
RUN npm install # Reinstalls everything each time!
# ✅ GOOD - Copy dependency files first, leverage caching
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./ # Only changes when deps change
RUN npm install # Cached until package.json changes
COPY . . # App code changes don't bust npm cache
RUN npm run build
Other optimization tips:
- Combine
RUNcommands with&&to reduce layers - Use
.dockerignoreto excludenode_modules,.git, build artifacts - Order instructions from least-changing to most-changing
- Use
--mount=type=cache(BuildKit) for package manager caches
# BuildKit cache mount for faster builds
RUN --mount=type=cache,target=/root/.npm \
npm ci
Ans: Both are container orchestration platforms, but they differ in complexity and capability:
| Feature | Docker Swarm | Kubernetes |
|---|---|---|
| Setup complexity | Simple | Complex |
| Learning curve | Low | High |
| Scalability | Moderate | Enterprise-grade |
| Auto-healing | Basic | Advanced |
| Ecosystem | Docker-native | Massive (CNCF) |
| Use case | Small/medium teams | Large-scale production |
# Initialize a Swarm cluster
docker swarm init --advertise-addr <manager-ip>
# Deploy a stack (like docker-compose for Swarm)
docker stack deploy -c docker-compose.yml myapp
# Scale a service
docker service scale myapp_web=5
# List services
docker service ls
# Rolling update
docker service update --image my-app:2.0 myapp_web
When to choose what:
- Swarm → simpler apps, small teams, already using Docker Compose
- Kubernetes → complex microservices, multi-cloud, large engineering teams
Ans: Never store secrets as environment variables in images or plain docker-compose.yml. Use proper secrets management:
Option 1: Docker Secrets (Swarm mode)
# Create a secret
echo "super_secret_password" | docker secret create db_password -
# Use in a service
docker service create \
--name myapp \
--secret db_password \
my-app:latest
Inside the container, secrets are available at /run/secrets/db_password.
Option 2: Docker Compose secrets (for dev)
services:
app:
image: my-app
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt # Never commit this file!
Option 3: External secrets managers (production)
# HashiCorp Vault, AWS Secrets Manager, Azure Key Vault
# Inject at runtime via init containers or sidecar patterns
Best practices:
- Add secret files to
.gitignore - Rotate secrets regularly
- Use least-privilege access
- Audit secret access in production
Ans:
# 1. Use minimal base images
FROM alpine:3.19 # Small attack surface
FROM gcr.io/distroless/nodejs:18 # Distroless (no shell!)
# 2. Run as non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# 3. Drop Linux capabilities
# In docker-compose.yml:
# cap_drop: [ALL]
# cap_add: [NET_BIND_SERVICE]
# 4. Read-only filesystem
# docker run --read-only --tmpfs /tmp my-app
# 5. Avoid storing secrets in ENV or layers
# Use Docker secrets or external vaults
# 6. Pin base image versions
FROM node:18.19.0-alpine3.19 # Pinned, not :latest
# Scan image for vulnerabilities
docker scout cves my-app:latest
# or
trivy image my-app:latest
# Run with security options
docker run \
--read-only \
--no-new-privileges \
--cap-drop ALL \
--security-opt seccomp=default \
my-app:latest
Ans: Docker is not a VM — it uses Linux kernel features to create isolated processes:
Namespaces — provide isolation of system resources:
| Namespace | Isolates |
|---|---|
pid | Process IDs (container can’t see host processes) |
net | Network interfaces, IP tables, ports |
mnt | Filesystem mount points |
uts | Hostname and domain name |
ipc | Inter-process communication |
user | User and group IDs |
Control Groups (cgroups) — limit and account for resource usage:
# Limit container to 512MB RAM and 1 CPU
docker run \
--memory="512m" \
--memory-swap="512m" \
--cpus="1.0" \
my-app
# View cgroup info for a container
cat /sys/fs/cgroup/memory/docker/<container-id>/memory.limit_in_bytes
Union Filesystem (OverlayFS) — layers images efficiently:
- Each Dockerfile instruction creates a new read-only layer
- Running container gets a thin writable layer on top
- Layers are shared between containers using the same image → saves disk space
# See the layers of an image
docker history my-app:latest
# Inspect overlay filesystem
docker inspect my-app | grep -A5 GraphDriver
Ans: Zero-downtime deployments require a strategy to transition traffic from old containers to new ones without service interruption.
Strategy 1: Docker Swarm rolling update
docker service update \
--image my-app:2.0 \
--update-parallelism 1 \
--update-delay 10s \
--update-failure-action rollback \
myapp_web
Strategy 2: Blue-Green with Nginx + Compose
# docker-compose.blue-green.yml
services:
app-blue:
image: my-app:1.0
networks: [proxy]
app-green:
image: my-app:2.0
networks: [proxy]
nginx:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
ports:
- "80:80"
networks: [proxy]
# 1. Start green alongside blue
docker compose up -d app-green
# 2. Health check green
curl http://localhost/health
# 3. Switch Nginx upstream to green (update config + reload)
docker exec nginx nginx -s reload
# 4. Remove blue after confirming green is stable
docker compose stop app-blue
Strategy 3: Kubernetes (Deployment rollout)
kubectl set image deployment/my-app my-app=my-app:2.0
kubectl rollout status deployment/my-app
kubectl rollout undo deployment/my-app # Rollback if needed
Ans: Both define the command that runs when a container starts, but they behave differently:
| CMD | ENTRYPOINT | |
|---|---|---|
| Syntax | CMD [“executable”,“param1”,“param2”] | ENTRYPOINT [“executable”,“param1”,“param2”] |
| Purpose | Default arguments (can be overridden) | Fixed executable (cannot be overridden easily) |
| Override | Any CMD in the Dockerfile is overridden by docker run arguments. | ENTRYPOINT is not overridden by docker run arguments. |
| Default | If no CMD is specified in the Dockerfile, it uses the default one from the base image. | If no ENTRYPOINT is specified in the Dockerfile, it uses the default one from the base image. |
| Multiple commands | Only one CMD instruction can be used. | Multiple ENTRYPOINT instructions can be used. |
# CMD - easily overridden
CMD ["node", "server.js"]
# ENTRYPOINT - fixed executable
ENTRYPOINT ["node"]
CMD ["server.js"] # default arg, can be overridden
# Run: docker run my-app debug.js
# → executes: node debug.js
Best practice: Use ENTRYPOINT for the main executable and CMD for default arguments.
Add More Questions to This Guide
Know questions that should be here? Share them and help the community!
Open Google Form