My notes from learning Docker β explained simply for absolute beginners
π³ This is Part 2 of my Docker series!
In my previous post, I covered the fundamentals:
- What is Docker and why use it
- Containers vs Virtual Machines
- Installing Docker
- Images vs Containers
- Docker Hub and Registries
- Essential commands (pull, run, stop, ps)
- Port binding
π Read Part 1: Docker for Beginners: A Complete Guide to Containerisation
What You'll Learn in This Post
Now that you understand Docker basics, it's time to build your own images! In this post, I'll cover:
- π Dockerfile β Writing instructions to create images
- ποΈ FROM β Choosing a base image
- βοΈ RUN β Installing packages during build
- π COPY β Adding your files to the image
- π Downloading files β Using curl efficiently
- π CMD β Setting the startup command
- π§ Overriding commands β Running containers interactively
By the end, you'll be able to create your own custom Docker images from scratch!
π Table of Contents
- Creating Images with Dockerfile
- The FROM Instruction
- Building a Dockerfile
- Naming Your Image with Tags
- The RUN Instruction
- COPYing Files into an Image
- Downloading Files in Docker
- The CMD Instruction
- Overriding the Default Start Command
- Quick Reference Cheat Sheet
Creating Images with Dockerfile
A Dockerfile is a text file with instructions to build a Docker image.
The Flow
Dockerfile β Build β Docker Image β Run β Container
π π¨ π βΆοΈ π¦
Recipe Cooking Frozen Meal Heat Hot Meal
The FROM Instruction
Every Dockerfile must start with FROM. It tells Docker what base image to use.
FROM ubuntu
FROM python:3.11
FROM node:18-alpine
With Specific Versions (Recommended)
FROM ubuntu:22.04
FROM python:3.11.4
FROM node:18.17.0-alpine
π‘ Always use specific versions in production to avoid unexpected changes!
Why Use a Base Image?
| Starting Point | What You Get |
|---|---|
FROM ubuntu |
Empty OS, install everything yourself |
FROM python:3.11 |
Python already installed |
FROM node:18 |
Node.js already installed |
FROM postgres:15 |
Full database ready to use |
Building a Dockerfile
The Build Command
docker build .
The . (dot) means "look for Dockerfile in current folder".
What the Dot Means
| Command | Where Docker Looks |
|---|---|
docker build . |
Current folder |
docker build ./app |
The app subfolder |
docker build .. |
Parent folder |
Build Output
$ docker build .
[+] Building 0.1s (5/5) FINISHED
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 54B
=> CACHED [1/1] FROM docker.io/library/ubuntu
=> exporting to image
=> => writing image sha256:a67f41b1d127160a7647b6709...
Naming Your Image with Tags
Without a name, your image gets a random ID like sha256:a67f41b1d127... π
Use the -t Flag
docker build -t my-app .
Add Version Numbers
docker build -t my-app:v1.0 .
docker build -t my-app:v1.1 .
docker build -t my-app:latest .
Real Example
# Build and name it
docker build -t my-python-app:v1 .
# Now you can run it easily
docker run my-python-app:v1
The RUN Instruction
RUN executes commands during the build process.
RUN <shell-command>
Example: Installing Python
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y python3
What Does apt-get update Do?
It refreshes the package list (catalog of available software):
| Command | What It Does | Analogy |
|---|---|---|
apt-get update |
Get latest list of packages | Get the restaurant menu |
apt-get install python3 |
Install the package | Order from the menu |
The -y Flag
RUN apt-get install -y python3
-y = "Yes to all prompts"
Without it, Docker would wait for you to type "Y" (which you can't do during build!).
Combine Commands for Smaller Images
# β BAD - Creates 3 layers
RUN apt-get update
RUN apt-get install -y python3
RUN apt-get install -y curl
# β
GOOD - Creates 1 layer
RUN apt-get update && apt-get install -y python3 curl
COPYing Files into an Image
COPY takes files from your computer and puts them inside the image.
COPY <source-on-computer> <destination-in-image>
Copy a Single File
COPY app.py /app/app.py
Copy to Folder (Keeps Same Name)
COPY app.py /app/
# Result: /app/app.py
Copy Entire Folder
COPY src/ /app/
# Copies everything in src/ to /app/
β οΈ Important Rule: No Parent Directory Access
# β This will FAIL
COPY ../secret-file.txt /app/
# Docker can't access files ABOVE the Dockerfile location (security!)
Visual Example
Your Computer: Inside Image:
my-project/ /app/
βββ Dockerfile βββ main.py
βββ main.py βCOPYβ βββ utils.py
βββ utils.py βββ config.py
Downloading Files in Docker
Instead of COPY, you can download files from the internet:
Three Steps
# 1. Download
RUN curl https://example.com/file.zip -o /tmp/file.zip
# 2. Unzip
RUN unzip /tmp/file.zip -d /app/
# 3. Remove zip (cleanup)
RUN rm /tmp/file.zip
β‘ Efficient Way (Single Instruction)
Each RUN creates a layer. Even deleted files add to image size!
# β BAD - 3 layers, zip still counts toward size
RUN curl https://example.com/file.zip -o /tmp/file.zip
RUN unzip /tmp/file.zip -d /app/
RUN rm /tmp/file.zip
# β
GOOD - 1 layer, zip deleted before layer saves
RUN curl https://example.com/file.zip -o /tmp/file.zip \
&& unzip /tmp/file.zip -d /app/ \
&& rm /tmp/file.zip
What Does && Mean?
&& = "then do this" (runs next command only if previous succeeded)
What Does \ Mean?
\ = "continue on next line" (makes long commands readable)
The CMD Instruction
CMD tells Docker what command to run when the container starts.
CMD <shell-command>
RUN vs CMD
| Instruction | When It Runs | Purpose |
|---|---|---|
RUN |
During build | Install software, setup |
CMD |
At startup | Start your application |
Examples
# Run a Python script
CMD python3 app.py
# Start a web server
CMD npm start
# Run a shell script
CMD ./start.sh
Key Points About CMD
- Only the LAST CMD counts (if you have multiple)
- Does NOT increase image size
- Does NOT add time to build
Complete Example
FROM python:3.11
COPY app.py /app/
WORKDIR /app
CMD python3 app.py
When you run this:
docker run my-app
# Automatically executes: python3 app.py
Overriding the Default Start Command
You can replace the CMD when running a container:
Default (Uses CMD)
docker run my-image
# Runs whatever CMD is in the Dockerfile
Override with Your Command
docker run my-image echo "Hello!"
# Ignores CMD, runs "echo Hello!" instead
Interactive Mode
docker run -it ubuntu bash
| Flag | Meaning |
|---|---|
-i |
Interactive - keeps input open |
-t |
Terminal - shows proper console |
This opens a shell inside the container:
$ docker run -it ubuntu bash
root@abc123:/# ls
bin boot dev etc home lib ...
root@abc123:/# echo "I'm inside the container!"
I'm inside the container!
root@abc123:/# exit
$
When to Use Override?
| Use Case | Command |
|---|---|
| Debug inside container | docker run -it my-image bash |
| Run different script | docker run my-image python3 other.py |
| Check files inside | docker run my-image ls /app |
Quick Reference Cheat Sheet
Dockerfile Instructions
| Instruction | Purpose | Example |
|---|---|---|
FROM |
Base image | FROM ubuntu:22.04 |
RUN |
Run command during build | RUN apt-get install -y python3 |
COPY |
Copy files into image | COPY app.py /app/ |
CMD |
Command to run at startup | CMD python3 app.py |
WORKDIR |
Set working directory | WORKDIR /app |
Docker CLI Commands
| Command | What It Does |
|---|---|
docker build -t name . |
Build image from Dockerfile |
docker run image |
Run a container |
docker run -it image bash |
Run with interactive shell |
docker images |
List all images |
docker ps |
List running containers |
docker pull image:tag |
Download an image |
Example Dockerfile
# Start from Python base image
FROM python:3.11-slim
# Set working directory
WORKDIR /app
# Copy requirements first (for caching)
COPY requirements.txt .
# Install dependencies
RUN pip install -r requirements.txt
# Copy application code
COPY . .
# Command to run at startup
CMD ["python", "app.py"]
Build and Run
# Build the image
docker build -t my-python-app:v1 .
# Run the container
docker run my-python-app:v1
# Run with interactive shell (for debugging)
docker run -it my-python-app:v1 bash
Summary
Today I learned:
β Dockerfile is a recipe for building images
β FROM sets the base image (always first!)
β RUN executes commands during build
β COPY puts files from your computer into the image
β CMD runs when the container starts
β docker build -t name . builds and names your image
β docker run -it image bash lets you explore inside a container
β
Use && to combine commands for smaller images
π¬ Keep Learning With Me!
I'm documenting my learning journey in public. If you found this helpful, check out my blog for more tutorials:
π kerempakten.dev
You'll find:
- π³ DevOps & Cloud tutorials
- π» Project breakdowns & real code
- π― Career tips for new graduates
- π Honest "building in public" updates
I'm a recent Computer Science graduate from King's College London, learning and sharing everything along the way. No gatekeeping β just practical knowledge for beginners like us!
Let's connect and learn together! π
Found an error or have a suggestion? Drop a comment below!
Top comments (0)