Bài 04

Docker Compose: 1 file YAML, dựng full stack

13 tháng 5, 2026 · 120 phút đọc

Bài 04 — Docker Compose: 1 file YAML, dựng full stack

Đây là bài cuối cùng của chặng Docker. Bài 01-03 bạn đã có mọi mảnh ghép:

  • Container lifecycle (Bài 01)
  • Image & Dockerfile (Bài 02)
  • Network & Storage (Bài 03)

Giờ là lúc gắn tất cả lại. Vấn đề: app thực không chỉ 1 container. App thực = nhiều container chạy cùng nhau (web + database + cache + queue + ...). Quản lý 10 lệnh docker run mỗi lần deploy là kinh khủng.

Đây là lúc cần Docker Compose — orchestrate multi-container app qua 1 file YAML.

Mục tiêu bài này: dựng được full LEMP stack (nginx + PHP-FPM + MariaDB) qua 1 lệnh docker compose up. Đây là sản phẩm thật sự của chặng — gắn mọi kiến thức về 1 capstone.


Vấn đề: chạy nhiều container manual

Giả sử cần dựng stack có: 1 nginx + 1 PHP + 1 MariaDB + 1 Redis.

# 1. Tạo network
docker network create app-net

# 2. Tạo volumes
docker volume create db-data
docker volume create redis-data

# 3. Run MariaDB
docker run -d \
    --name mariadb \
    --network app-net \
    -e MYSQL_ROOT_PASSWORD=secret \
    -e MYSQL_DATABASE=app \
    -v db-data:/var/lib/mysql \
    --restart unless-stopped \
    mariadb:11

# 4. Run Redis
docker run -d \
    --name redis \
    --network app-net \
    -v redis-data:/data \
    --restart unless-stopped \
    redis:7-alpine

# 5. Build PHP image
docker build -t myapp-php ./php

# 6. Run PHP-FPM
docker run -d \
    --name php \
    --network app-net \
    -v $(pwd)/src:/var/www/html \
    --restart unless-stopped \
    myapp-php

# 7. Run nginx
docker run -d \
    --name nginx \
    --network app-net \
    -p 8080:80 \
    -v $(pwd)/nginx.conf:/etc/nginx/conf.d/default.conf \
    -v $(pwd)/src:/var/www/html \
    --restart unless-stopped \
    nginx:alpine

Vấn đề:

  • 7 lệnh dài — dễ gõ sai.
  • Thứ tự quan trọng — phải start MariaDB trước PHP. Sai thứ tự = lỗi.
  • Khó tái sử dụng — onboarding dev mới: gửi 7 lệnh? Họ copy sai 1 dấu.
  • Khó tear down — phải nhớ tên container, network, volume để xóa.
  • Không version control — config nằm trong shell history.

Đây là 4 container đơn giản. Production stack 10-20 container = không khả thi.


Docker Compose là gì

Docker Compose là tool orchestrate multi-container app, mô tả toàn hệ thống trong 1 file YAML.

"Mô tả lại toàn hệ thống trong 1 file" — chính là tinh thần của Compose.

   Manual (Bash):              Docker Compose:
   
   docker network create...    ┌────────────────────┐
   docker volume create...     │ docker-compose.yml │
   docker run -d --name...     │                    │
   docker run -d --name...     │ services:          │
   docker run -d --name...     │   nginx: ...       │
   docker build -t...          │   php: ...         │
   docker run -d --name...     │   mariadb: ...     │
   docker run -d --name...     │ volumes:           │
                                │   db-data:         │
   7 lệnh, dễ sai              │ networks:          │
                                │   app-net:         │
                                └─────────┬──────────┘
                                          │
                                          │ docker compose up
                                          ▼
                                  Mọi container UP
                                  Network + Volume tạo
                                  Đúng thứ tự
                                  1 LỆNH

3 lý do cần Compose

  1. Môi trường nhiều container — app modern ít khi 1 container, thường 3-20.
  2. Chuẩn hóa môi trườngcompose.yml commit git, ai pull về cũng dựng giống nhau.
  3. Mô tả toàn hệ thống trong 1 file — file vừa là code, vừa là documentation.

Compose vs Production Orchestration

⚠️ Quan trọng để biết:

            Docker Compose            Docker Swarm        Kubernetes
            ───────────────           ─────────────       ──────────
Scope:      1 host                    Cluster (multi)     Cluster (multi)
Quy mô:     Dev, small prod           Medium prod         Large prod
Học:        Dễ (1 ngày)               Trung bình          Khó (tháng)
File:       docker-compose.yml        docker stack.yml    YAML manifest
Use case:   Dev, CI/CD, local test    Small clusters      Production scale

Tài liu của bạn có ghi:
"Chủ yếu dùng trong test/dev. Môi trường prod thường dùng Stack, K8s"

Compose tốt cho: local dev, CI/CD pipeline, smoke test, demo, app nhỏ 1 server. Production thật quy mô lớn: Kubernetes.

Nhưng học Compose là bước đệm tốt để hiểu Kubernetes — concept service, network, volume tương tự.


Cài đặt Docker Compose

Docker Compose v2 đã tích hợp sẵn trong Docker CLI từ 2022 — không cần cài thêm:

docker compose version
# Docker Compose version v2.20.3

(Lưu ý syntax: docker compose — có space, không phải dash docker-compose. V1 dùng docker-compose, v2 dùng docker compose. V1 đã deprecated.)

Nếu chưa có:

# CentOS 9
sudo dnf install docker-compose-plugin

# Ubuntu
sudo apt install docker-compose-plugin

Cấu trúc file docker-compose.yml

File YAML mô tả toàn stack. 4 top-level keys chính:

version: "3.8"          # Compose file format version

services:               # Container services (web, db, ...)
  nginx:
    ...
  db:
    ...

volumes:                # Named volumes
  db-data:

networks:               # Custom networks
  app-net:
            docker-compose.yml
   ┌────────────────────────────────────────┐
   │ version: "3.8"                          │
   │                                          │
   │ ┌────────────────────────────────────┐  │
   │ │ services:    (các container)        │  │
   │ │ ┌─────────┐ ┌─────────┐ ┌────────┐ │  │
   │ │ │ nginx   │ │  php    │ │   db   │ │  │
   │ │ │         │ │         │ │        │ │  │
   │ │ │ image   │ │ build   │ │ image  │ │  │
   │ │ │ ports   │ │ volumes │ │ env    │ │  │
   │ │ │ volumes │ │ networks│ │ volumes│ │  │
   │ │ │ depends │ │         │ │ network│ │  │
   │ │ └────┬────┘ └────┬────┘ └────┬───┘ │  │
   │ └──────┼───────────┼───────────┼─────┘  │
   │        │           │           │         │
   │ ┌──────┴───────────┴───────────┴─────┐  │
   │ │ networks:                          │  │
   │ │   app-net:                          │  │
   │ └────────────────────────────────────┘  │
   │                                          │
   │ ┌──────────────────────────────────────┐│
   │ │ volumes:                              ││
   │ │   db-data:                            ││
   │ └──────────────────────────────────────┘│
   └────────────────────────────────────────┘

YAML cú pháp nhanh

key: value              # key-value
key:
  - item1               # list
  - item2

key:                    # nested object
  subkey: value
  another_key:
    deep_key: value

# Comment
key: "string with spaces"   # quote khi cần

⚠️ YAML rất nhạy với indentation. Dùng space, KHÔNG tab. Mọi level con thụt vào 2 space.


Compose Commands cơ bản

# Khởi động stack (đọc docker-compose.yml ở thư mục hiện tại)
docker compose up           # foreground, thấy log
docker compose up -d        # detach (background)

# Dừng và xóa
docker compose down         # giữ volume
docker compose down -v      # xóa cả volume (CẢNH BÁO: mất data)

# Dùng file khác
docker compose -f production.yml up -d

# Xem container đang chạy
docker compose ps

# Xem log
docker compose logs -f          # all services
docker compose logs -f nginx    # 1 service

# Restart 1 service
docker compose restart nginx

# Exec vào container
docker compose exec nginx bash

# Build lại image trước khi up
docker compose up -d --build

# Scale 1 service (chạy nhiều instance)
docker compose up -d --scale php=3

⚠️ Tài liệu của bạn ghi docker-compose downd — typo, đúng là docker compose down.


Service Definition chi tiết

Mỗi service là 1 container. Các thuộc tính phổ biến:

services:
  myservice:
    # ─── Source: từ image có sẵn HOẶC build từ Dockerfile ───
    image: nginx:1.25-alpine            # từ registry
    # HOẶC
    build:
      context: ./php                     # thư mục chứa Dockerfile
      dockerfile: Dockerfile             # tên file Dockerfile

    # ─── Container name (optional) ───
    container_name: myapp-nginx

    # ─── Port mapping ───
    ports:
      - "8080:80"                        # host:container
      - "443:443"

    # ─── Volumes ───
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf   # bind mount
      - db-data:/var/lib/mysql                         # named volume

    # ─── Environment variables ───
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - APP_ENV=production
    # HOẶC
    env_file:
      - .env

    # ─── Network ───
    networks:
      - app-net
      - public-net

    # ─── Dependencies ───
    depends_on:
      - db                                # start sau db
      - redis

    # ─── Restart policy ───
    restart: unless-stopped               # auto restart khi crash

    # ─── Healthcheck ───
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 3s
      retries: 3

    # ─── Resource limits ───
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 512M

    # ─── Override command ───
    command: ["nginx", "-g", "daemon off;"]

image vs build

# image: pull từ registry (Docker Hub, etc.)
image: mysql:8

# build: build từ Dockerfile local
build:
  context: ./backend       # folder có Dockerfile
  dockerfile: Dockerfile   # tên file (default "Dockerfile")

Image cho service standard (DB, cache). Build cho app code custom.

depends_on — thứ tự khởi động

services:
  nginx:
    depends_on:
      - php      # nginx start SAU php
      - db       # AND sau db

  php:
    depends_on:
      - db       # php start sau db
Start order:
  db ──► php ──► nginx
        ▲ ▲       ▲
        │ │       │
     "depends_on: db"
                  "depends_on: php"

⚠️ depends_on chỉ check container start, KHÔNG check app ready. Vd: MySQL container start lên nhưng MySQL daemon chưa initialize → PHP try connect fail.

Solution: dùng depends_on với condition:

depends_on:
  db:
    condition: service_healthy   # đợi healthcheck PASS

Hoặc app retry connection (production approach).

Restart policies

restart: "no"            # không tự restart (default)
restart: always          # luôn restart khi exit
restart: on-failure      # restart khi exit != 0
restart: unless-stopped  # restart trừ khi user stop (RECOMMEND)

Production hầu hết dùng unless-stopped — auto recover khi app crash, nhưng respect user stop.


DNS giữa Services — magic

Trong Compose, mỗi service name = DNS hostname. Không cần config gì thêm.

services:
  web:
    image: nginx
  db:
    image: mysql:8
  cache:
    image: redis
Containers tự thấy nhau qua tên service:
  web    → ping db       ✅ (resolve thành IP container db)
  web    → ping cache    ✅
  cache  → ping db       ✅

Trong app code (PHP, Node):
  $host = "db";   // dùng service name làm hostname
  $port = 3306;

→ Compose tự tạo network mặc định cho stack, mọi service connect vào, DNS work. Tương tự custom bridge từ Bài 03.


Variables với .env file

Tách secrets/config khỏi compose file — best practice.

Tạo file .env

# .env (cùng folder với docker-compose.yml)
MYSQL_ROOT_PASSWORD=supersecret
MYSQL_DATABASE=myapp
REDIS_PASSWORD=cache_pwd
APP_ENV=production

Reference trong compose

services:
  db:
    image: mysql:8
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}

Compose auto load .env khi run.

env_file — pass tất cả vars trong .env

services:
  app:
    image: myapp
    env_file:
      - .env             # mọi var trong .env có sẵn trong container

Best practice security

  • Commit .env.example (template, không có giá trị thật):
    MYSQL_ROOT_PASSWORD=
    MYSQL_DATABASE=
  • KHÔNG commit .env (có secret). Thêm .env vào .gitignore.
  • Production: dùng secret manager (Vault, AWS Secrets Manager), không phải .env.

🚀 Lab Capstone — Dựng full LEMP stack

Đây là product cuối cùng của chặng. Sau lab này bạn dựng được toàn bộ stack chặng 4 chỉ với 1 lệnh.

Cấu trúc thư mục

my-lemp-stack/
├── docker-compose.yml
├── .env
├── nginx/
│   └── default.conf
├── php/
│   └── Dockerfile
└── src/
    └── index.php

File 1: docker-compose.yml

version: "3.8"

services:
  nginx:
    image: nginx:1.25-alpine
    container_name: lemp-nginx
    ports:
      - "8080:80"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./src:/var/www/html
    depends_on:
      - php
    networks:
      - app-net
    restart: unless-stopped

  php:
    build:
      context: ./php
      dockerfile: Dockerfile
    container_name: lemp-php
    volumes:
      - ./src:/var/www/html
    depends_on:
      - db
    networks:
      - app-net
    restart: unless-stopped

  db:
    image: mariadb:11
    container_name: lemp-db
    environment:
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - app-net
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: lemp-redis
    volumes:
      - redis-data:/data
    networks:
      - app-net
    restart: unless-stopped

volumes:
  db-data:
  redis-data:

networks:
  app-net:
    driver: bridge

File 2: .env

# Database credentials
MYSQL_ROOT_PASSWORD=rootpass123
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=apppass123

File 3: nginx/default.conf

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;             # ← "php" là service name, DNS auto
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

File 4: php/Dockerfile

FROM php:8.2-fpm-alpine

# Cài extension cần thiết
RUN apk add --no-cache mariadb-client \
    && docker-php-ext-install pdo pdo_mysql mysqli

# Cài redis extension
RUN apk add --no-cache --virtual .build-deps autoconf gcc g++ make \
    && pecl install redis \
    && docker-php-ext-enable redis \
    && apk del .build-deps

WORKDIR /var/www/html

File 5: src/index.php

<?php
// Test connection tới các service trong stack

echo "<h1>LEMP Stack Test</h1>";

// 1. PHP version
echo "<p>PHP: " . phpversion() . "</p>";

// 2. MariaDB connection
try {
    $db = new PDO(
        "mysql:host=db;dbname=" . getenv("MYSQL_DATABASE"),
        getenv("MYSQL_USER"),
        getenv("MYSQL_PASSWORD")
    );
    echo "<p>✅ MariaDB: connected</p>";
} catch (PDOException $e) {
    echo "<p>❌ MariaDB: " . $e->getMessage() . "</p>";
}

// 3. Redis connection
try {
    $redis = new Redis();
    $redis->connect("redis", 6379);
    $redis->set("test", "OK");
    echo "<p>✅ Redis: " . $redis->get("test") . "</p>";
} catch (Exception $e) {
    echo "<p>❌ Redis: " . $e->getMessage() . "</p>";
}

⚠️ Pass DB credentials vào PHP container — cần thêm environment trong service php:

php:
  build: ...
  environment:
    - MYSQL_DATABASE=${MYSQL_DATABASE}
    - MYSQL_USER=${MYSQL_USER}
    - MYSQL_PASSWORD=${MYSQL_PASSWORD}

Chạy stack

cd my-lemp-stack

# 1 lệnh dựng cả stack
docker compose up -d

# Output:
# [+] Running 4/4
#  ✔ Network my-lemp-stack_app-net  Created
#  ✔ Container lemp-db              Started
#  ✔ Container lemp-redis           Started
#  ✔ Container lemp-php             Started
#  ✔ Container lemp-nginx           Started

# Kiểm tra:
docker compose ps
# NAME           IMAGE                STATUS         PORTS
# lemp-db        mariadb:11           Up 30 seconds  3306/tcp
# lemp-nginx     nginx:1.25-alpine    Up 25 seconds  0.0.0.0:8080->80/tcp
# lemp-php       my-lemp-stack-php    Up 25 seconds  9000/tcp
# lemp-redis     redis:7-alpine       Up 30 seconds  6379/tcp

# Test:
curl http://localhost:8080
# <h1>LEMP Stack Test</h1>
# <p>PHP: 8.2.x</p>
# <p>✅ MariaDB: connected</p>
# <p>✅ Redis: OK</p>

Toàn bộ LEMP stack lên trong 30 giây. So với chặng 4 cài bare-metal mất 12 tiếng. Magic của container.

Tear down

docker compose down                # giữ data
docker compose down -v             # xóa luôn volume (mất DB data)

Multi-environment Pattern

Production thực tế: dev và prod khác nhau. Compose hỗ trợ multiple files.

Pattern 1: Compose override

my-lemp-stack/
├── docker-compose.yml              # base
├── docker-compose.override.yml     # dev (auto-loaded)
└── docker-compose.prod.yml          # production

docker-compose.yml (base):

services:
  nginx:
    image: nginx:1.25-alpine
    ports:
      - "8080:80"

docker-compose.override.yml (dev — auto-loaded):

services:
  nginx:
    volumes:
      - ./src:/var/www/html      # bind mount dev
    environment:
      - DEBUG=true

docker-compose.prod.yml:

services:
  nginx:
    image: myrepo/nginx:v1.2.3   # image custom đã build
    restart: always
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G

Cách run

# Dev: auto merge base + override
docker compose up -d

# Production: explicit
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

1 codebase, nhiều môi trường. Dev pull code, docker compose up ngay. Prod pull image build sẵn.


Câu chuyện thực tế

Năm 2023, mình join 1 startup. Team có 6 dev. Mỗi dev mới onboard mất 2 ngày chỉ để setup local env:

  • Cài PHP 8.2 + extensions (3 tiếng, dễ sai version)
  • Cài MySQL 8 + tạo DB + user (1 tiếng)
  • Cài Redis (30 phút)
  • Setup nginx config (1 tiếng)
  • Fix permission các thư mục (1-2 tiếng)
  • Debug "trên máy chạy được" issues (vài tiếng)

6 dev × 2 ngày = 12 ngày-người chỉ để setup env. Chưa kể inconsistency — dev A có PHP 8.2.3, dev B có 8.2.5, gây bug khó debug.

Mình spend 1 ngày viết docker-compose.yml. Sau đó workflow onboard dev mới:

git clone repo.git
cd repo
cp .env.example .env
docker compose up -d
# 30 giây sau: env sẵn sàng

5 phút thay vì 2 ngày. 6 dev × 2 ngày → 6 dev × 5 phút = tiết kiệm 11.5 ngày-người onboard.

Bonus:

  • Mọi dev có env giống y hệt — không còn "trên máy chạy được".
  • Senior debug junior: pull code junior, docker compose up → reproduce ngay.
  • Switch project: docker compose downdocker compose up project khác. Không conflict port/version.

Bài học:

  1. Compose ROI cực cao. 1 ngày viết = tiết kiệm hàng tuần onboarding.

  2. Đầu tư setup chuẩn từ đầu project. Project thứ 2 trở đi: clone template, đổi tên service, xong.

  3. .env.example là phần documentation. Junior xem .env.example biết app cần config gì.

  4. docker-compose.yml là documentation thật. Quên app dùng port nào? Mở compose file ra xem.

  5. Tách dev vs prod compose. Production cần image build sẵn, không bind mount source code.

  6. Mock data trong init.sql. Mount SQL script vào MariaDB image — container tạo DB + data tự động lần đầu run.


Pitfalls

  1. YAML indent sai → parse error, không hiểu lỗi. Dùng 2 space, không tab. Editor có YAML lint là nice.

  2. depends_on không đợi app ready — chỉ đợi container start. App connect DB sớm → fail. Dùng healthcheck + service_healthy.

  3. Commit .env lên git → leak secrets. Add .env vào .gitignore. Chỉ commit .env.example.

  4. Quên define volume trong top-level volumes: → compose báo lỗi "volume not declared".

  5. Service tên có dấu gạch dưới _ → DNS resolve có thể fail trên 1 số config. Dùng - (hyphen).

  6. Hardcode port trong code thay vì DNS service name → khó migrate giữa env.

  7. docker compose down -v ngày production → mất toàn bộ volume. Cẩn thận -v flag.

  8. Compose file version cũ (2.x) → thiếu features mới. Dùng "3.8" hoặc bỏ version (v2+).

  9. Mount bind code trong production → security risk + slow filesystem. Production dùng image với code build vào.

  10. Quên restart: unless-stopped → container crash không tự lên. Production mọi service phải có restart policy.

  11. Logs không rotate → compose log mặc định ghi unlimited. Set log driver + rotation:

    services:
      web:
        logging:
          driver: "json-file"
          options:
            max-size: "10m"
            max-file: "3"
  12. Dùng docker-compose (V1) thay docker compose (V2) — V1 deprecated. Update lên V2.

  13. Container name conflict giữa nhiều stack — đặt prefix project name hoặc bỏ container_name.

  14. Healthcheck quá nghiêminterval: 1s → spam check, ngốn CPU. 30s là OK.


Tóm tắt

  • Docker Compose = orchestrate multi-container app qua 1 file YAML.
  • 3 lý do dùng: môi trường nhiều container, chuẩn hóa, mô tả toàn hệ thống trong 1 file.
  • Compose tốt cho dev/CI, production lớn dùng K8s.
  • 4 top-level keys: version, services, volumes, networks.
  • docker compose up -d = 1 lệnh dựng full stack. docker compose down = teardown.
  • Service definition: image/build, ports, volumes, environment, depends_on, networks, restart, healthcheck.
  • DNS auto giữa service qua service name (như custom bridge từ Bài 03).
  • .env file cho secrets/config. Không commit .env, chỉ .env.example.
  • depends_on chỉ check container start, không check app ready. Dùng healthcheck + condition.
  • Multi-environment: base file + override (dev/prod).
  • restart: unless-stopped cho mọi production service.
  • YAML rất nhạy indent — dùng space, không tab.

🎓 Kết thúc Chặng 6 — Container & Docker

Đi qua 4 bài:

  1. Bài 01 — Docker cơ bản: container vs VM, kiến trúc Docker, lifecycle, vào shell, monitor.
  2. Bài 02 — Image & Dockerfile: layers, registry, Dockerfile, 10 best practices tối ưu image.
  3. Bài 03 — Network & Storage: 5 network drivers, custom bridge + DNS, Volume/Bind/tmpfs, immutable infrastructure.
  4. Bài 04 — Docker Compose: orchestrate multi-container, full LEMP stack qua 1 file YAML.

Từ 1 lệnh docker run hello-worlddựng được full production-ready stack trong 30 giây.

Bạn đã sẵn sàng cho

  • Kubernetes (chặng tiếp): K8s là "Compose ở cluster scale". Service = service. Volume = PersistentVolume. Network = NetworkPolicy. Compose hiểu rồi K8s sẽ thấy quen.
  • CI/CD: build image trong pipeline (GitHub Actions, GitLab CI), push registry, deploy. Chặng tiếp.
  • Observability: Prometheus + Grafana scrape container metrics. Loki collect log. Cluster-ready monitoring.
  • Service Mesh (Istio, Linkerd): tách service-to-service traffic ra mesh layer. Cần K8s trước.
  • Microservices architecture: containerize từng service, mỗi service team riêng quản lý.

Lời khuyên đi tiếp

  1. Không vội học K8s. Compose hiểu vững → K8s 50% đã quen. Đừng skip.

  2. Containerize 1 project thật. Pick app cũ, dockerize end-to-end. Học từ pain thực.

  3. Cố tình break stack — stop 1 container, network die, volume corrupt. Học debug.

  4. Đọc Compose file open source. Awesome-compose repo có nhiều ví dụ production. Study how others do it.

  5. docker compose down -v không phải lỗi gõ — là feature reset stack. Nhưng đừng trong production.

  6. Multi-stage Dockerfile + multi-environment Compose = combo production-grade.

  7. Sau Docker là K8s, sau K8s là... infinity. Vẫn cần basics chắc. Đừng skip foundation.

Chặng tiếp theo là Kubernetes. Nếu hôm nay bạn dựng được LEMP stack qua 1 lệnh docker compose up — bạn đã có nền vững nhất.

Chúc bạn build được hệ thống mà junior mới vào, 5 phút là chạy được! 🚀

Minh Hưng

← Bài trước
Bài 03
Zalo tư vấn