Docker Container tự thoát ngay lập tức? Cách khắc phục để duy trì hoạt động

beginner🐳 Docker2026-04-03| Docker Engine (Mọi phiên bản), Docker Compose, Linux, macOS, WSL2

Error Message

Container shuts down instantly (e.g., `docker ps -a` shows 'Exited (0)' or 'Exited (1)')
#docker#devops#khắc phục lỗi#quản trị hệ thống

Container "Lúc Ẩn Lúc Hiện"

Bạn chạy lệnh docker run, terminal trả về một ID container, và mọi thứ có vẻ ổn. Nhưng chỉ một giây sau, dịch vụ của bạn không thể truy cập được. Bạn chạy docker ps và thấy một danh sách trống. Cuối cùng, docker ps -a tiết lộ sự thật: container của bạn đã "chết" ngay khi vừa mới khởi tạo.

# Những gì bạn thấy trong terminal
CONTAINER ID   IMAGE         COMMAND                  STATUS                     NAMES
7a1b2c3d4e5f   my-app:latest "docker-entrypoint.s…"   Exited (0) 5 seconds ago   my-app-container

Các container Docker chỉ duy trì trạng thái hoạt động chừng nào tiến trình chính (PID 1) của chúng còn chạy. Nếu tiến trình đó hoàn thành nhiệm vụ hoặc gặp lỗi và bị treo, container sẽ dừng lại. Đây không phải là lỗi; đó là cách Docker được thiết kế để vận hành. Dưới đây là cách chẩn đoán và khắc phục các nguyên nhân phổ biến nhất.

Bước 1: Tìm hiểu nguyên nhân từ Logs

Đừng vội vàng thay đổi code một cách mù quáng. Ngay cả khi container ở trạng thái 'Exited', Docker thường vẫn lưu giữ các luồng STDOUT và STDERR. Hành động đầu tiên của bạn nên là kiểm tra 20 đến 50 dòng output cuối cùng.

docker logs --tail 50 <container_id_or_name>

Hãy tìm các manh mối cụ thể như stack traces, "Permission denied," hoặc thiếu file cấu hình. Nếu log hoàn toàn trống và bạn thấy Exited (0), container có khả năng đã thực hiện một tác vụ nhanh (như ls hoặc một script ngắn) và thoát ra vì không còn việc gì để làm.

Bước 2: Giữ cho các Container tương tác luôn hoạt động

Các base image như ubuntu, alpine, hoặc debian được xây dựng để cung cấp một shell. Nếu bạn chạy chúng mà không có terminal tương tác, shell sẽ không nhận thấy đầu vào và thoát ngay lập tức để tiết kiệm tài nguyên.

Cách khắc phục nhanh cho các lần chạy đơn lẻ

Sử dụng các flag -it. Điều này yêu cầu Docker giữ cho standard input luôn mở và cấp phát một pseudo-TTY:

docker run -it ubuntu /bin/bash

Giải pháp với Docker Compose

Nếu bạn đang sử dụng Compose để xây dựng môi trường phát triển, hãy thêm hai dòng này vào định nghĩa service của bạn. Điều này mô phỏng hành vi của -it và ngăn container đóng phiên làm việc.

services:
  app:
    image: ubuntu
    tty: true
    stdin_open: true

Mẹo "Vòng lặp vô hạn"

Đôi khi bạn cần một container duy trì hoạt động dưới nền chỉ để có thể exec vào đó sau này. Trong những trường hợp này, hãy ghi đè lệnh mặc định bằng một tiến trình không bao giờ kết thúc:

services:
  app:
    image: alpine
    command: tail -f /dev/null

Bước 3: Xử lý lỗi Exit Code 1 (Ứng dụng bị sập)

Trạng thái Exited (1) có nghĩa là ứng dụng đã cố gắng chạy nhưng gặp lỗi nghiêm trọng. Trong khoảng 90% trường hợp, thủ phạm là một trong ba nguyên nhân sau:

  • Thiếu biến môi trường: Ứng dụng của bạn yêu cầu DATABASE_URL nhưng nó chưa được định nghĩa trong khối environment.
  • Quyền hạn Volume: Bạn đã mount một thư mục cục bộ vào /var/log/app, nhưng người dùng trong container không có quyền ghi vào máy host của bạn.
  • Sai WORKDIR: Lệnh CMD đang tìm kiếm index.js ở thư mục gốc, nhưng WORKDIR của bạn lại được thiết lập là /usr/src/app.

Mẹo nhỏ: Luôn kiểm tra kỹ các đường dẫn của bạn. Nếu bạn sử dụng một script entrypoint, hãy đảm bảo nó có quyền thực thi chính xác trước khi build image:

# Bên trong Dockerfile của bạn
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Bước 4: Bẫy ký tự kết thúc dòng giữa Windows và Linux

Nếu bạn phát triển trên Windows và chạy container trên Linux, các script của bạn có thể được lưu với ký tự kết thúc dòng CRLF. Linux không nhận diện được các ký tự này. Điều này thường dẫn đến lỗi "file not found" gây khó hiểu, ngay cả khi file đó hiển thị rõ ràng.

Bạn có thể khắc phục điều này bằng cách buộc IDE sử dụng ký tự kết thúc LF hoặc thêm dos2unix vào quá trình build:

# Một cách hiệu quả để xử lý ký tự kết thúc dòng trong Dockerfile
RUN apt-get update && apt-get install -y dos2unix
RUN dos2unix /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

Bước 5: Sử dụng định dạng JSON 'Exec'

Cách bạn viết lệnh CMD rất quan trọng. Hãy tránh sử dụng shell form (CMD node index.js) vì nó bao bọc lệnh của bạn trong /bin/sh -c. Điều này ngăn ứng dụng của bạn nhận các tín hiệu Unix như SIGTERM.

# Ưu tiên: Định dạng Exec
CMD ["node", "index.js"]

Định dạng Exec đảm bảo ứng dụng của bạn là PID 1. Điều này cho phép tắt ứng dụng một cách an toàn (graceful shutdown) và ngăn chặn các tiến trình "zombie" tồn tại sau khi xảy ra lỗi.

Cách xác minh việc khắc phục

Sau khi áp dụng các thay đổi, đừng vội giả định rằng nó hoạt động chỉ vì lệnh không báo lỗi. Hãy kiểm tra thời gian uptime sau 30 giây. Sử dụng docker ps để đảm bảo trạng thái hiển thị Up 30 seconds (hoặc lâu hơn). Nếu bạn có định nghĩa health check, hãy xác minh bằng cách chạy lệnh docker inspect --format='{{json .State.Health.Status}}' <container_id>. Trạng thái "healthy" là minh chứng cuối cùng cho việc tiến trình của bạn thực sự đang hoạt động tốt.

Related Error Notes