Το Docker αλλαξε τον τροπο που χτιζουμε, διανεμουμε και τρεχουμε λογισμικο. Αντι για "δουλευει στο μηχανημα μου", το Docker εγγυαται οτι η εφαρμογη σας τρεχει με τον ιδιο τροπο παντου - στο laptop σας, στο μηχανημα ενος συναδελφου, στο CI/CD και στην παραγωγη. Σε αυτον τον οδηγο, θα παμε απο το μηδεν εως το deploy μιας πραγματικης εφαρμογης.
Τι ειναι το Docker;
Το Docker ειναι μια πλατφορμα που πακεταρει την εφαρμογη σας και ολες τις εξαρτησεις της σε μια τυποποιημενη μοναδα που ονομαζεται container. Ενα container ειναι μια απομονωμενη, ελαφρια διεργασια που μοιραζεται τον πυρηνα του λειτουργικου συστηματος του host αλλα εχει το δικο της συστημα αρχειων, δικτυο και χωρο διεργασιων.
Containers vs Εικονικες Μηχανες
| Πτυχη | Containers | Εικονικες Μηχανες |
|---|---|---|
| Εκκινηση | Δευτερολεπτα | Λεπτα |
| Μεγεθος | MB | GB |
| ΛΣ | Μοιραζεται τον πυρηνα του host | Πληρες guest ΛΣ |
| Απομονωση | Επιπεδο διεργασιας | Επιπεδο υλικου |
| Αποδοση | Σχεδον native | Επιβαρυνση απο hypervisor |
| Πυκνοτητα | Εκατονταδες ανα host | Δεκαδες ανα host |
Εγκατασταση 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
Βασικες Εννοιες
Images
Ενα image ειναι ενα template μονο για αναγνωση με οδηγιες για τη δημιουργια ενος container. Σκεφτειτε το ως ενα στιγμιοτυπο της εφαρμογης σας και του περιβαλλοντος της.
# Pull an image from Docker Hub docker pull node:20-alpine # List local images docker images # Remove an image docker rmi node:20-alpine
Containers
Ενα container ειναι ενα τρεχον στιγμιοτυπο ενος image. Μπορειτε να δημιουργησετε, ξεκινησετε, σταματησετε και διαγραψετε containers.
# 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
Γραφοντας ενα Dockerfile
Ενα Dockerfile ειναι ενα αρχειο κειμενου με οδηγιες για τη δημιουργια ενος image. Καθε οδηγια δημιουργει ενα layer.
Βασικο Dockerfile για μια Node.js Εφαρμογη
# 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"]
Build και Εκτελεση
# 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 κρατουν τα production images μικρα διαχωριζοντας το περιβαλλον build απο το 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"]
Αυτο παραγει ενα image μονο με το compiled output και τις production εξαρτησεις - χωρις πηγαιο κωδικα, χωρις εξαρτησεις αναπτυξης, χωρις εργαλεια build.
Next.js Multi-Stage Παραδειγμα
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: Μονιμα Δεδομενα
Απο προεπιλογη, τα δεδομενα μεσα σε ενα container χανονται οταν το container αφαιρεθει. Τα volumes λυνουν αυτο το προβλημα.
# 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
Δικτυωση
Το Docker δημιουργει απομονωμενα δικτυα για την επικοινωνια των containers.
# 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 σας επιτρεπει να οριζετε και να τρεχετε εφαρμογες πολλαπλων containers με ενα μονο αρχειο YAML.
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:
Εντολες
# 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
Οπως το .gitignore, αυτο το αρχειο εμποδιζει τα περιττα αρχεια απο το να αντιγραφουν στο image.
node_modules .git .env *.md .next dist coverage
Βελτιστες Πρακτικες Παραγωγης
1. Χρησιμοποιηστε Μικρα Base Images
# Bad: 1GB+ FROM node:20 # Good: ~180MB FROM node:20-alpine
2. Μην Τρεχετε ως Root
FROM node:20-alpine RUN addgroup -S app && adduser -S app -G app USER app WORKDIR /home/app COPY . .
3. Χρησιμοποιηστε Συγκεκριμενα Image Tags
# Bad: can change unexpectedly FROM node:latest # Good: pinned version FROM node:20.11-alpine3.19
4. Αξιοποιηστε το Build Cache
Ταξινομηστε τις οδηγιες του Dockerfile απο τις λιγοτερο εως τις περισσοτερο συχνα τροποποιουμενες:
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. Ελεγχοι Υγειας
HEALTHCHECK \ CMD wget -qO- http://localhost:3000/health || exit 1
6. Χρησιμοποιηστε Μεταβλητες Περιβαλλοντος
ENV NODE_ENV=production ENV PORT=3000
Συνοπτικος Οδηγος Κοινων Εντολων Docker
# 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
Απο το Docker στο Kubernetes
Το Docker διαχειριζεται μεμονωμενα containers. Οταν χρειαζεται να ενορχηστρωσετε εκατονταδες containers σε πολλαπλους servers, χρειαζεστε Kubernetes. Docker και Kubernetes ειναι συμπληρωματικα:
- Docker: χτιζει και τρεχει containers
- Kubernetes: ενορχηστρωνει containers σε κλιμακα (προγραμματισμος, κλιμακωση, αυτο-ιαση)
Αν ενδιαφερεστε για το επομενο βημα, δειτε το αρθρο μου για την Εισαγωγη στο Kubernetes.
Συμπερασμα
Το Docker ειναι μια θεμελιωδης δεξιοτητα για τους συγχρονους προγραμματιστες. Εξαλειφει τις ασυνεπειες περιβαλλοντος, απλοποιει το deployment και ειναι η βαση για την ενορχηστρωση containers με Kubernetes. Ξεκινηστε με ενα απλο Dockerfile, μεταβειτε στο Docker Compose για εφαρμογες πολλαπλων υπηρεσιων και υιοθετηστε multi-stage builds και βελτιστες πρακτικες ασφαλειας καθως αναπτυσσεστε.
Ο καλυτερος τροπος να μαθετε Docker ειναι να containerize ενα εργο στο οποιο ηδη εργαζεστε. Ξεκινηστε σημερα.