Everyone says "just use Docker."
Nobody explains what it is. Let's fix that first. Then install it. Then run your first container.
Think of a lunchbox.
Without Docker: You cook at your friend's house. Their stove is different. No salt. Wrong pan. Dinner fails.
With Docker: You bring a sealed lunchbox β food, spoon, everything inside. Open it anywhere. Same meal. Every time.
| Real Life | Docker |
|---|---|
| Recipe | Dockerfile |
| Packed, sealed lunchbox | Image |
| Lunchbox opened and being eaten | Container |
| Lunchbox shop (anyone can grab one) | Docker Hub |
π‘ Docker packs your app plus everything it needs into one box that runs the same everywhere.
You build an app on your laptop. It works. π
You move it to a server. It breaks. π₯
Why? Different Python version. Missing library. Different OS settings.
π» Your laptop βοΈ Server
Python 3.12 β Python 3.8
Library X β
Library X β
Works β
Crashes β
Docker's fix: ship the environment together with the app.
π¦ Container = App + Python + Libraries + Settings
β
Runs identically on laptop, server, anywhere
You may have used VirtualBox or VMware. Containers are different.
VIRTUAL MACHINES CONTAINERS
ββββββββ ββββββββ ββββββββ ββββββββ
β App β β App β β App β β App β
ββββββββ€ ββββββββ€ ββββββββ€ ββββββββ€
β OS β β OS β β Libs β β Libs β
β(full)β β(full)β ββββ¬ββββ ββββ¬ββββ
ββββ¬ββββ ββββ¬ββββ ββββββ¬βββββ
ββββββ¬βββββ βββββββ΄ββββββ
βββββββ΄ββββββ β Docker β
β Hypervisorβ βββββββββββββ€
βββββββββββββ€ β Host OS β
β Host OS β βββββββββββββ
βββββββββββββ
| Virtual Machine | Container | |
|---|---|---|
| Has its own full OS | Yes | No, shares the host kernel |
| Size | GBs | MBs |
| Start time | Minutes | Seconds |
| Isolation | Very strong | Strong, but lighter |
| Best for | Running a different OS | Running apps consistently |
Analogy: VM = separate house per family. Container = separate apartment in one building. Same plumbing, own locked door.
| Term | Meaning | Analogy |
|---|---|---|
| Image | Read-only package with your app and its environment | Frozen lunchbox |
| Container | A running instance of an image | Lunchbox being eaten |
| Dockerfile | Text file with build instructions | Recipe |
| Registry | Online store for images (Docker Hub) | Lunchbox shop |
One image β many containers. Same as one recipe β many meals.
IMAGE (nginx)
ββββΊ Container 1 (running)
ββββΊ Container 2 (running)
ββββΊ Container 3 (stopped)
You type: docker run nginx
β
βΌ
βββββββββββββββββ
β Docker CLI β β the command you use
βββββββββ¬ββββββββ
βΌ
βββββββββββββββββ
β Docker Engine β β does the real work
βββββββββ¬ββββββββ
β image not found locally?
βΌ
βββββββββββββββββ
β Docker Hub β β downloads it
βββββββββ¬ββββββββ
βΌ
π¦ Container starts
Why the official repo? Ubuntu's default docker.io package is often outdated. Docker's own repository gives you the current version plus Compose.
β Works on Ubuntu x86 and ARM (including Oracle Cloud Ampere VMs).
Step 1 β Remove old versions (safe even if none exist):
sudo apt remove docker docker-engine docker.io containerd runc
Step 2 β Add Docker's official key and repository:
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Step 3 β Install:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Step 4 β Run Docker without typing sudo every time:
sudo usermod -aG docker $USER
Now log out and log back in (or run newgrp docker).
β οΈ Members of the
dockergroup effectively have root power on the machine. Only add users you trust.
Step 5 β Verify:
docker --version
docker compose version
docker run hello-world
If you see Hello from Docker! β you're done. π
π Commands change over time. If any step fails, check the official guide at docs.docker.com/engine/install/ubuntu
Windows uses Docker Desktop. It runs Linux containers through WSL 2 (Windows Subsystem for Linux).
Step 1 β Enable virtualization. Open Task Manager β Performance β CPU. Check that Virtualization: Enabled. If disabled, turn it on in BIOS.
Step 2 β Install WSL 2. Open PowerShell as Administrator:
wsl --install
Restart when asked.
Step 3 β Download Docker Desktop from docker.com and run the installer. Keep Use WSL 2 ticked.
Step 4 β Start Docker Desktop. Wait until the whale icon says it is running.
Step 5 β Verify in PowerShell:
docker --version
docker compose version
docker run hello-world
π‘ Docker Desktop has licensing terms for larger companies. Personal use and learning are fine.
hello-world proves it works. Now run something useful β a web server.
docker run -d --name my-web -p 8080:80 nginx
Break it down:
| Part | Meaning |
|---|---|
docker run |
Create and start a container |
-d |
Detached β run in background |
--name my-web |
Give it a name you can remember |
-p 8080:80 |
Map your port 8080 to the container's port 80 |
nginx |
The image to use (downloaded from Docker Hub) |
Open your browser: http://localhost:8080
You'll see the Nginx welcome page. You just ran a web server without installing Nginx.
Browser β localhost:8080 β [ Docker ] β container port 80 β Nginx
Clean up:
docker stop my-web
docker rm my-web
| Command | What it does |
|---|---|
docker pull nginx |
Download an image |
docker images |
List downloaded images |
docker ps |
List running containers |
docker ps -a |
List all containers, including stopped |
docker logs my-web |
See what the container printed |
docker exec -it my-web sh |
Open a shell inside a running container |
docker stop my-web |
Stop a container |
docker rm my-web |
Delete a stopped container |
Extra cleanup:
docker rmi nginx delete an image
docker system prune remove unused stuff (asks first)
On a server, this command:
docker run -d -p 8080:80 nginx
opens port 8080 to the whole internet. Docker edits firewall rules itself, so UFW does not stop it.
Safer on a server:
docker run -d -p 127.0.0.1:8080:80 nginx
Now only the server itself can reach it. Put Nginx or a firewall rule in front for public access.
| Command | Who can reach it |
|---|---|
-p 8080:80 |
Everyone β οΈ |
-p 127.0.0.1:8080:80 |
Only the server β |
| Error | Cause | Fix |
|---|---|---|
permission denied ... docker.sock |
User not in docker group | Step 4 above, then re-login |
Cannot connect to the Docker daemon |
Docker not running | Linux: sudo systemctl start docker Β· Windows: open Docker Desktop |
port is already allocated |
Port in use | Use a different host port, like -p 8081:80 |
WSL 2 installation is incomplete |
WSL not set up | Run wsl --install, restart |
Virtualization is disabled |
BIOS setting | Enable virtualization in BIOS |
name is already in use |
Old container has that name | docker rm my-web first |
Docker = packs app + environment into one portable box
Image = the frozen package
Container = the image, running
Dockerfile = recipe to build an image
Docker Hub = online store of images
Container β VM: lighter, shares the host kernel
Ubuntu = install from Docker's official repo
Windows = Docker Desktop + WSL 2
Test = docker run hello-world
Server rule = bind ports to 127.0.0.1 unless you want the internet in
Dockerize Your Flask App with Dockerfile and Docker Compose
TechWithJuned Β· Learn β Execute β Build
π¬ Questions & Discussion
Have a doubt? Ask below β no login needed.
Loading comments...