Skip to content

Container Lifecycle CLI — run, stop, rm, ps, logs, exec

Thứ Sáu, 2 giờ sáng. Cảnh báo PagerDuty vang lên: "Payment Service — 502 Bad Gateway". Đội fintech của bạn đang xử lý 40,000 giao dịch/phút. Mỗi giây downtime là tiền thật mất đi. Bạn SSH vào production server, chạy docker ps — container payment-api biến mất khỏi danh sách. docker ps -a hiện nó ở trạng thái Exited (137). Bạn cần xem log, restart container, exec vào kiểm tra config — và bạn cần làm tất cả trong vòng 3 phút trước khi khách hàng bắt đầu gọi hotline.

Đây không phải kịch bản giả tưởng. Đây là thứ xảy ra hàng đêm ở các hệ thống production thực tế. Bài này trang bị cho bạn 6 lệnh Docker CLI cốt lõi để quản lý toàn bộ vòng đời container — từ khởi tạo đến dọn dẹp. Không chỉ cú pháp, mà hiểu tại sao mỗi lệnh hoạt động như vậy, để khi production cháy lúc 3 giờ sáng, bạn phản xạ được ngay.

🎯 Mục tiêu

  • Nắm vững state machine của container: Created → Running → Paused → Stopped → Removed — và lệnh nào chuyển giữa các trạng thái
  • Thành thạo docker run với các flag quan trọng: -d, --name, -p, -e, -v, --rm, -it
  • Dùng docker ps, docker logs, docker exec để giám sát và debug container đang chạy
  • Hiểu quy trình cleanup: docker stopdocker rmdocker system prune
  • Nắm cơ chế signal propagation bên dưới docker stop — tại sao SIGTERM trước, SIGKILL sau

Concept — Container States: Máy Trạng Thái

Trước khi gõ bất kỳ lệnh nào, bạn cần hình dung container như một finite state machine — mỗi container luôn ở đúng một trạng thái tại mỗi thời điểm, và chỉ có thể chuyển trạng thái thông qua các lệnh cụ thể.

                          docker unpause
                       ┌──────────────────┐
                       │                  │
                       ▼                  │
┌─────────┐  docker start  ┌─────────┐  docker pause  ┌──────────┐
│ Created │───────────────▶│ Running │────────────────▶│  Paused  │
└─────────┘                └─────────┘                 └──────────┘
     ▲                          │
     │                          │ docker stop / docker kill
     │                          ▼
     │                    ┌─────────┐   docker rm    ┌─────────┐
     │                    │ Stopped │───────────────▶│ Removed │
     │                    │(Exited) │                │  (Gone) │
     │                    └─────────┘                └─────────┘
     │                          │
     │      docker restart      │
     └──────────────────────────┘

 docker create → Created
 docker run    → Created + Started (2 bước gộp 1)
 docker rm -f  → Bất kỳ state nào → Removed (force)

Giải thích từng trạng thái

Trạng tháiÝ nghĩaLệnh vàoLệnh ra
CreatedContainer được tạo nhưng chưa chạy. Filesystem đã mount, config đã set.docker createdocker start, docker rm
RunningProcess chính (PID 1) đang chạy bên trong container.docker start, docker rundocker stop, docker pause, docker kill
PausedProcess bị đóng băng (SIGSTOP). Không tiêu thụ CPU nhưng vẫn giữ memory.docker pausedocker unpause
StoppedProcess chính đã exit. Container vẫn tồn tại trên disk (filesystem, logs).docker stop, crashdocker start, docker rm
RemovedContainer bị xóa hoàn toàn. Không thể recover.docker rm

⚠️ State "Stopped" ≠ "Removed"

Đây là nguồn gốc của 90% container zombie. Khi container stop, nó vẫn chiếm disk space — filesystem layer, logs, metadata đều còn nguyên. Chỉ docker rm mới giải phóng thực sự. Rất nhiều engineer mới nghĩ docker stop là xong — sai.


docker run — Con Dao Thụy Sĩ

docker run là lệnh bạn dùng nhiều nhất. Nó gộp docker create + docker start thành một bước, kèm theo hàng chục flag điều khiển hành vi container.

Chạy container ở chế độ detached (background)

bash
# Chạy nginx ở background, đặt tên "myapp", map port 8080 host → 80 container
docker run -d --name myapp -p 8080:80 nginx

# Phân tích từng flag:
# -d            → detached mode — container chạy nền, trả lại terminal cho bạn
# --name myapp  → đặt tên dễ nhớ thay vì ID ngẫu nhiên (ví dụ: a3f8c2b1d9e0)
# -p 8080:80    → host port 8080 → container port 80
# nginx         → image name (tự pull từ Docker Hub nếu chưa có local)

Sau khi chạy, bạn có thể truy cập http://localhost:8080 trên máy host để thấy trang chào Nginx.

Truyền biến môi trường và mount volume

bash
# Chạy PostgreSQL với env vars và volume
docker run -d \
  --name mydb \
  -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=supersecret \
  -e POSTGRES_DB=payments \
  -v pgdata:/var/lib/postgresql/data \
  -p 5432:5432 \
  postgres:16-alpine

# -e KEY=VALUE  → set biến môi trường bên trong container
# -v name:path  → mount named volume — dữ liệu persist ngay cả khi container bị rm

⚠️ Cạm bẫy

Lệnh docker run -e POSTGRES_PASSWORD=supersecret ở trên chỉ dùng cho dev/learning. Trong production, KHÔNG BAO GIỜ đặt password trực tiếp trong CLI — nó hiện rõ trong docker inspect, process list (ps aux), và shell history.

bash
# ❌ Sai — secret lộ trong process list và shell history
docker run -e DB_PASSWORD=MyS3cretP@ss myapp

# ✅ Đúng — dùng file hoặc Docker secrets
docker run --env-file .env myapp
# Hoặc với Docker Swarm:
echo "MyS3cretP@ss" | docker secret create db_password -

Auto-cleanup với --rm

bash
# Container tự xóa khi exit — hoàn hảo cho task ngắn
docker run --rm alpine echo "Hello from Alpine"
# Output: Hello from Alpine
# Container đã biến mất — docker ps -a sẽ không thấy nó

# Dùng --rm cho script chạy-một-lần
docker run --rm -v $(pwd):/app -w /app node:20-alpine npm test
# Chạy test rồi tự dọn — không tạo rác

Chế độ interactive — khi bạn cần shell

bash
# Mở shell Alpine interactive
docker run --rm -it alpine sh

# -i  → interactive — giữ STDIN mở (để bạn gõ lệnh)
# -t  → tty — cấp pseudo-terminal (để output có format, màu sắc)
# sh  → override CMD mặc định, chạy shell thay vì process chính của image

# Bên trong container:
/ # whoami
root
/ # cat /etc/os-release
NAME="Alpine Linux"
/ # exit
# → Container exit + tự xóa (nhờ --rm)

💡 Khi nào dùng -it vs -d?

  • -d (detached): Cho service chạy nền lâu dài — web server, database, message queue
  • -it (interactive): Cho debug, explore filesystem, chạy one-off command
  • --rm: Kết hợp với cả hai khi bạn không cần giữ container sau khi exit

Quy tắc nhớ: Service → -d. Debug → -it --rm.

Tổng hợp các flag quan trọng của docker run

FlagViết tắtÝ nghĩaVí dụ
--detach-dChạy nền-d
--nameĐặt tên container--name myapp
--publish-pMap port host:container-p 8080:80
--env-eSet biến môi trường-e NODE_ENV=production
--volume-vMount volume/bind mount-v data:/app/data
--rmTự xóa khi exit--rm
--interactive-iGiữ STDIN mở-i
--tty-tCấp pseudo-terminal-t
--memory-mGiới hạn RAM-m 512m
--cpusGiới hạn CPU--cpus 1.5
--restartChính sách restart--restart unless-stopped

docker ps — Giám Sát Container

docker ps là "đôi mắt" của bạn. Nó cho biết container nào đang chạy, port nào đang mở, và container đã chạy bao lâu.

Xem container đang chạy

bash
docker ps

# CONTAINER ID   IMAGE   COMMAND                  CREATED         STATUS         PORTS                  NAMES
# a3f8c2b1d9e0   nginx   "/docker-entrypoint.…"   5 minutes ago   Up 5 minutes   0.0.0.0:8080->80/tcp   myapp
# b7d2e4f6a8c1   postgres:16-alpine   "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   0.0.0.0:5432->5432/tcp   mydb

Xem TẤT CẢ container (kể cả đã stop)

bash
docker ps -a

# CONTAINER ID   IMAGE     STATUS                      NAMES
# a3f8c2b1d9e0   nginx     Up 5 minutes                myapp
# b7d2e4f6a8c1   postgres  Up 3 minutes                mydb
# c9e1f3a5b7d2   alpine    Exited (0) 10 minutes ago   focused_newton   ← container cũ chưa rm
# d1f3a5b7c9e2   redis     Exited (137) 2 hours ago    old_cache        ← bị kill (137 = SIGKILL)

Exit code giải mã:

  • 0 → exit bình thường (success)
  • 1 → lỗi application
  • 137 → bị SIGKILL (OOM killer hoặc docker kill)
  • 143 → nhận SIGTERM (từ docker stop) và exit gracefully

Format tùy chỉnh — output gọn gàng

bash
# Chỉ hiện tên, trạng thái, port
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

# NAMES     STATUS         PORTS
# myapp     Up 5 minutes   0.0.0.0:8080->80/tcp
# mydb      Up 3 minutes   0.0.0.0:5432->5432/tcp

# Xuất JSON — hữu ích cho scripting
docker ps --format json | jq '.Names'
# "myapp"
# "mydb"

# Lọc container theo trạng thái
docker ps -a --filter "status=exited"
# Chỉ hiện container đã stop — tiện cho cleanup

# Chỉ lấy container ID — pipe vào lệnh khác
docker ps -aq --filter "status=exited"
# c9e1f3a5b7d2
# d1f3a5b7c9e2

docker logs — Debug Bằng Mắt

Khi container gặp lỗi, docker logs là nơi đầu tiên bạn kiểm tra. Nó hiển thị mọi thứ mà process bên trong container ghi ra stdoutstderr.

Xem log cơ bản

bash
# Xem toàn bộ log của container
docker logs myapp

# Xem 100 dòng cuối — tránh bị ngập bởi hàng triệu dòng
docker logs --tail 100 myapp

Follow log real-time

bash
# Theo dõi log liên tục — giống tail -f
docker logs -f myapp

# 172.17.0.1 - - [15/Jan/2025:02:15:33 +0000] "GET / HTTP/1.1" 200 615
# 172.17.0.1 - - [15/Jan/2025:02:15:34 +0000] "GET /api/health HTTP/1.1" 200 2
# 172.17.0.1 - - [15/Jan/2025:02:15:35 +0000] "POST /api/payment HTTP/1.1" 500 89  ← BUG
# ^C để dừng

Lọc log theo thời gian

bash
# Xem log 5 phút gần nhất — critical khi debug incident
docker logs --since 5m myapp

# Xem log trong khoảng thời gian cụ thể
docker logs --since 2025-01-15T02:00:00 --until 2025-01-15T02:30:00 myapp

# Kết hợp: 50 dòng cuối + follow
docker logs --tail 50 -f myapp

Thêm timestamp vào log

bash
docker logs -t myapp

# 2025-01-15T02:15:33.000000000Z 172.17.0.1 - ... "GET / HTTP/1.1" 200
# 2025-01-15T02:15:35.000000000Z 172.17.0.1 - ... "POST /api/payment HTTP/1.1" 500

💡 Chiến thuật debug log trong production incident

Khi nhận alert lúc 2 giờ sáng, đây là quy trình 3 bước:

bash
# Bước 1: Xem container có đang chạy không
docker ps -a --filter name=payment-api

# Bước 2: Xem log 10 phút gần nhất với timestamp
docker logs --since 10m -t payment-api

# Bước 3: Tìm dòng lỗi cụ thể
docker logs --since 10m payment-api 2>&1 | grep -i "error\|fatal\|panic"

Mẹo: redirect 2>&1 vì nhiều app ghi lỗi ra stderr, nhưng grep mặc định chỉ đọc stdout.


docker exec — Đột Nhập Container Đang Chạy

docker exec cho phép bạn chạy lệnh bên trong một container đang Running. Đây là công cụ debug mạnh nhất khi bạn cần kiểm tra filesystem, network, hoặc config bên trong container.

Mở shell interactive

bash
# Mở shell bash/sh bên trong container đang chạy
docker exec -it myapp sh

# Bên trong container:
# ls /usr/share/nginx/html/
# index.html  50x.html
# cat /etc/nginx/nginx.conf | head -20
# exit

Chạy lệnh one-off (không cần shell)

bash
# Xem config nginx mà không cần mở shell
docker exec myapp cat /etc/nginx/nginx.conf

# Kiểm tra DNS resolution bên trong container
docker exec myapp nslookup google.com

# Kiểm tra biến môi trường
docker exec myapp env | grep -i postgres
# POSTGRES_USER=admin
# POSTGRES_DB=payments

# Kiểm tra process đang chạy bên trong container
docker exec myapp ps aux
# PID   USER     TIME  COMMAND
#   1   root     0:00  nginx: master process
#  29   nginx    0:00  nginx: worker process
#  30   nginx    0:00  nginx: worker process

Chạy lệnh với user khác

bash
# Exec với quyền root (khi container chạy với user khác)
docker exec -u root myapp apt-get update

# Exec với user cụ thể
docker exec -u www-data myapp whoami
# www-data

🔥 Anti-pattern: Dùng docker exec thay SSH trong production

Tuyệt đối không dùng docker exec như SSH replacement cho production workload.

bash
# ❌ Anti-pattern — thay đổi file trong container đang chạy
docker exec -it payment-api vi /app/config.json
# Hậu quả:
# 1. Thay đổi mất khi container restart (container là ephemeral)
# 2. Không có audit trail — ai sửa gì, lúc nào?
# 3. Tạo config drift — container A khác container B

# ✅ Đúng cách — build image mới với config đúng, deploy lại
# Sửa config trong source code → rebuild image → redeploy
docker build -t payment-api:v1.2.1 .
docker stop payment-api && docker rm payment-api
docker run -d --name payment-api payment-api:v1.2.1

Nguyên tắc vàng: Container là immutable. Mọi thay đổi phải đi qua image build pipeline. docker exec chỉ dùng để đọcdebug, không bao giờ để sửa.


docker stop / docker rm — Dọn Dẹp Có Trách Nhiệm

docker stop — Tắt container lịch sự

bash
# Gửi SIGTERM → chờ 10 giây → SIGKILL nếu chưa exit
docker stop myapp

# Tùy chỉnh thời gian chờ (ví dụ: 30 giây cho app cần flush data)
docker stop -t 30 myapp

# Stop nhiều container cùng lúc
docker stop myapp mydb redis_cache

docker rm — Xóa container

bash
# Xóa container đã stop
docker rm myapp

# ❌ Không xóa được container đang chạy
docker rm mydb
# Error: cannot remove running container — stop first

# Force remove — stop + rm trong 1 lệnh
docker rm -f mydb
# Container bị SIGKILL ngay lập tức — KHÔNG có grace period

# Xóa tất cả container đã stop
docker rm $(docker ps -aq --filter "status=exited")

⚠️ Cạm bẫy

Mỗi lần bạn docker run mà không có --rm, container sẽ ở lại sau khi exit. Sau vài tuần develop/test, bạn có hàng trăm container zombie:

bash
# Kiểm tra "thiệt hại"
docker ps -a | wc -l
# 347  ← 346 container zombie đang ngốn disk

# Mỗi container giữ lại: writable layer, logs, metadata
docker system df
# TYPE           TOTAL    ACTIVE   SIZE      RECLAIMABLE
# Containers     346      2        12.4GB    12.1GB (97%)   ← 12GB rác!
# Images         45       8        8.7GB     6.2GB (71%)

# Giải pháp nhanh: xóa tất cả container stopped
docker container prune
# WARNING! This will remove all stopped containers.
# Are you sure you want to continue? [y/N] y
# Deleted Containers:
# c9e1f3a5b7d2... d1f3a5b7c9e2... (344 containers deleted)
# Total reclaimed space: 12.1GB

Thói quen tốt: Luôn dùng --rm cho container tạm thời. Với service lâu dài, schedule cleanup hàng tuần.

docker system prune — Nút bấm hạt nhân

bash
# Xóa TẤT CẢ: stopped containers, unused networks, dangling images, build cache
docker system prune

# Thêm -a để xóa cả images không được container nào dùng
docker system prune -a

# Thêm --volumes để xóa cả volumes không dùng (CẨN THẬN — mất dữ liệu!)
docker system prune -a --volumes

🔥 docker system prune --volumes xóa cả dữ liệu!

Nếu bạn có named volume chứa database data mà không container nào đang mount, --volumes sẽ xóa sạch nó. Luôn kiểm tra docker volume ls trước khi prune.


🔥 Thực Chiến: Debug Payment Service Lúc 2 Giờ Sáng

🏦 Business Scenario — Fintech Production Incident

Bối cảnh

Đội fintech vận hành payment-api container xử lý thanh toán qua API gateway. Lúc 2:13 AM, Grafana alert: error rate tăng từ 0.1% lên 15%. Khách hàng chuyển tiền bị lỗi. SLA yêu cầu recovery trong 5 phút.

Quy trình debug thực tế

bash
# === PHÚT 1: Xác nhận tình trạng ===

# Container có đang chạy không?
docker ps --filter name=payment-api --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# NAMES         STATUS          PORTS
# payment-api   Up 3 days       0.0.0.0:8443->8443/tcp
# → Container vẫn chạy. Vấn đề ở bên trong.

# Resource usage — OOM?
docker stats payment-api --no-stream
# CONTAINER     CPU %   MEM USAGE / LIMIT   MEM %   NET I/O
# payment-api   89%     1.87GiB / 2GiB      93%     1.2GB / 890MB
# → Memory gần limit! Có thể memory leak.


# === PHÚT 2: Xem log tìm root cause ===

# Log 5 phút gần nhất, lọc error
docker logs --since 5m payment-api 2>&1 | grep -i "error\|exception\|fatal"
# 2025-01-15T02:10:12Z ERROR: Connection pool exhausted — max 20 connections reached
# 2025-01-15T02:10:15Z ERROR: Failed to acquire DB connection within 5s timeout
# 2025-01-15T02:11:33Z FATAL: java.lang.OutOfMemoryError: Java heap space
# → Root cause: DB connection pool exhausted → memory leak từ connection chưa release


# === PHÚT 3: Exec vào kiểm tra chi tiết ===

# Kiểm tra connection pool metrics
docker exec payment-api curl -s localhost:8080/actuator/health | jq .
# {
#   "status": "DOWN",
#   "components": {
#     "db": { "status": "DOWN", "details": { "error": "Connection pool exhausted" } }
#   }
# }

# Kiểm tra số connection thực tế
docker exec payment-api sh -c "ss -tn | grep 5432 | wc -l"
# 20  ← Max pool size reached, tất cả bị giữ

# Xem heap memory
docker exec payment-api jcmd 1 VM.native_memory summary


# === PHÚT 4: Khắc phục tạm thời ===

# Restart container để giải phóng connection pool
docker restart payment-api

# Verify recovery
sleep 10
docker logs --tail 5 payment-api
# 2025-01-15T02:17:45Z INFO: Application started on port 8443
# 2025-01-15T02:17:46Z INFO: DB connection pool initialized: 5/20

docker exec payment-api curl -s localhost:8080/actuator/health | jq .status
# "UP"


# === SAU INCIDENT: Tạo ticket fix connection leak ===
# Root cause: missing connection.close() trong payment transaction handler
# Long-term fix: code review + add connection timeout + monitoring alert

Bài học rút ra

  1. docker stats là thứ đầu tiên kiểm tra — memory/CPU anomaly cho manh mối ngay
  2. docker logs --since + grep lọc nhanh root cause từ hàng triệu dòng log
  3. docker exec + health endpoint xác nhận component nào fail
  4. docker restart là bandage tạm thời — luôn tìm và fix root cause sau incident

🧩 Bài Tập Parsons: Sắp Xếp Lệnh Debug

Bạn nhận alert: container order-service trả HTTP 500. Sắp xếp các lệnh sau theo đúng thứ tự để debug và khắc phục:

A. docker exec order-service curl -s localhost:8080/health
B. docker logs --since 5m order-service 2>&1 | grep -i error
C. docker ps -a --filter name=order-service
D. docker restart order-service
E. docker stats order-service --no-stream
F. docker logs --tail 5 order-service
💡 Đáp án đúng

C → E → B → A → D → F

  1. Cdocker ps -a — Xác nhận container có tồn tại và đang ở trạng thái nào
  2. Edocker stats — Kiểm tra resource usage (CPU, memory) để phát hiện anomaly
  3. Bdocker logs --since 5m | grep error — Tìm root cause trong log gần đây
  4. Adocker exec curl health — Kiểm tra health endpoint từ bên trong container
  5. Ddocker restart — Khắc phục tạm thời sau khi đã hiểu nguyên nhân
  6. Fdocker logs --tail 5 — Xác nhận container đã restart thành công

Nguyên tắc: Quan sát trước → Chẩn đoán → Hành động → Xác nhận.


Under the Hood — Signal Propagation: Tại Sao docker stop Gửi SIGTERM Trước?

Khi bạn chạy docker stop myapp, Docker không kill container ngay lập tức. Quy trình bên dưới phức tạp hơn bạn tưởng — và hiểu nó là sự khác biệt giữa graceful shutdown và data corruption.

Quy trình chi tiết

Bạn gõ: docker stop myapp


┌─────────────────────────────────┐
│  Docker Daemon nhận request     │
│  Gửi SIGTERM (signal 15)       │──────────▶  PID 1 trong container
│  đến PID 1 của container       │             (process chính)
└─────────────────────────────────┘
         │                                           │
         │  Bắt đầu đếm ngược                       │
         │  (mặc định: 10 giây)                      ▼
         │                              ┌──────────────────────────┐
         │                              │  App nhận SIGTERM:       │
         │                              │  - Flush buffer/cache    │
         │                              │  - Close DB connections  │
         │                              │  - Finish pending request│
         │                              │  - Write final log       │
         │                              │  - Exit với code 0       │
         │                              └──────────────────────────┘

         │  Nếu hết 10 giây mà PID 1 chưa exit...

┌─────────────────────────────────┐
│  Docker Daemon gửi SIGKILL     │──────────▶  Process bị kernel hủy
│  (signal 9) — KHÔNG THỂ BẮT   │             ngay lập tức. Không cleanup.
│  KHÔNG THỂ BỎ QUA              │             Exit code: 137
└─────────────────────────────────┘

Tại sao điều này quan trọng?

Nếu app không handle SIGTERM, nó sẽ bị SIGKILL sau 10 giây — nghĩa là:

  • Database transaction đang dở → có thể corrupt data
  • File đang ghi → file bị truncate
  • HTTP request đang xử lý → client nhận connection reset
  • Message queue → message bị mất, không ack

Ví dụ: App Node.js handle SIGTERM đúng cách

javascript
const http = require('http');
const server = http.createServer(handler);
const db = require('./database');

// Graceful shutdown handler
process.on('SIGTERM', async () => {
  console.log('SIGTERM received. Starting graceful shutdown...');

  // 1. Ngừng nhận connection mới
  server.close(() => {
    console.log('HTTP server closed. No new connections.');
  });

  // 2. Chờ request đang xử lý hoàn thành (tối đa 8 giây)
  await Promise.race([
    waitForPendingRequests(),
    new Promise(resolve => setTimeout(resolve, 8000))
  ]);

  // 3. Đóng database connection pool
  await db.pool.end();
  console.log('Database connections closed.');

  // 4. Exit sạch
  process.exit(0);
});

server.listen(8080);

💡 Liên kết Linux Phase 1

Cơ chế signal (SIGTERM, SIGKILL, SIGHUP) được giải thích chi tiết trong bài Process Management & Signals. Docker container thực chất là Linux process — nên mọi kiến thức về signal trong Linux đều áp dụng trực tiếp cho container.

Điểm khác biệt duy nhất: PID 1 trong container không có signal handler mặc định của init system. Nếu app chạy với PID 1 mà không handle SIGTERM → signal bị bỏ qua (không phải default behavior "terminate"). Đây là lý do nhiều production container dùng tini hoặc dumb-init làm PID 1 wrapper.

dockerfile
# ✅ Dùng tini làm init process — forward signal đúng cách
FROM node:20-alpine
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]

So sánh docker stop vs docker kill

Hành vidocker stopdocker kill
Signal gửi đầu tiênSIGTERM (15)SIGKILL (9) mặc định
Grace period10s (tuỳ chỉnh -t)Không có
App có cơ hội cleanup?✅ Có❌ Không
Exit code143 (SIGTERM) hoặc 0137 (SIGKILL)
Khi nào dùng?Mặc định — luôn dùngChỉ khi container bị treo, không phản hồi SIGTERM

🏎️ Performance: docker stats và Resource Limits

💡 Giám sát resource real-time với docker stats

bash
# Real-time resource monitoring — giống top nhưng cho container
docker stats

# CONTAINER     CPU %   MEM USAGE / LIMIT     MEM %   NET I/O          BLOCK I/O
# payment-api   2.3%    256MiB / 2GiB         12.5%   1.2GB / 890MB    45MB / 12MB
# mydb          1.1%    512MiB / 1GiB         50.0%   230MB / 180MB    1.2GB / 890MB
# redis_cache   0.1%    28MiB / 256MiB        10.9%   45MB / 38MB      0B / 0B

# Snapshot một lần (không stream)
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

Luôn set resource limits khi chạy container trong production — ngăn một container "ăn hết" tài nguyên server:

bash
# Giới hạn 512MB RAM và 1.5 CPU cores
docker run -d --name myapp \
  --memory 512m \
  --cpus 1.5 \
  --restart unless-stopped \
  myapp:latest

# Nếu container vượt memory limit → OOM killer → exit code 137
# Nếu container vượt CPU limit → bị throttle (chậm lại, không bị kill)

📋 Tổng Hợp: Cheatsheet Docker Container Lifecycle

bash
# ─── KHỞI TẠO ───
docker run -d --name app -p 8080:80 nginx     # Chạy nền
docker run --rm -it alpine sh                   # Interactive + tự dọn
docker run -d -e KEY=val -v data:/app app:v1   # Với env + volume

# ─── GIÁM SÁT ───
docker ps                                       # Container đang chạy
docker ps -a                                    # Tất cả container
docker stats                                    # Resource real-time
docker logs --tail 100 -f app                   # Log gần + follow

# ─── DEBUG ───
docker exec -it app sh                          # Shell vào container
docker exec app cat /etc/config.yml             # Đọc file config
docker logs --since 5m app 2>&1 | grep error   # Lọc lỗi

# ─── DỌN DẸP ───
docker stop app                                 # SIGTERM → chờ → SIGKILL
docker rm app                                   # Xóa container stopped
docker rm -f app                                # Force kill + xóa
docker container prune                          # Xóa mọi container stopped
docker system prune -a                          # Xóa TOÀN BỘ rác

Checklist Hoàn Thành

::: success ✅ Bạn đã nắm vững bài này khi:

  • [ ] Vẽ được state machine của container (5 trạng thái) mà không nhìn tài liệu
  • [ ] Chạy được container detached với port mapping, env vars, và volume
  • [ ] Dùng docker ps -a + docker logs --since + docker exec để debug container có vấn đề
  • [ ] Giải thích được tại sao docker stop gửi SIGTERM trước SIGKILL
  • [ ] Biết khi nào dùng --rm và tại sao quên nó gây tích tụ container zombie
  • [ ] Đã thực hành ít nhất một lần: chạy nginx → xem logs → exec vào → stop → rm

:::


Quiz: Kiểm Tra Kiến Thức

❓ Câu 1: Exit code 137 nghĩa là gì?

A. Container exit bình thường B. Container bị SIGTERM và exit gracefully C. Container bị SIGKILL (128 + 9 = 137) D. Container gặp lỗi permission denied

Đáp án: C — 137 = 128 + signal number 9 (SIGKILL). Container bị kernel hủy cưỡng bức, thường do OOM killer hoặc docker kill.

❓ Câu 2: docker stop gửi signal nào trước?

A. SIGKILL rồi SIGTERM B. SIGTERM rồi chờ 10 giây rồi SIGKILL C. SIGHUP rồi SIGTERM D. SIGINT rồi SIGKILL

Đáp án: Bdocker stop luôn gửi SIGTERM trước, chờ grace period (mặc định 10s), rồi mới SIGKILL nếu process chưa exit.

❓ Câu 3: Lệnh nào giúp bạn xem log 5 phút gần nhất?

A. docker logs --last 5m myappB. docker logs --since 5m myappC. docker logs --time 5m myappD. docker logs --recent 5m myapp

Đáp án: B--since nhận relative time (5m, 1h, 30s) hoặc absolute timestamp.

❓ Câu 4: Tại sao KHÔNG nên dùng docker exec để sửa file trong production container?

A. Vì docker exec chạy chậm B. Vì thay đổi sẽ mất khi container restart, không có audit trail, gây config drift C. Vì docker exec không có quyền root D. Vì docker exec chỉ hoạt động trên Linux

Đáp án: B — Container là ephemeral (tạm thời). Mọi thay đổi bên trong phải đi qua image build pipeline để đảm bảo reproducibility và traceability.