>_
EngineeringNotes
Back to Docker Modules

Dockerfiles & Building

Mastering the Art of Building Images and composing services.

The Dockerfile

A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.

# 1. Start from a base image
FROM node:18-alpine

# 2. Set working directory
WORKDIR /app

# 3. Copy package files
COPY package*.json ./

# 4. Install dependencies
RUN npm install

# 5. Copy source code
COPY . .

# 6. Expose port
EXPOSE 3000

# 7. Start the app
CMD ["npm", "start"]

For Building Docker Image

Terminal
bash
docker build -t my-app .
OR
Terminal
bash
docker build -t my-app:v1 .
Terminal
bash
docker run -p 3000:3000 my-app

The Anatomy of a Dockerfile

Dockerfile.explained
Build Time (Steps 1-6)Run Time (Step 7)
# 1. Base Image: Starting Point (OS + Runtime)
FROM node:18-alpine

We select an existing node image for ease. We could use Ubuntu and manually install Node, but this is efficient.

# 2. Set working directory
WORKDIR /app

Defines where inside the container we will keep our code base.

# 3. Copy package files ONLY
COPY package*.json ./

We copy only package.json first. This is crucial for caching!

# 4. Install dependencies
RUN npm install

Installs all dependencies defined in package.json.

# 5. Copy source code
COPY . .

Now we copy the rest of the codebase.

# 6. Expose port
EXPOSE 4000

Documentation step. Tells users which port the app listens on by default.

# 7. Start the app
CMD ["npm", "start"]

RUNTIME: This command runs automatically when someone starts the container.

Layer Caching & Optimization

In the industry, we don't just want our code to run; we want our deployment pipelines to be fast and efficient. Docker is "smart"—it caches layers. If a layer and all previous layers haven't changed, Docker reuses the cached version.

The "Lazy" Way

COPY . .
RUN npm install
  • • Copies everything first.
  • • If you change 1 line of code, cache invalidates.
  • Result: npm install runs on EVERY build.
  • Time: Slow 🐢

The Professional Way

COPY package*.json ./
RUN npm install
COPY . .
  • • Copies dependency files first.
  • • Dependencies change rarely.
  • Result: npm install comes from CACHE.
  • Time: Instant ⚡

How it works: The Union File System (UnionFS)

The "Transparent Sheets" Analogy

Imagine drawing on transparent plastic sheets (projector transparencies).

  • 1.Base Layer: You ask for "Node.js". Docker puts down a sheet with the OS and Node files. This sheet is Locked (Read-Only).
  • 2.New Instructions: Every COPY or RUN command puts a fresh transparent sheet on top.
  • 3.The View: When you look from above, you see one combined image—the Union of all sheets.
Why this matters for Speed:

Reuse

If you build 5 different apps that all use FROM node:18, Docker only downloads/stores that bottom sheet once.

Invalidation

If you change a sheet in the middle, Docker must throw away that sheet and every sheet above it. This is why we put stable sheets (dependencies) at the bottom!

RUN vs CMD: The Eternal Confusion

RUN

Executes commands DURING the build process. It creates a new layer in the image.

Use Case

  • Installing packages (npm, pip, apt)
  • Building code (npm run build)
  • Setting up folders
RUN npm install react
Build Time

(Happens when you run docker build)

CMD

Executes commands AUTOMATICALLY when the container starts.

Triggers When:

  • docker run -p ...
  • docker start ...

"Internally, my image runs this command to wake up."

CMD ["npm", "start"]
Run Time

(Happens when you run the image)

💡

Mental Model

RUN is like preparing the kitchen (buying ingredients, chopping types).
CMD is like opening the restaurant (serving the food).

Sharing with the World: Push to DockerHub

Once you've built your image, it lives only on your laptop. To share it (or deploy it to a server), you need to push it to a registry like Docker Hub.

1

Create Repository

Go to hub.docker.com, sign up, and click Create Repository.

Repo Name Example:my-node-app
  • * Public/Private: You can choose visibility when creating manually.
  • * Auto-Create: If you skip this and just push, it defaults to a Public repo.
2

Login to CLI

Connect your terminal to your account.

docker login -u <username>
(Enter your password/token when prompted)
3

Build & Tag properly

This is crucial! Your image name MUST start with your Docker Hub username.

# Syntax: docker build -t username/repo:tag .
docker build -t <username>/my-node-app:v1 .
⚠️ If you don't use your username prefix, permission will be denied!

If error occurs like this: tag does not exist: <username>/my-node-app:v1

Run this command to fix it:

docker tag my-node-app:v1 <username>/my-node-app:v1
4

Push!

Uploads (pushes) your layers to the cloud.

docker push <username>/my-node-app:v1