Docker w 20 minut — konteneryzacja bez bólu głowy

Zrozum Docker od podstaw i uruchom pierwszy kontener bez chaosu. Obrazy, kontenery, Dockerfile, volumes i docker compose w praktyce.

Opublikowano

15 października 2025 12:40

Czytanie

5 min czytania

Aktualizacja

15 kwietnia 2026 11:52

"Zainstaluj Docker", "uruchom docker compose up", "odpal to w kontenerze" — te zdania padają dziś tak często, jak kiedyś "zrób npm install". Docker stał się standardowym elementem workflow, ale dla wielu frontendowców nadal brzmi jak osobny świat DevOps.

W praktyce Docker rozwiązuje bardzo konkretny problem: środowisko uruchomieniowe przestaje zależeć od tego, co masz aktualnie zainstalowane lokalnie. W tym artykule przejdziemy przez podstawy bez mistyki i bez założenia, że chcesz zostać administratorem systemów.

Krótka odpowiedź: Docker pakuje aplikację z jej zależnościami w kontener, który działa identycznie na każdym komputerze. Podstawy dla frontendowca: docker run (uruchom kontener), Dockerfile (zbuduj obraz), docker compose (wiele kontenerów, np. app + baza danych). Najważniejszy use case: lokalny stack dev z bazą PostgreSQL bez globalnej instalacji.

Po co Docker?

Problem

Code
Developer A: Node 18, PostgreSQL 14
Developer B: Node 20, PostgreSQL 15
Serwer:      Node 16, PostgreSQL 13

Efekt: "U mnie działa, na produkcji nie"

Rozwiązanie

Code
Kontener = aplikacja + zależności
Działa identycznie wszędzie

Podstawowe pojęcia

  • Image (obraz): Szablon. Read-only. Jak klasa.
  • Container (kontener): Uruchomiona instancja. Jak obiekt.
  • Dockerfile: Instrukcja budowania obrazu.
  • docker compose: Uruchamianie wielu kontenerów.
  • Volume: Trwałe dane poza cyklem życia kontenera.

Najważniejsza rzecz do zapamiętania: kontener to nie pełna maszyna wirtualna. To izolowany proces z własnym filesystemem, siecią i zależnościami, ale współdzielący kernel hosta.

Instalacja

Pobierz Docker Desktop (macOS/Windows). Docker Desktop zawiera dziś także docker compose.

Na Linuksie możesz zainstalować Dockera z repozytorium dystrybucji lub z oficjalnych paczek:

Code
# Linux
sudo apt install docker.io  # docker compose V2 jest wbudowany

Pierwsze kroki

Code
# Szybki test instalacji
docker run --rm hello-world
 
# Uruchom kontener w tle
docker run -d -p 8080:80 nginx
# http://localhost:8080 -> nginx
 
# Lista kontenerów
docker ps
 
# Zatrzymaj
docker stop <container_id>
 
# Logi
docker logs <container_id>
 
# Wejdź do kontenera
docker exec -it <container_id> sh

Najlepiej myśleć o tym tak: docker run bierze obraz i tworzy z niego działający proces. Gdy kontener usuniesz, jego lokalny filesystem zwykle znika razem z nim, chyba że używasz volume.

Dockerfile

Code
FROM node:20-alpine
 
WORKDIR /app
 
COPY package.json package-lock.json ./
RUN npm ci
 
COPY . .
 
EXPOSE 3000
 
CMD ["npm", "start"]
Code
# Zbuduj
docker build -t my-app .
 
# Uruchom
docker run -d -p 3000:3000 my-app

Kolejność instrukcji nie jest przypadkowa. Najpierw kopiujesz pliki zależności i instalujesz pakiety, a dopiero potem resztę projektu. Dzięki temu Docker lepiej wykorzystuje cache warstw i nie reinstaluje wszystkiego po każdej drobnej zmianie w kodzie.

.dockerignore

Code
node_modules
.next
.git
.env.local

docker compose

Code
# compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy
  
  db:
    image: postgres:14
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 5s
      timeout: 5s
      retries: 10
 
volumes:
  postgres_data:
Code
# Uruchom wszystko
docker compose up -d
 
# Zatrzymaj
docker compose down
 
# Logi
docker compose logs -f

W tym przykładzie łączymy Node.js z PostgreSQL — najpopularniejszą relacyjną bazą danych w fullstack projektach.

Ważny niuans: samo depends_on nie oznacza jeszcze, że baza jest gotowa na połączenia. Dlatego dodałem healthcheck. I tak w realnej aplikacji warto mieć retry po stronie aplikacji, bo "kontener uruchomiony" nie zawsze znaczy "usługa gotowa".

Development z hot-reload

Code
# compose.dev.yml
services:
  app:
    build: .
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    command: npm run dev

To klasyczny układ developerski: bind mount mapuje lokalny katalog projektu do kontenera, a osobny mount na /app/node_modules chroni zależności zainstalowane w kontenerze przed nadpisaniem przez hosta.

Przydatne komendy

Code
# Obrazy
docker images
docker rmi <image_id>
 
# Kontenery
docker ps -a
docker rm <container_id>
docker rm -f $(docker ps -aq)  # usuń wszystkie — ostrożnie
 
# Volumes
docker volume ls
docker volume prune
 
# Czyszczenie
docker system prune -a  # czyści agresywnie obrazy/cache

Komendy czyszczące są wygodne, ale potrafią zabrać Ci obrazy, cache builda i nieużywane wolumeny, których jednak jeszcze potrzebowałeś. Zanim odruchowo użyjesz prune, sprawdź, co dokładnie zostanie usunięte.

Multi-stage build (optymalizacja)

Code
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
 
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]

To podejście zmniejsza obraz i oddziela etap budowania od etapu uruchamiania. W praktyce prawie każdy sensowny obraz produkcyjny powinien być multi-stage.

FAQ

Czym jest Docker i do czego służy?

Docker to platforma do konteneryzacji — pakuje aplikację razem z jej zależnościami (Node.js w konkretnej wersji, biblioteki systemowe, konfiguracja) w izolowany kontener. Kontener działa identycznie na każdym komputerze i serwerze, eliminując problem "u mnie działa, na produkcji nie". Dla frontendowców najważniejszy use case: uruchomienie lokalnej bazy danych bez instalowania PostgreSQL/Redis/MongoDB globalnie.

Jaka różnica między Docker image a kontenerem?

Image (obraz) to read-only szablon — jak klasa lub blueprint. Zawiera system plików, kod aplikacji, środowisko uruchomieniowe. Kontener to uruchomiona instancja image — jak obiekt stworzony z klasy. Możesz uruchomić wiele kontenerów z jednego image. Image budujesz przez docker build, kontenery uruchamiasz przez docker run. Gdy kontener usuniesz, jego lokalny filesystem znika — dane przeżywają restart tylko gdy używasz volumes.

Czym jest docker compose i kiedy go używać?

docker compose to narzędzie do uruchamiania wielu powiązanych kontenerów z jednego pliku konfiguracyjnego (compose.yml). Definiujesz serwisy (np. aplikacja Node.js + baza PostgreSQL + Redis), ich porty, zmienne środowiskowe, volumes i zależności. Jedno polecenie docker compose up -d uruchamia cały stack. Idealne do lokalnego developmentu i prostego deploymentu. Od Docker 20.10+ wbudowany — nie potrzebujesz osobnej instalacji.

Jak skonteneryzować aplikację Node.js?

Stwórz Dockerfile: zacznij od FROM node:20-alpine, ustaw WORKDIR /app, skopiuj package.json i uruchom npm ci, potem skopiuj resztę kodu, expose port i ustaw CMD ["npm", "start"]. Kolejność jest ważna — zależności kopiujesz przed kodem źródłowym, żeby Docker mógł cache'ować tę warstwę i nie reinstalować pakietów przy każdej małej zmianie. Dodaj .dockerignore z node_modules i .next.

Czym jest multi-stage build w Docker?

Multi-stage build dzieli Dockerfile na kilka etapów (stages) — każdy może bazować na innym image. Typowy wzorzec: stage builder używa pełnego Node.js do instalacji zależności i buildu, stage production kopiuje tylko artefakty builda bez devDependencies i narzędzi buildowych. Efekt: znacznie mniejszy obraz produkcyjny (bez webpack, TypeScript, testów), szybszy start kontenera i mniejsza powierzchnia ataku.

Jak uruchomić bazę danych lokalnie przez Docker?

Najprostsza metoda to docker compose z serwisem bazy. W compose.yml dodaj serwis db z image: postgres:14, zmiennymi środowiskowymi (POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB) i volume dla danych. Użyj healthcheck żeby aplikacja czekała na gotowość bazy przed startem. Dane przeżywają restarty kontenerów dzięki named volume. Dostęp: localhost:5432 lub przez nazwę serwisu w sieci Docker (db:5432).

Czym Docker różni się od maszyny wirtualnej?

VM emuluje pełny sprzęt i uruchamia osobny system operacyjny — zajmuje GB RAM i GB na dysku, startuje minutami. Docker kontener współdzieli kernel hosta — uruchamia tylko izolowany proces, zajmuje MB, startuje sekundami. VM daje pełną izolację systemu operacyjnego. Docker daje izolację procesu i środowiska. Docker jest szybszy i lżejszy, VM jest bezpieczniejszy i bardziej izolowany. Dla developmentu i większości deploymentów Docker jest wystarczający.

Źródła i dokumentacja

Podsumowanie

KomendaOpis
docker build -t name .Zbuduj obraz
docker run -d -p 3000:3000 nameUruchom kontener
docker psLista kontenerów
docker logs -f idŚledź logi
docker exec -it id shShell w kontenerze
docker compose up -dUruchom stack
docker compose downZatrzymaj stack

Najważniejsza korzyść z Dockera nie polega na tym, że "używasz nowoczesnego narzędzia". Polega na tym, że środowisko staje się powtarzalne: ten sam Node, ta sama baza, te same komendy, ten sam efekt u Ciebie, u kolegi i na CI.

Jeśli dopiero zaczynasz, zrób trzy rzeczy:

  • uruchom pojedynczy kontener przez docker run
  • zbuduj własny obraz z prostego Dockerfile
  • połącz aplikację z bazą przez docker compose

To wystarczy, żeby Docker przestał być czarną magią i zaczął być po prostu kolejnym narzędziem w workflow.


Chcesz zobaczyć Docker w praktyce? Sprawdź tutorial fullstack — kompletna aplikacja z bazą danych.

Pracuję z tym zawodowo.

Jeśli chcesz uporządkować backendowe fundamenty aplikacji i uniknąć typowych błędów architektonicznych już na starcie, skontaktuj się ze mną. Pomagam przekładać wiedzę techniczną na rozwiązania, które da się sensownie utrzymać i rozwijać.

O autorze

Maciej Sala

Maciej Sala — project manager i frontendowiec z doświadczeniem w marketingu internetowym. Na co dzień pracuję z Reactem, Next.js i TypeScriptem, łącząc perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat związany z branżą gier wideo jako project manager i game designer.

Absolwent historii na Uniwersytecie Jagiellońskim i studiów podyplomowych z marketingu internetowego na Akademii Górniczo-Hutniczej w Krakowie. Poza pracą trenuje na siłowni, maluje figurki i realizuje własne projekty.

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
Anthropic uderza w Figmę i Adobe — oto Claude Design

Anthropic uderza w Figmę i Adobe — oto Claude Design

Anthropic wypuścił właśnie narzędzie AI do tworzenia stron, landing page'ów i prezentacji z promptu. Oto co wiemy o Claude Design i Opus 4.7 — i co to oznacza dla developerów.

Maciej Sala

Maciej Sala

Founder Strivelab

Astro.js vs Next.js — które narzędzie wybrać w 2026 roku?

Astro.js vs Next.js — które narzędzie wybrać w 2026 roku?

Fachowe porównanie Astro.js i Next.js z perspektywy developera pracującego na co dzień w Next.js. Architektura, wydajność, SEO, DX, koszty i konkretne use case — z benchmarkami i przykładami kodu.

Maciej Sala

Maciej Sala

Founder Strivelab