Vad är Docker?
Docker är en plattform med öppen källkod för att köra applikationer i containrar. En container innehåller applikationen tillsammans med de beroenden den behöver, vilket gör att samma applikation kan köras på utvecklarens laptop, en stagingserver eller i produktion med ett mer konsekvent beteende.
Analogin som ofta används är fraktcontainern, och den håller ganska bra. Innehållet kan variera, men själva förpackningsformen är alltid densamma. I mjukvaruvärlden är grundtanken snarlik: applikationen paketeras på ett mer enhetligt sätt så att den blir enklare att flytta och köra.
Problemet Docker löser
"It Works on My Machine"
Innan Docker fanns var det klassiska problemet enkelt: applikationen körde felfritt på utvecklarens laptop, men krånglade så fort den flyttades till en server.
Några vanliga orsaker:
- Olika versioner av beroenden
- Miljökonfigurationen skiljde sig åt
- OS eller systembibliotek passade inte ihop
Docker hjälper genom att paketera applikationen tillsammans med de komponenter den behöver. Det betyder inte att alla problem försvinner, men skillnaderna mellan miljöer blir betydligt mindre.
Docker jämfört med virtuella maskiner
| Aspekt | Docker-container | Virtuell maskin | |-------|-----------------|-----------------| | Storlek | MB (megabyte) | GB (gigabyte) | | Uppstart | Sekunder | Minuter | | Prestanda | Nästan native | Märkbar overhead | | Isolering | Processnivå | Hårdvarunivå | | OS | Delar värdens kärna | Fullständigt OS per VM | | Resursanvändning | Effektiv | Tung |
Visualisering
Virtuell maskin:
┌─────────────────────────┐
│ App A │ App B │
├───────────┼─────────────┤
│ Guest OS │ Guest OS │
├───────────┴─────────────┤
│ Hypervisor │
├─────────────────────────┤
│ Host OS │
├─────────────────────────┤
│ Hardware │
└─────────────────────────┘
Docker:
┌─────────────────────────┐
│ App A │ App B │
├───────────┼─────────────┤
│ Container │ Container │
├───────────┴─────────────┤
│ Docker Engine │
├─────────────────────────┤
│ Host OS │
├─────────────────────────┤
│ Hardware │
└─────────────────────────┘
Viktiga Docker-koncept
1. Docker Image
En image är en skrivskyddad mall som innehåller instruktionerna för att skapa en container. Tänk på den som en "blueprint" eller ett "snapshot" av applikationen.
# Ladda ner image från Docker Hub
docker pull nginx:latest
docker pull node:18-alpine
docker pull postgres:15
2. Docker Container
En container är en körande instans av en image. En och samma image kan användas för att skapa många containrar.
# Kör en container från en image
docker run -d -p 8080:80 nginx:latest
# Lista körande containrar
docker ps
# Stoppa en container
docker stop <container_id>
3. Dockerfile
En instruktionsfil för att bygga en Docker-image. Ungefär som ett "recept" för att skapa en image.
# Exempel på Dockerfile för en Node.js-app
FROM node:18-alpine
# Sätt working directory
WORKDIR /app
# Kopiera package-filer
COPY package*.json ./
# Installera beroenden
RUN npm ci --production
# Kopiera källkod
COPY . .
# Exponera port
EXPOSE 3000
# Sätt miljö
ENV NODE_ENV=production
# Kommando som körs
CMD ["node", "server.js"]
4. Docker Compose
Ett verktyg för att definiera och köra applikationer med flera containrar.
# docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://db:5432/myapp
depends_on:
- db
- redis
db:
image: postgres:15
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
postgres_data:
# Starta alla tjänster
docker-compose up -d
# Stoppa alla tjänster
docker-compose down
Viktiga Docker-kommandon
Hantera images
# Lista images
docker images
# Bygg image från Dockerfile
docker build -t myapp:v1 .
# Tagga image
docker tag myapp:v1 username/myapp:v1
# Pusha till registry
docker push username/myapp:v1
# Ta bort image
docker rmi myapp:v1
Hantera containrar
# Kör container
docker run -d --name myapp -p 8080:3000 myapp:v1
# Kör med miljövariabler
docker run -d -e DATABASE_URL=postgres://... myapp:v1
# Kör med volymer
docker run -d -v /host/path:/container/path myapp:v1
# Kör ett kommando i en körande container
docker exec -it myapp /bin/sh
# Visa loggar
docker logs myapp
docker logs -f myapp # Följ loggarna
# Stoppa container
docker stop myapp
# Starta en stoppad container
docker start myapp
# Ta bort container
docker rm myapp
# Ta bort alla stoppade containrar
docker container prune
Systemkommandon
# Visa Docker-info
docker info
# Visa diskanvändning
docker system df
# Städa bort oanvända resurser
docker system prune -a
# Visa containrarnas resursanvändning
docker stats
Bästa praxis för Dockerfile
1. Använd officiella basimages
Mindre bra:
FROM ubuntu
RUN apt-get update && apt-get install -y nodejs
Bättre:
FROM node:18-alpine
2. Minimera antalet lager
Mindre effektivt:
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y curl
Mer effektivt:
RUN apt-get update && apt-get install -y \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
3. Flerstegsbyggen (multi-stage builds)
För att minska den slutliga image-storleken:
# Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
EXPOSE 3000
CMD ["node", "dist/server.js"]
4. .dockerignore-fil
Exkludera filer från byggkontexten:
# .dockerignore
node_modules
npm-debug.log
.git
.env
.DS_Store
dist
coverage
*.md
5. Säkerhetspraxis
# Kör inte som root
FROM node:18-alpine
# Skapa en icke-root-användare
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
COPY --chown=nodejs:nodejs . .
RUN npm ci --production
# Byt till icke-root-användaren
USER nodejs
EXPOSE 3000
CMD ["node", "server.js"]
Docker-nätverk
Bridge-nätverk (standard)
Containrar i samma nätverk kan kommunicera via namn.
# Skapa ett eget nätverk
docker network create mynetwork
# Kör containrar i samma nätverk
docker run -d --name db --network mynetwork postgres
docker run -d --name app --network mynetwork myapp
# App kan ansluta till db via: postgres://db:5432
Portmappning
# Mappa containerport till värdens port
docker run -p 8080:3000 myapp # host:container
# Flera portar
docker run -p 8080:3000 -p 8081:3001 myapp
# Alla portar
docker run -P myapp
Docker-volymer
För beständig datalagring:
Namngivna volymer
# Skapa volym
docker volume create mydata
# Använd volym
docker run -v mydata:/app/data myapp
# Lista volymer
docker volume ls
# Inspektera volym
docker volume inspect mydata
Bind mounts
Montera en katalog från värden i containern:
# Utveckling: live reload
docker run -v $(pwd):/app myapp
# Windows
docker run -v %cd%:/app myapp
Praktiska användningsfall
1. Utvecklingsmiljö
# docker-compose.dev.yml
version: '3.8'
services:
app:
build: .
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- NODE_ENV=development
command: npm run dev
2. Microservices-arkitektur
version: '3.8'
services:
frontend:
image: myapp/frontend
ports:
- "80:80"
api-gateway:
image: myapp/api-gateway
ports:
- "8080:8080"
user-service:
image: myapp/user-service
product-service:
image: myapp/product-service
order-service:
image: myapp/order-service
3. CI/CD-integration
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push myapp:${{ github.sha }}
Docker i produktion
Orkestreringsverktyg
För att hantera containrar i skala:
- Docker Swarm - Dockers inbyggda orkestrering
- Kubernetes - Det vanligaste valet för containerorkestrering
- AWS ECS - Amazons containertjänst
- Google Cloud Run - Serverlösa containrar
Health checks
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:3000/health || exit 1
Resursbegränsningar
# Begränsa minne och CPU
docker run -m 512m --cpus=1 myapp
Docker för utvecklare
Fördelar
- Mer konsekvent miljö - Dev, staging och produktion skiljer sig inte lika mycket åt
- Bättre isolerade projekt - Beroenden mellan projekt krockar inte lika lätt
- Snabbare setup - Nya projekt kan köras utan lång manuell installation
- Smidigare samarbete - Teamet använder en i stort sett likadan miljö
- Säkrare experiment - Enklare att prova databaser, meddelandekö eller andra tjänster
Utmaningar
- Kräver inlärning i början - Koncept som image, container, volym och nätverk tar tid att förstå
- Kräver lagringsutrymme - Images och volymer kan snabbt växa sig stora
- Viss overhead på Windows eller macOS - Vanligtvis via Docker Desktop
- Nätverksfelsökning kan kännas förvirrande - Särskilt i början
Tips för att komma igång med Docker
- Börja med en enda tjänst - Flytta inte hela systemet på en gång
- Använd officiella images - Säkrare att lära sig på, och dokumentationen brukar vara bättre
- Lär dig Docker Compose - Till stor hjälp när applikationen har flera tjänster
- Prova i ett projekt du redan känner till - Lättare att förstå hur beteendet ändras
- Följ communityn - Många vardagsproblem löses snabbare genom diskussioner med andra utvecklare
Alternativ till Docker
- Podman - Daemonless, rootless containrar
- LXC/LXD - Systemcontainrar
- rkt - Alternativ container-runtime (utfasad)
- containerd - Kärnan i container-runtimen (används av Docker internt)
Docker med smbCloud
smbCloud stödjer Docker-baserad deployment utan ett långdraget setup-flöde.
# smbCloud identifierar Dockerfile automatiskt
$ cat Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "start"]
$ git push smb main
# smbCloud bygger image och deployar automatiskt
Fördelar:
- Inget behov av att sätta upp ett eget Docker-registry för grundflödet
- Image kan byggas direkt från
Dockerfile - Containern kan skalas via plattformens funktioner
- Grundläggande övervakning finns redan på plats
Felsökning av vanliga problem
Container avslutas direkt
# Kontrollera loggar
docker logs <container_id>
# Kör interaktivt för att felsöka
docker run -it myapp /bin/sh
Porten används redan
# Hitta processen som använder porten
lsof -i :8080 # Mac/Linux
netstat -ano | findstr :8080 # Windows
# Döda processen eller använd en annan port
docker run -p 8081:3000 myapp
Diskutrymmet är slut
# Ta bort oanvända images
docker image prune -a
# Ta bort oanvända volymer
docker volume prune
# Städa allt
docker system prune -a --volumes
Slutsats
Docker hjälper utvecklare att köra applikationer i en mer konsekvent miljö. Därför används Docker ofta för utveckling, testning, CI/CD och ända fram till deployment.
Om du precis har börjat behöver du inte tänka på stora kluster eller komplexa arkitekturer direkt. Börja med en enda applikation, förstå Dockerfile, skilj på image och container, och prova sedan att köra flera tjänster med Compose. Efter det brukar de mer avancerade koncepten kännas betydligt mer begripliga.