Docker aendrede maden vi bygger, leverer og korer software pa. I stedet for "det virker pa min maskine" garanterer Docker, at din applikation korer pa samme made overalt - pa din laptop, pa en kollegas maskine, i CI/CD og i produktion. I denne guide gar vi fra nul til at deploye en rigtig applikation.
Hvad er Docker?
Docker er en platform, der pakker din applikation og alle dens afhaengigheder ind i en standardiseret enhed kaldet en container. En container er en isoleret, letvaegtproces, der deler vaertsmaskinens OS-kerne, men har sit eget filsystem, netvaerk og procesrum.
Containere vs Virtuelle Maskiner
| Aspekt | Containere | Virtuelle Maskiner |
|---|---|---|
| Opstart | Sekunder | Minutter |
| Storrelse | MB | GB |
| OS | Deler vaertskerne | Fuldt gaeste-OS |
| Isolering | Procesniveau | Hardwareniveau |
| Ydeevne | Naesten nativ | Overhead fra hypervisor |
| Taethed | Hundredvis per vaert | Tiere per vaert |
Installation af Docker
# macOS brew install --cask docker # Ubuntu/Debian curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER # Verify installation docker --version docker run hello-world
Kernebegreber
Images
Et image er en skrivebeskyttet skabelon med instruktioner til at oprette en container. Taenk pa det som et snapshot af din applikation og dens miljo.
# Pull an image from Docker Hub docker pull node:20-alpine # List local images docker images # Remove an image docker rmi node:20-alpine
Containere
En container er en korende instans af et image. Du kan oprette, starte, stoppe og slette containere.
# Run a container docker run -d --name my-app -p 3000:3000 node:20-alpine # List running containers docker ps # List all containers (including stopped) docker ps -a # Stop a container docker stop my-app # Remove a container docker rm my-app # View logs docker logs my-app # Execute a command inside a running container docker exec -it my-app sh
Skrivning af en Dockerfile
En Dockerfile er en tekstfil med instruktioner til at bygge et image. Hver instruktion opretter et lag.
Grundlaeggende Dockerfile til en Node.js App
# Use an official Node.js runtime as base image FROM node:20-alpine # Set working directory WORKDIR /app # Copy package files first (better caching) COPY package.json package-lock.json ./ # Install dependencies RUN npm ci --only=production # Copy application code COPY . . # Expose the port the app runs on EXPOSE 3000 # Command to run the application CMD ["node", "server.js"]
Byg og Kor
# Build the image docker build -t my-node-app . # Run the container docker run -d -p 3000:3000 my-node-app # Visit http://localhost:3000
Multi-Stage Builds
Multi-stage builds holder dine produktionsimages sma ved at adskille buildmiljoet fra runtime.
# Stage 1: Build FROM node:20-alpine AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build # Stage 2: Production FROM node:20-alpine AS runner WORKDIR /app COPY /app/dist ./dist COPY /app/node_modules ./node_modules COPY /app/package.json ./ EXPOSE 3000 CMD ["node", "dist/server.js"]
Dette producerer et image med kun den kompilerede output og produktionsafhaengigheder - ingen kildekode, ingen udviklingsafhaengigheder, ingen buildvaerktojer.
Next.js Multi-Stage Eksempel
FROM node:20-alpine AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci FROM node:20-alpine AS builder WORKDIR /app COPY /app/node_modules ./node_modules COPY . . RUN npm run build FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production COPY /app/public ./public COPY /app/.next/standalone ./ COPY /app/.next/static ./.next/static EXPOSE 3000 CMD ["node", "server.js"]
Volumes: Persistent Data
Som standard gar data inde i en container tabt, nar containeren fjernes. Volumes loser dette.
# Create a named volume docker volume create my-data # Run with a volume docker run -d -v my-data:/app/data my-app # Bind mount (map host directory to container) docker run -d -v $(pwd)/data:/app/data my-app # List volumes docker volume ls
Netvaerk
Docker opretter isolerede netvaerk, sa containere kan kommunikere.
# Create a custom network docker network create my-network # Run containers on the same network docker run -d --name api --network my-network my-api docker run -d --name db --network my-network postgres:16 # Containers can reach each other by name # From "api" container: postgres://db:5432
Docker Compose
Docker Compose lader dig definere og kore multi-container applikationer med en enkelt YAML-fil.
docker-compose.yml
services: api: build: ./api ports: - "3000:3000" environment: - DATABASE_URL=postgres://user:pass@db:5432/mydb depends_on: - db db: image: postgres:16-alpine environment: - POSTGRES_USER=user - POSTGRES_PASSWORD=pass - POSTGRES_DB=mydb volumes: - pgdata:/var/lib/postgresql/data ports: - "5432:5432" redis: image: redis:7-alpine ports: - "6379:6379" volumes: pgdata:
Kommandoer
# Start all services docker compose up -d # View logs docker compose logs -f # Stop all services docker compose down # Rebuild and restart docker compose up -d --build # Scale a service docker compose up -d --scale api=3
.dockerignore
Ligesom .gitignore forhindrer denne fil unoedvendige filer i at blive kopieret ind i imaget.
node_modules .git .env *.md .next dist coverage
Bedste Praksis for Produktion
1. Brug Sma Basisimages
# Bad: 1GB+ FROM node:20 # Good: ~180MB FROM node:20-alpine
2. Kor Ikke som Root
FROM node:20-alpine RUN addgroup -S app && adduser -S app -G app USER app WORKDIR /home/app COPY . .
3. Brug Specifikke Image Tags
# Bad: can change unexpectedly FROM node:latest # Good: pinned version FROM node:20.11-alpine3.19
4. Udnyt Build Cache
Ordne dine Dockerfile-instruktioner fra mindst til mest hyppigt aendret:
FROM node:20-alpine WORKDIR /app # These change rarely - cached COPY package.json package-lock.json ./ RUN npm ci --only=production # This changes often - not cached COPY . .
5. Sundhedstjek
HEALTHCHECK \ CMD wget -qO- http://localhost:3000/health || exit 1
6. Brug Miljovariabler
ENV NODE_ENV=production ENV PORT=3000
Snydeark for Almindelige Docker-Kommandoer
# Images docker build -t name:tag . # Build image docker images # List images docker rmi image_name # Remove image docker image prune # Remove unused images # Containers docker run -d -p 3000:3000 image # Run detached docker ps # List running docker stop container_name # Stop docker rm container_name # Remove docker logs -f container_name # Follow logs docker exec -it container sh # Shell into container # Compose docker compose up -d # Start services docker compose down # Stop services docker compose logs -f # Follow all logs docker compose ps # List services # Cleanup docker system prune -a # Remove everything unused
Fra Docker til Kubernetes
Docker handterer individuelle containere. Nar du skal orkestrere hundredvis af containere pa tvaers af flere servere, har du brug for Kubernetes. Docker og Kubernetes er komplementaere:
- Docker: bygger og korer containere
- Kubernetes: orkestrerer containere i stor skala (planlaegning, skalering, selvhelbredelse)
Hvis du er interesseret i naeste trin, kan du se min artikel om Introduktion til Kubernetes.
Konklusion
Docker er en grundlaeggende faerdighed for moderne udviklere. Det eliminerer miljoinkonsekvenser, forenkler deployment og er fundamentet for containerorkestrering med Kubernetes. Start med en simpel Dockerfile, ga videre til Docker Compose for multi-service apps, og adopter multi-stage builds og sikkerheds-bedste-praksis efterhanden som du vokser.
Den bedste made at laere Docker pa er at containerisere et projekt, du allerede arbejder pa. Start i dag.