Chuyển tới nội dung chính

Docker cơ bản — Container hóa ứng dụng

Docker giải quyết vấn đề gì?

Câu chuyện quen thuộc trong mọi dự án:

"Trên máy tôi chạy được mà!"

Docker đóng gói ứng dụng cùng toàn bộ dependencies vào một container — chạy giống nhau trên mọi máy.


Các khái niệm cốt lõi

Khái niệmTương tựMô tả
DockerfileCông thức nấu ănHướng dẫn từng bước tạo Image
ImageClass trong OOPBản thiết kế, bất biến, dùng lại được
ContainerObject (instance)Image đang chạy, có thể tạo nhiều cái
Registrynpm / App StoreKho lưu và chia sẻ Image
VolumeỔ đĩa gắn ngoàiLưu dữ liệu bền vững ngoài container

Cài đặt và lệnh cơ bản

Kiểm tra cài đặt

docker --version
docker compose version

# Chạy container test
docker run hello-world

Làm việc với Image

# Tải image từ Docker Hub
docker pull node:18-alpine
docker pull nginx:latest

# Xem image đã có trên máy
docker images

# Xóa image
docker rmi node:18-alpine

# Tìm kiếm image
docker search nginx

Làm việc với Container

# Chạy container (tải image nếu chưa có)
docker run nginx

# Chạy ngầm (detached mode)
docker run -d nginx

# Chạy với đặt tên
docker run -d --name my-nginx nginx

# Chạy với map port: máy_host:container
docker run -d -p 8080:80 --name my-nginx nginx
# → Truy cập http://localhost:8080

# Xem container đang chạy
docker ps

# Xem tất cả container (kể cả đã dừng)
docker ps -a

# Dừng container
docker stop my-nginx

# Xóa container
docker rm my-nginx

# Xem log
docker logs my-nginx
docker logs -f my-nginx # follow log real-time

# Vào bên trong container
docker exec -it my-nginx bash
docker exec -it my-nginx sh # Nếu không có bash

Viết Dockerfile

Cấu trúc cơ bản

# 1. Base image
FROM node:18-alpine

# 2. Thư mục làm việc trong container
WORKDIR /app

# 3. Copy file package trước (tận dụng cache layer)
COPY package*.json ./

# 4. Cài dependencies
RUN npm install --production

# 5. Copy toàn bộ source code
COPY . .

# 6. Build (nếu cần)
RUN npm run build

# 7. Khai báo port container sẽ lắng nghe
EXPOSE 3000

# 8. Lệnh chạy khi container khởi động
CMD ["node", "src/index.js"]

Bài toán thực tế: Dockerize ứng dụng Node.js + React

Giả sử bạn có dự án:

my-app/
backend/ ← Node.js API
frontend/ ← React app
docker-compose.yml

Dockerfile cho Backend:

FROM node:18-alpine

WORKDIR /app

# Tách riêng bước install để tận dụng Docker cache layer
# → Chỉ re-install khi package.json thay đổi
COPY package*.json ./
RUN npm install --production

COPY . .

EXPOSE 4000
CMD ["node", "server.js"]

Dockerfile cho Frontend:

# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 2: Serve (image nhỏ hơn nhiều)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Multi-stage Build

Kỹ thuật dùng nhiều FROM — build ở stage 1 (image lớn, nhiều tool), copy artifact sang stage 2 (image nhỏ, chỉ có runtime). Image cuối có thể nhỏ hơn 10 lần.

.dockerignore

Tương tự .gitignore — tránh copy file thừa vào image:

node_modules
.git
.env
*.log
dist
coverage

Volume — Lưu dữ liệu bền vững

Container bị xóa thì dữ liệu bên trong mất theo. Volume giải quyết vấn đề này.

# Tạo volume
docker volume create mydb-data

# Chạy container với volume
docker run -d \
--name mongodb \
-v mydb-data:/data/db \
-p 27017:27017 \
mongo:6

# Xem danh sách volume
docker volume ls

# Xóa volume
docker volume rm mydb-data

# Mount thư mục máy host (bind mount) — dùng khi dev
docker run -d \
-v $(pwd)/src:/app/src \ # thay đổi code → tự reload
-p 3000:3000 \
my-app

Docker Compose — Quản lý nhiều container

Thay vì gõ lệnh docker run dài dòng cho từng service, Docker Compose dùng file YAML.

docker-compose.yml:

version: '3.8'

services:
# MongoDB
mongodb:
image: mongo:6
container_name: app-mongodb
restart: unless-stopped
volumes:
- mongodb-data:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secret
ports:
- "27017:27017"

# Backend API
backend:
build: ./backend # Build từ Dockerfile trong ./backend
container_name: app-backend
restart: unless-stopped
depends_on:
- mongodb # Đợi mongodb khởi động trước
environment:
NODE_ENV: production
MONGO_URI: mongodb://admin:secret@mongodb:27017/myapp
ports:
- "4000:4000"

# Frontend
frontend:
build: ./frontend
container_name: app-frontend
restart: unless-stopped
depends_on:
- backend
ports:
- "80:80"

volumes:
mongodb-data: # Khai báo volume dùng chung

Các lệnh Docker Compose hay dùng

# Khởi động tất cả service (build nếu chưa có image)
docker compose up -d

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

# Xem log tất cả service
docker compose logs -f

# Xem log 1 service cụ thể
docker compose logs -f backend

# Dừng tất cả
docker compose down

# Dừng và xóa luôn volume (⚠️ mất data)
docker compose down -v

# Restart 1 service
docker compose restart backend

# Vào shell trong service
docker compose exec backend sh

# Xem trạng thái các service
docker compose ps

Workflow phát triển với Docker


Cheat sheet nhanh

Việc cần làmLệnh
Chạy containerdocker run -d -p 8080:80 nginx
Xem container đang chạydocker ps
Xem logdocker logs -f <tên>
Vào trong containerdocker exec -it <tên> sh
Dừng containerdocker stop <tên>
Xóa containerdocker rm <tên>
Build imagedocker build -t my-app .
Xem imagedocker images
Khởi động Composedocker compose up -d
Dừng Composedocker compose down
Dọn rác (image cũ)docker system prune