Docker Images — Beginner Friendly Guide

This is the second article in our Docker series. In Part 1, we explored what containers are and how they differ from virtual machines. In this article, we’ll focus on Docker Images, the foundation of every container.
What You’ll Learn
What Docker images are and how they work.
How to write a Dockerfile (with clear explanations).
How to build, run, pull, and push images.
Hands-on recap.
A list of useful Docker image commands.
What is a Docker Image?
A Docker image is like a blueprint for your application. It contains everything your app needs to run: code, libraries, dependencies, and configurations.
Image → Recipe (instructions to cook a dish).
Container → The actual dish (running instance of the image).
Without an image, you cannot create a container.
Layers in an Image
Each instruction in a Dockerfile (
FROM,RUN,COPY) creates a new image layer.These layers are stacked to form the final image.
Layers are cached to make builds faster.
Run this to see the layers of any image:
docker history <image-name>
Building Docker Images
To build an image, we need a Dockerfile contains simple text and a set of instructions.
We’ll use the Python Flask To-Do app for this demo (repo link: docker-python-flask-todo-app).
Step 1: Write a Dockerfile
# Start from a lightweight Python base image
FROM python:3.11-slim
# Set a working directory inside the container
WORKDIR /app
# Copy requirements and install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt
# Copy the rest of the application code to the working directory
COPY . .
# Set environment variables
ENV FLASK_APP=app.py
ENV FLASK_ENV=production
# Expose the port Flask runs on
EXPOSE 5000
# Run Flask when the container starts
CMD ["flask", "run", "--host=0.0.0.0", "--port=5000"]
Dockerfile Explained (Line by Line)
FROM python:3.11-slim
This chooses Python 3.11 slim version as the base image.
“Slim” means it’s smaller and faster to download.
It already has Python installed, so no need to install it yourself.
WORKDIR /app
Sets /app as the working directory inside the container.
All following commands (COPY, RUN, CMD) will run from here.
Without this, everything would run from
/.
COPY requirements.txt . + RUN pip install -r requirements.txt
Copies
requirements.txtinto the container.Installs Python dependencies inside the container.
Copying requirements first ensures Docker caches dependencies. If only your code changes and no changes in the dependencies, Docker won’t reinstall everything.
COPY . .
Copies everything from your project folder into /app.
Includes app.py, templates, and static files.
ENV FLASK_APP=app.py + ENV FLASK_ENV=production
Defines environment variables inside the container.
FLASK_APP=app.py→ tells Flask which file to run.FLASK_ENV=production→ production mode (no auto-reload, fewer debug logs).
For development, you’d use FLASK_ENV=development.
EXPOSE 5000
Documents that the app will use port 5000.
- This doesn’t open the port automatically, you still need
-p 5000:5000when running.
CMD ["flask", "run", "--host=0.0.0.0", "--port=5000"]
Defines the default command when the container starts.
Runs Flask using
flask run.--host=0.0.0.0makes it accessible from outside the container.--port=5000listens on port 5000 inside the container.
If you omit --host=0.0.0.0, Flask defaults to 127.0.0.1 (only accessible inside the container).
Step 2: Build the Image
docker build -t flask-todo-app:1.0 .
-t flask-todo-app:1.0→ tags the image with a name and version..→ tells Docker to use the current directory as the build context.
Check if the image was created:
docker images
Step 3: Run a Container
docker run -d -p 5000:5000 --name flask-todo flask-todo-app:1.0
-d→ run in detached mode (background).-p 5000:5000→ maps your computer’s port 5000 to the container’s port 5000.--name flask-todo→ names the container.
Check running containers:
docker ps
View logs:
docker logs flask-todo
Stop the container:
docker stop flask-todo
Remove the container:
docker rm flask-todo
🔹 Pulling Docker Images
You don’t always need to build from scratch — you can pull existing images from Docker Hub:
docker pull nginx:alpine
If no tag is specified, Docker defaults to latest.
List images:
docker images
🔹 Pushing Docker Images
To share your image:
Step 1: Login
docker login
Step 2: Tag the Image
docker tag flask-todo-app:1.0 <your-dockerhub-username>/flask-todo-app:1.0
Step 3: Push the Image
docker push <your-dockerhub-username>/flask-todo-app:1.0
Now anyone can pull it:
docker pull <your-dockerhub-username>/flask-todo-app:1.0
Hands-On Recap
✅ Clone repo
git clone https://github.com/papani-sivasai/docker-python-flask-todo-app
cd docker-python-flask-todo-app
✅ Build image
docker build -t flask-todo-app:1.0 .
✅ Run container
docker run -d -p 5000:5000 flask-todo-app:1.0
✅ Tag & push to Docker Hub
docker tag flask-todo-app:1.0 <your-dockerhub-username>/flask-todo-app:1.0
docker push <your-dockerhub-username>/flask-todo-app:1.0
✅ Pull & run anywhere
docker pull <your-dockerhub-username>/flask-todo-app:1.0
🔹 Docker Image Commands (Cheat Sheet)
# Build an image
docker build -t name:tag .
# List all images
docker images
# Remove an image
docker rmi image_id
# Pull an image
docker pull image_name:tag
# Push an image
docker push username/image_name:tag
# Tag an image
docker tag source:tag target:tag
# View image layers
docker history image_name:tag
# Inspect detailed info
docker inspect image_name:tag
Visual Recap
Here’s a simple lifecycle diagram:
🔹 Summary
Docker images are the blueprints for containers.
A Dockerfile defines how to build an image.
Use
docker buildto create a image,docker runto start the container,docker pull/pushto share the image.
Give it a try and let me know if your first Docker image build worked! In the next article, we’ll explore Docker Containers in depth using the BMI Calculator React app.