PTENES
MODULE 4.1

🐳 Docker for Beginners

"It works on my machine" is the phrase Docker was made to put an end to. With it, you package your program with everything it needs in a box that runs the same way on any computer. Here, you’ll learn about containers from scratch and run your first one.

6
Topics
45
Minutes
Basic
Level
Hands-on
Type
1

What Is a Container

One container is a sealed box that carries your program together with everything it needs to run: the code, libraries, the right language version, even a small part of the operating system. You send this box to any computer, and it runs exactly the same. No “installing dependencies,” no “configuring the environment,” no surprises.

IMAGE (template) 📦 code + libs + runtime + OS docker run CONTAINERS (running instances) app #1 app #2 app #3 app #4 app #5 one image, many identical containers

🧠 Analogy: The Fully Packed Suitcase

Imagine you’re traveling and don’t trust yourself to find anything at your destination. So you pack a suitcase with EVERYTHING: clothes, a toothbrush, a pillow, even a power adapter. Wherever you arrive, you open the suitcase and have exactly the same comforts as at home. A container is that suitcase for your program.

  • •The suitcase: the container (the closed box)
  • •What goes inside: your app, the libraries, the right version of everything
  • •The destination: any computer with Docker (your PC, the cloud, the server)
  • •The result: runs the same everywhere, without “it works on my machine”

💡 A container is not a virtual machine

You might think of it as a virtual machine (VM), but it’s much lighter. A VM loads an entire operating system from scratch (takes up gigabytes and takes minutes to start). A container shares the computer’s operating system and packages only what your app needs. That’s why it starts in seconds and you can run dozens of them on the same computer without slowing it down.

2

Installing Docker

Before running any container, you need to install Docker. On Windows and Mac you install Docker Desktop (a program with a window). In Linux, you install Docker Engine directly from the terminal. We’ll go through each operating system.

W

Windows

Docker Desktop (WSL2 must be enabled)

# 1. Download the installer

docker.com/products/docker-desktop

# 2. Run the installer, select "Use WSL 2"

Docker Desktop Installer.exe

# 3. Restart and open Docker Desktop

🍎

macOS

Docker Desktop (Intel or Apple Silicon version)

# Option 1: official site

Download the .dmg and drag it to Applications

# Option 2: Homebrew (if you have it)

$ brew install --cask docker

🐧

Linux (Ubuntu/Debian)

Docker Engine, installed using the official script

# Official installation script

$ curl -fsSL https://get.docker.com | sh

# Run Docker without sudo (log in again afterward)

$ sudo usermod -aG docker $USER

👁 How to confirm it installed

Open the terminal and ask for the version. If a number appears, it’s working:

$ docker --version

Docker version 27.3.1, build ce12230

# More thorough check (client + server):

$ docker info

Server Version: 27.3.1

Containers: 0 Images: 0

If the version appears, Docker is installed and ready. You can skip to the next topic and run your first container.

⚠️ Common Error

Problem: runs docker info and you see "Cannot connect to the Docker daemon".
Solution: Docker is installed, but the engine (daemon) isn’t running. On Windows/Mac, open Docker Desktop and wait for the icon to turn green. On Linux, run sudo systemctl start docker.

3

docker run: Your First Container

The command docker run is the heart of Docker. It does everything at once: downloads the image (if it isn’t there), creates a container from it, and starts it. We’ll go from Docker’s "hello world" to running a real server.

docker run hello-world - The test

This command downloads a tiny image, runs it, and prints a message. It’s the official way to confirm that everything works.

$ docker run hello-world

Unable to find image 'hello-world:latest' locally

latest: Pulling from library/hello-world

Hello from Docker!

This message shows that your installation

appears to be working correctly.

docker run -p - Opening the door

The container is closed off. To access a site inside it from your browser, you connect one of your ports to one of its ports with -p porta-sua:porta-do-container.

# Run nginx (web server) on port 8080

$ docker run -p 8080:80 nginx

# -d = runs in the background (detached)

$ docker run -d -p 8080:80 nginx

a1b2c3d4e5f6...

# Now open it in your browser:

http://localhost:8080

To the left of : and your computer's port; the one on the right is the port inside the container.

docker ps - What's running

Lists the containers running now. With -a also shows the ones that have already stopped.

$ docker ps

CONTAINER ID IMAGE STATUS PORTS

a1b2c3d4e5f6 nginx Up 2 minutes 0.0.0.0:8080->80/tcp

# Stop a container by ID

$ docker stop a1b2c3d4e5f6

# View all, including stopped ones

$ docker ps -a

💡 Tip: you don’t need to memorize the entire ID

The container ID is a long code, but you only need to type the first characters (usually 3 or 4 are enough). Instead of docker stop a1b2c3d4e5f6, just docker stop a1b2. Docker understands.

✓ What TO DO

  • ✓Use -d to run servers in the background
  • ✓Check with docker ps what’s live
  • ✓Stop containers you no longer use (frees up ports and memory)

✗ What NOT to do

  • ✗Change the port (-p 80:8080 when the app uses 80)
  • ✗Forget about containers left running and consuming resources
  • ✗Use the same port on two containers at the same time
4

Images vs. Containers

This is the number one source of confusion for beginners. The rule is simple: the image and the template (stopped, saved on disk) and the container and the running instance (running, active). From a single image, you can create as many containers as you want.

🧠 Analogy: The Recipe and the Cake

A image and the recipe on paper: it only describes; you can't eat it. The container is the cake actually baked and ready on the table. With one recipe, you can bake as many cakes as you want, all the same. Once you’ve eaten one, make another with the same recipe.

  • •Image (recipe): file sitting on disk; it doesn't use memory
  • •Container (cake): running process that uses CPU and memory
  • •1 image -> N containers: one recipe, several cakes

IMAGE commands

# List images on disk

$ docker images

REPOSITORY TAG SIZE

nginx latest 187MB

# Download an image

$ docker pull node:20

# Delete an image

$ docker rmi nginx

CONTAINER commands

# List running containers

$ docker ps

# Stop a container

$ docker stop a1b2

# Delete a stopped container

$ docker rm a1b2

# View its logs (output)

$ docker logs a1b2

⚠️ Common Error

Problem: try docker rmi nginx and you see "image is being used by running container".
Solution: you can't remove the recipe while there's a cake on the table. Stop and remove the containers that use the image first (docker stop + docker rm), then delete the image.

📦
images

List Templates

⬇
pull

Download template

▶
ps

Live containers

🗑
rm / rmi

Delete

5

Dockerfile: The Container Recipe

So far, you’ve used ready-made images (nginx, hello-world). But what about YOUR program? To package your code into an image, you write a Dockerfile: a text file with the instructions, line by line, for how to build the image.

📝 An example Dockerfile (Node app)

# starts from a base image with Node already installed

FROM node:20

# working directory inside the container

WORKDIR /app

# copies your project files into

COPY . .

# runs a command when building the image

RUN npm install

# command that runs when the container starts

CMD ["node", "server.js"]

FROM - where to start

Every recipe starts from a ready-made base image (Node, Python, Ubuntu...). You don’t build everything from scratch; you start with something that already exists.

COPY - bring your code in

Copies files from your computer into the image. The COPY . . takes the entire current folder to the container's working directory.

RUN - run during setup

Runs a command while the image is being built (e.g., installing dependencies). The result is saved in the image.

CMD - what to do when it starts

Defines the command that runs when the container starts. Unlike RUN (during the build), CMD runs at execution time.

💡 Tip: RUN x CMD

The most common confusion: RUN happens when you builds the image (once, then freeze it in the template). CMD happens when you runs the container (every time it starts). Think: RUN = packing the suitcase; CMD = what you do when you arrive at your destination.

6

Build and Push: From Dockerfile to the World

You have the Dockerfile (the recipe). Now comes the final cycle: build turns the recipe into an image, run starts a container from it, and push pushes the image to a cloud registry so any server can download and run it.

1

Build: create the image

O -t give the image a name (tag). The period at the end means the current folder (where the Dockerfile is).

$ docker build -t meu-app .

[+] Building 12.3s

=> [1/4] FROM node:20

=> [4/4] RUN npm install

=> naming to docker.io/library/meu-app

2

Run: test locally

Before sharing it with the world, run the image you just put together.

$ docker run -p 3000:3000 meu-app

Server running on port 3000

3

Push: upload to the registry

The registry is the “image cloud” (Docker Hub is the most common). You log in, tag the image with your username, and push it.

# 1. log in to Docker Hub

$ docker login

# 2. mark it with your username

$ docker tag meu-app seuuser/meu-app:1.0

# 3. send it to the cloud

$ docker push seuuser/meu-app:1.0

The push refers to repository [docker.io/seuuser/meu-app]

1.0: pushed

👁 The complete cycle, from zero to deploy

# 1. write the recipe (Dockerfile)

# 2. build the image

$ docker build -t seuuser/meu-app:1.0 .

# 3. send it to the registry

$ docker push seuuser/meu-app:1.0

# 4. on the server, download and run it

$ docker run -d -p 80:3000 seuuser/meu-app:1.0

✓ What TO DO

  • ✓Version the tag (:1.0, :1.1) instead of just latest
  • ✓Test with docker run before pushing
  • ✓Create one .dockerignore to avoid copying junk

✗ What NOT to do

  • ✗Putting passwords/tokens inside the image
  • ✗Push an image that has never run locally
  • ✗Push the folder node_modules inside the image

🏆 Congratulations!

You now understand the entire Docker cycle: image, container, Dockerfile, build, and push. This means your program runs the same on your PC and on any server in the world. In the next module, you’ll learn to orchestrate multiple containers at once with Docker Compose.

📚 Module Summary

✓
A container is a complete suitcase - packages the app and everything it needs; runs the same anywhere
✓
docker --version and docker run - installed and ran your first container (hello-world, nginx with -p)
✓
An image is the template; a container is the instance - one image can generate as many containers as you want
✓
Dockerfile is the recipe - FROM, COPY, RUN, CMD build your app's image
✓
build and push - docker build -t creates the image, docker push sends it to the registry

Next Module:

4.2 - Docker Compose: orchestrating multiple containers (app + database + cache) with a single file