Trong quá trình vận hành hệ thống với Docker, đôi khi bạn sẽ gặp phải tình huống trớ trêu: một container (ví dụ như MySQL) không thể bị dừng hoặc xóa bỏ hoàn toàn. Dù bạn đã thử mọi lệnh từ
stop,
kill cho đến
rm -f, container đó vẫn ngay lập tức "hồi sinh".
Triệu chứng của vấn đề
Khi kiểm tra danh sách container bằng lệnh
docker ps, bạn thấy container vẫn đang chạy:
docker ps | grep mysql-server
# Kết quả: 7844250860f8 mysql:5.7 "..." 41 minutes ago Up 8 minutes mysql-prod-instance
Ngay sau khi thực hiện lệnh
docker stop 7844250860f8, bạn kiểm tra lại và thấy thời gian sống của nó chỉ mới được vài giây:
docker ps | grep mysql-server
# Kết quả: 7844250860f8 mysql:5.7 "..." 42 minutes ago Up Less than a second mysql-prod-instance
Thậm chí, khi tìm PID của tiến trình trên máy chủ (Host) thông qua
docker inspect và dùng lệnh
kill -9 để can thiệp trực tiếp vào tiến trình hệ điều hành, container vẫn tự động khởi động lại.
Kiểm tra cấu hình Restart Policy
Bước đầu tiên trong việc gỡ rối là kiểm tra chính sách khởi động lại (Restart Policy) của Docker. Thông thường, Docker hỗ trợ các tùy chọn sau:
- no: Mặc định, không bao giờ tự khởi động lại.
- on-failure: Chỉ khởi động lại nếu container thoát với mã lỗi khác 0.
- always: Luôn khởi động lại bất kể lý do thoát là gì.
- unless-stopped: Tương tự
always, nhưng nếu container đã bị dừng thủ công trước khi Docker daemon restart, nó sẽ không tự chạy lại.
Bạn có thể kiểm tra cấu hình này bằng lệnh:
docker inspect --format='{{json .HostConfig.RestartPolicy}}' [container_id_hoặc_name]
Nếu kết quả trả về là
"Name":"no" nhưng container vẫn tự chạy lại, vấn đề không nằm ở Docker Engine.
Nguyên nhân cốt lõi: Vai trò của các công cụ điều phối (Orchestrators)
Trong nhiều môi trường thực tế, Docker không chạy độc lập mà được quản lý bởi các công cụ như
Rancher, Kubernetes (K8s) hoặc
Docker Swarm.
Các công cụ này hoạt động dựa trên nguyên lý "Trạng thái mong muốn" (Desired State). Nếu bạn cấu hình hệ thống yêu cầu luôn phải có 1 instance MySQL hoạt động, thì khi bạn stop hoặc kill container đó, trình điều phối (Orchestrator) sẽ nhận thấy trạng thái thực tế đang thiếu hụt so với cấu hình và ngay lập tức ra lệnh tạo mới hoặc khởi động lại container để bù đắp.
Để dừng triệt để trong trường hợp này, bạn không thể tác động trực tiếp vào container ở tầng Docker mà phải điều chỉnh
Scale của Service về 0 hoặc xóa Resource trên giao diện quản lý của Rancher/Kubernetes.
Tìm hiểu sâu về các chính sách Restart trong Docker
Dưới đây là cách triển khai các chính sách khởi động lại khi bạn khởi tạo container thủ công:
1. Cấu hình giới hạn số lần thử lại với on-failure:
Lệnh này hữu ích khi ứng dụng gặp lỗi kết nối cơ sở dữ liệu tạm thời và cần thử lại một vài lần.
docker run -d \
--name app-worker \
--restart on-failure:3 \
my-app-image:latest
2. Sử dụng always để đảm bảo tính sẵn sàng:
Container sẽ tự chạy lại kể cả khi bạn khởi động lại toàn bộ máy chủ (Host) hoặc restart Docker service.
docker run -d \
--name web-gateway \
--restart always \
nginx:alpine
3. Sự khác biệt của unless-stopped:
Chính sách này giúp tránh tình trạng các container cũ, lỗi thời tự khởi chạy lại sau khi bảo trì máy chủ nếu trước đó bạn đã chủ động dừng chúng để nâng cấp.
docker run -d \
--name legacy-service \
--restart unless-stopped \
old-image:v1
Mẹo nhỏ: Nếu container đang chạy và bạn muốn đổi chính sách mà không muốn tạo lại container, hãy sử dụng lệnh
update:
docker update --restart=no [container_name]