If you’ve ever heard a developer say “just run it in Docker” and had no idea what that actually meant, you’re in exactly the right place. Docker for beginners doesn’t have to be intimidating — at its core, it solves one very relatable problem: getting an app to run the same way on your machine as it does on someone else’s.

Docker packages an application together with everything it needs to run — code, dependencies, system tools, even the exact software versions — into a lightweight, portable unit called a container. Instead of manually installing Python, MySQL, and a dozen other dependencies on your computer, you can describe them once and run them anywhere Docker is installed.

This guide covers the Docker basics every beginner should know: what containers actually are, the core Docker concepts and commands, and how Docker Compose lets you run a multi-part application — like a Flask app connected to a MySQL database — with a single command.

What Is Docker?

Docker is a platform for building, running, and sharing applications inside containers. A container bundles an application with its dependencies so it runs consistently, whether it’s on your laptop, a teammate’s machine, or a production server.

Containers vs. Virtual Machines

If you’ve read about virtual machines, containers might sound familiar — but they solve the same problem differently:

  • A virtual machine includes an entire guest operating system, making it heavier and slower to start.
  • A container shares the host machine’s operating system kernel and only packages the application and its dependencies, making it much lighter and faster to start — usually in seconds.

Containers trade some of a VM’s isolation for speed and efficiency, which is exactly why they’ve become the standard for running modern web applications.

Core Docker Concepts

A handful of terms show up constantly once you start using Docker:

  • Image — a read-only template that defines what goes inside a container (code, dependencies, configuration).
  • Container — a running instance of an image.
  • Dockerfile — a text file with instructions for building an image.
  • Docker Hub — a public registry of ready-made images (like python, mysql, or nginx) you can build on top of.
  • Docker Compose — a tool for defining and running multi-container applications with one configuration file.

How to Install Docker

Docker Desktop provides everything you need on Windows and macOS, including Docker Engine, Docker Compose, and a graphical interface for managing containers. On Linux, you can install Docker Engine directly through your distribution’s package manager. Once installed, confirm it’s working:

docker --version
docker run hello-world

If you see a welcome message from the hello-world container, Docker is installed correctly.

Basic Docker Commands Cheat Sheet

CommandPurpose
docker run <image>Run a container from an image
docker psList running containers
docker ps -aList all containers, including stopped ones
docker imagesList downloaded images
docker build -t <name> .Build an image from a Dockerfile
docker stop <container>Stop a running container
docker rm <container>Remove a stopped container
docker rmi <image>Remove an image
docker exec -it <container> bashOpen a shell inside a running container
docker logs <container>View a container’s output/logs

What Is Docker Compose?

Most real applications aren’t just one piece — a typical web app needs a server and a database at minimum. Docker Compose lets you define every part of that application in a single docker-compose.yml file, then start the entire stack with one command instead of manually running and connecting each container yourself.

Example: Flask + MySQL with Docker Compose

Let’s put this into practice with a common beginner project: a Flask app that connects to a MySQL database, both running in their own containers.

Project Structure

flask-mysql-app/
├── app.py
├── requirements.txt
├── Dockerfile
└── docker-compose.yml

The Flask App

# app.py
import os
import mysql.connector
from flask import Flask

app = Flask(__name__)

def get_db_connection():
    return mysql.connector.connect(
        host=os.environ.get("MYSQL_HOST", "localhost"),
        user=os.environ.get("MYSQL_USER", "root"),
        password=os.environ.get("MYSQL_PASSWORD", ""),
        database=os.environ.get("MYSQL_DB", "exampledb"),
    )

@app.route("/")
def index():
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute("SELECT VERSION()")
    db_version = cursor.fetchone()
    cursor.close()
    conn.close()
    return f"Connected to MySQL version: {db_version[0]}"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
# requirements.txt
flask
mysql-connector-python

Notice that MYSQL_HOST defaults to localhost, but in Docker Compose it will actually be set to db — the name of the MySQL service, which Docker resolves automatically over its internal network.

The Dockerfile

FROM python:3.12-slim

WORKDIR /app

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

COPY . .

EXPOSE 5000
CMD ["python", "app.py"]

The docker-compose.yml File

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      MYSQL_HOST: db
      MYSQL_USER: root
      MYSQL_PASSWORD: examplepass
      MYSQL_DB: exampledb
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: examplepass
      MYSQL_DATABASE: exampledb
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 5s
      retries: 10

volumes:
  db_data:

Why the healthcheck matters: MySQL can take a few seconds to fully start up inside its container. Without the healthcheck and condition: service_healthy, Flask’s container might start and try to connect before MySQL is actually ready — a classic beginner gotcha that looks like a random connection error on the first run.

Running the Project

Start everything with one command from the project folder:

docker compose up --build

Once both containers are running, visit http://localhost:5000 in your browser. You should see a message confirming the Flask app successfully connected to MySQL.

To stop everything:

docker compose down

Add the -v flag (docker compose down -v) if you also want to delete the stored database data.

Common Beginner Mistakes to Avoid

  • Forgetting to rebuild after changing the Dockerfile. Use docker compose up --build to force a rebuild.
  • Connecting to localhost instead of the service name. Inside Docker Compose, containers reach each other by service name (like db), not localhost.
  • Skipping the healthcheck on a database service, then wondering why the app fails to connect on the first startup.
  • Hardcoding credentials directly in docker-compose.yml for a real project — use an .env file instead once you move past a learning example.

Conclusion

Docker for beginners boils down to one core idea: package an application and everything it needs into a portable container, so it runs the same way everywhere. From there, Docker Compose extends that idea to multi-part applications — like the Flask and MySQL example in this guide — letting you spin up an entire stack with a single command instead of configuring each piece by hand.

Start by getting comfortable with basic Docker commands and the image-versus-container distinction, then work through a small Compose project like the one here. Once you’ve connected a real app to a real database through Docker Compose, the rest of the Docker ecosystem — multi-service architectures, deployment pipelines, orchestration tools like Kubernetes — becomes a lot less intimidating and a lot more approachable.