AlgoInsight

Q&A

How to create an image using a Dockerfile

By AlgoInsight Team2026-06-18docker

Overview

A Docker image is an immutable, layered file system built from a Dockerfile. Each instruction adds a layer; layers are cached, so re-building after small changes is fast. The final image contains everything the application needs to run - OS base, runtime, dependencies, and code.

graph TD
    A[Dockerfile] --> B["FROM base-image"]
    B --> C["WORKDIR /app"]
    C --> D["COPY/ADD files"]
    D --> E["RUN install deps / build"]
    E --> F["CMD/ENTRYPOINT - default command"]
    F --> G["docker build → Docker image"]
    G --> H["docker run → running container"]
    style G fill:#1e1b4b,color:#fff

Core Dockerfile Instructions

Instruction Purpose
FROM Base image (required first instruction)
WORKDIR Set the working directory inside the image
COPY Copy files from build context into image
ADD Like COPY but also handles URLs and auto-extracts tarballs
RUN Execute commands during build (installs, builds)
ENV Set environment variables
EXPOSE Document which port the app uses
CMD Default command when container starts (overridable)
ENTRYPOINT Fixed executable; CMD provides default args
ARG Build-time variables (not in the final image)

A Practical Node.js Example

# 1. Base image - use a specific version tag, not 'latest'
FROM node:20-alpine

# 2. Working directory inside the container
WORKDIR /app

# 3. Copy dependency manifest first (cache optimization)
COPY package*.json ./

# 4. Install dependencies (cached layer unless package.json changed)
RUN npm ci --omit=dev

# 5. Copy application code
COPY . .

# 6. Document the port (informational; doesn't publish it)
EXPOSE 3000

# 7. Run the app
CMD ["node", "server.js"]

A Python Example

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

ENV FLASK_ENV=production
EXPOSE 5000

CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:5000"]

Building the Image

docker build -t myapp:1.0 .          # build, tag as myapp:1.0, context = current dir
docker build -t myapp:1.0 -f path/to/Dockerfile .   # custom Dockerfile path
docker images                           # list local images

Layer Caching - the Key Optimization

Docker caches each layer. When you rebuild, it reuses cached layers up to the first change. This is why you copy package.json / requirements.txt and install dependencies before copying application code - your npm install or pip install layer is only invalidated when dependencies change, not on every code edit.

Multi-Stage Builds (production best practice)

Multi-stage builds use one stage to compile/build and copy only the artifacts into a lean final image - keeping build tools out of production:

# Stage 1: Build
FROM node:20 AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

# Stage 2: Production image (lean)
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]

The final image contains only the alpine Node runtime + built output - no dev tools, no source, no build cache.

.dockerignore

Like .gitignore but for the Docker build context - exclude node_modules, .git, test files, secrets:

node_modules
.git
*.test.js
.env

Without .dockerignore, the entire project (including node_modules) gets sent to the Docker daemon on every build.

Why This Matters in Interviews

DevOps/backend interviews use this to test containerization knowledge. Key points: each instruction creates a cached layer; copy manifests and install deps before copying code (cache efficiency); use specific image version tags not latest; CMD is overridable, ENTRYPOINT is fixed; multi-stage builds produce lean images; and .dockerignore prevents sending unnecessary context. Explaining layer caching and multi-stage builds separates basic from advanced knowledge.

Common Pitfalls

References

More answers