Skip to content

Buổi 2: Docker Images & Dockerfile

🎯 Mục tiêu

  • Hiểu Docker Image là gì và cấu trúc layer
  • Biết cách pull, list, remove images
  • Viết Dockerfile cơ bản với các instructions chính
  • Build image từ Dockerfile
  • Push image lên Docker Hub

1. Docker Image là gì?

Định nghĩa

Docker Image là một template read-only chứa:

  • Hệ điều hành cơ sở (Ubuntu, Alpine, Debian...)
  • Runtime (Node.js, Python, Java...)
  • Thư viện & dependencies
  • Code ứng dụng
  • Cấu hình chạy

Image → là bản thiết kế (blueprint) Container → là instance đang chạy từ image đó

┌─────────────────────────────────────┐
│            Docker Image             │
│  (Read-only template)               │
│                                     │
│  ┌───────────────────────────────┐  │
│  │ Layer 4: COPY app code        │  │
│  ├───────────────────────────────┤  │
│  │ Layer 3: RUN npm install      │  │
│  ├───────────────────────────────┤  │
│  │ Layer 2: RUN apt-get update   │  │
│  ├───────────────────────────────┤  │
│  │ Layer 1: FROM node:20-alpine  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘
         │          │          │
         ▼          ▼          ▼
    Container A  Container B  Container C
    (writable)   (writable)   (writable)

Image layers – hệ thống lớp

Mỗi instruction trong Dockerfile tạo một layer. Docker cache các layer để tái sử dụng → build nhanh hơn.


2. Quản lý Images

Pull image từ Docker Hub

bash
# Pull image chính thức
$ docker pull nginx
$ docker pull node:20-alpine
$ docker pull python:3.12-slim

# Pull với tag cụ thể
$ docker pull ubuntu:22.04

# Pull từ registry khác
$ docker pull ghcr.io/owner/image:tag

Xem danh sách images

bash
$ docker images
REPOSITORY    TAG          IMAGE ID       CREATED        SIZE
nginx         latest       a6bd71f48f68   2 days ago     187MB
node          20-alpine    1a2b3c4d5e6f   1 week ago     130MB
python        3.12-slim    7a8b9c0d1e2f   3 days ago     52MB
ubuntu        22.04        4a5b6c7d8e9f   2 weeks ago    77MB

Xóa images

bash
# Xóa một image
$ docker rmi nginx

# Xóa image bằng ID
$ docker rmi a6bd71f48f68

# Xóa tất cả image không dùng
$ docker image prune -a

So sánh base images phổ biến

Base ImageDung lượngUse case
ubuntu:22.04~77MBFull OS, apt-get
debian:bookworm-slim~80MBStable, nhiều packages
alpine:3.19~7MBSiêu nhẹ, dùng apk
node:20~1GBFull Node.js + OS
node:20-alpine~130MBNode.js trên Alpine
node:20-slim~200MBNode.js minimal Debian
python:3.12~1GBFull Python + OS
python:3.12-slim~52MBPython minimal

💡 Khuyến nghị

Luôn dùng tag cụ thể (ví dụ node:20-alpine) thay vì latest để đảm bảo tính nhất quán.


3. Dockerfile – Tạo image riêng

Dockerfile là gì?

Dockerfile là file text chứa các instructions để Docker build ra một image.

Ví dụ: Node.js app đơn giản

Tạo cấu trúc project:

my-app/
├── Dockerfile
├── package.json
├── package-lock.json
└── server.js

server.js:

javascript
const http = require('http');
const PORT = 3000;

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from Docker! 🐳\n');
});

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Dockerfile:

dockerfile
# Bước 1: Chọn base image
FROM node:20-alpine

# Bước 2: Đặt thư mục làm việc trong container
WORKDIR /app

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

# Bước 4: Cài đặt dependencies
RUN npm install --production

# Bước 5: Copy toàn bộ code
COPY . .

# Bước 6: Khai báo port
EXPOSE 3000

# Bước 7: Lệnh chạy khi start container
CMD ["node", "server.js"]

4. Các Dockerfile Instructions quan trọng

InstructionÝ nghĩaVí dụ
FROMBase imageFROM node:20-alpine
WORKDIRThư mục làm việcWORKDIR /app
COPYCopy file từ host vào imageCOPY . .
ADDCopy + giải nén + URLADD archive.tar.gz /app
RUNChạy lệnh khi buildRUN npm install
CMDLệnh mặc định khi runCMD ["node", "app.js"]
ENTRYPOINTLệnh cố định khi runENTRYPOINT ["python"]
EXPOSEKhai báo portEXPOSE 3000
ENVBiến môi trườngENV NODE_ENV=production
ARGBiến lúc buildARG VERSION=1.0
LABELMetadata cho imageLABEL maintainer="dev"
USERChạy với user nàoUSER node

CMD vs ENTRYPOINT

dockerfile
# CMD – có thể bị override khi docker run
CMD ["node", "server.js"]
# docker run myapp            → chạy node server.js
# docker run myapp bash       → chạy bash (override CMD)

# ENTRYPOINT – không bị override
ENTRYPOINT ["node"]
CMD ["server.js"]
# docker run myapp            → chạy node server.js
# docker run myapp app.js     → chạy node app.js (CMD bị override)

COPY vs ADD

dockerfile
# COPY – chỉ copy file/thư mục (KHUYẾN NGHỊ)
COPY ./src /app/src
COPY package.json /app/

# ADD – copy + giải nén tự động + hỗ trợ URL
ADD archive.tar.gz /app/     # tự giải nén
ADD https://example.com/file /app/  # tải từ URL

⚠️ Lưu ý

Luôn dùng COPY trừ khi cần giải nén. ADD có hành vi phức tạp hơn và dễ gây nhầm lẫn.


5. Build Image

Lệnh docker build

bash
# Build image từ Dockerfile trong thư mục hiện tại
$ docker build -t my-node-app .

# Build với tag version
$ docker build -t my-node-app:1.0 .

# Build với build argument
$ docker build --build-arg VERSION=2.0 -t my-app:2.0 .

# Xem quá trình build chi tiết
$ docker build --progress=plain -t my-app .
FlagÝ nghĩa
-tTag – đặt tên:version cho image
.Build context – thư mục chứa Dockerfile
-fChỉ định Dockerfile khác tên mặc định
--no-cacheBuild không dùng cache
--build-argTruyền build argument

Ví dụ build và chạy

bash
# Build
$ docker build -t my-node-app:1.0 .

# Kiểm tra image
$ docker images | grep my-node-app
my-node-app   1.0   abc123def456   10 seconds ago   135MB

# Chạy container từ image
$ docker run -d -p 3000:3000 --name my-app my-node-app:1.0

# Kiểm tra
$ curl http://localhost:3000
Hello from Docker! 🐳

6. Ví dụ: Dockerfile cho Python

dockerfile
FROM python:3.12-slim

WORKDIR /app

# Copy requirements trước (tận dụng cache)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy code
COPY . .

EXPOSE 8000

CMD ["python", "app.py"]

7. Ví dụ: Dockerfile cho Go

dockerfile
FROM golang:1.22-alpine AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o main .

FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

🏋️ Bài tập thực hành

Bài 1: Pull và khám phá images

  1. Pull 3 images: nginx, node:20-alpine, python:3.12-slim
  2. So sánh dung lượng bằng docker images
  3. Kiểm tra chi tiết image: docker inspect node:20-alpine

Bài 2: Viết Dockerfile đầu tiên

  1. Tạo file server.js như ví dụ ở trên
  2. Viết Dockerfile cho Node.js app
  3. Build: docker build -t my-first-app .
  4. Chạy: docker run -d -p 3000:3000 my-first-app
  5. Mở http://localhost:3000 kiểm tra

Bài 3: Dockerfile cho static website

  1. Tạo file index.html đơn giản
  2. Viết Dockerfile dùng base nginx:alpine
  3. Copy index.html vào /usr/share/nginx/html/
  4. Build và chạy trên port 8080

Bài 4: Tag và quản lý images

  1. Build image với nhiều tags: myapp:1.0, myapp:latest
  2. Liệt kê tất cả images
  3. Xóa image cũ, giữ lại bản mới nhất
  4. Dọn dẹp: docker image prune