Docker Compose down vs stop: khác nhau thế nào?
docker compose stop chỉ dừng và giữ container. down xóa container, writable layer và network của project; named volume chỉ bị xóa khi thêm flag --volumes.
Câu trả lời ngắn gọn
docker compose stop dừng các container và giữ chúng trên đĩa. docker compose down dừng các container, sau đó xóa các container và network mà Compose tạo cho project. Cả hai lệnh đều không tác động đến named volume. Khi thêm -v, như trong docker compose down -v, lệnh sẽ xóa các named volume không phải external được khai báo trong phần volumes của file Compose và thuộc project này. down sẽ xóa dữ liệu mà container ghi vào writable layer riêng của nó, bên ngoài mọi volume.
Đó là toàn bộ khác biệt trong một đoạn. Phần còn lại của hướng dẫn này chứng minh điều đó bằng một Postgres volume mà bạn có thể theo dõi để thấy nó vẫn tồn tại sau down nhưng biến mất khi chạy down -v, đồng thời giải thích hai trường hợp bạn cần dùng --force-recreate.
docker compose stop: container vẫn còn
stop gửi tín hiệu stop đã cấu hình cho container, mặc định là SIGTERM, đến tiến trình chính trong từng container, chờ một khoảng thời gian, rồi gửi SIGKILL nếu tiến trình vẫn còn chạy. Thời gian chờ mặc định là 10 giây và -t thay đổi giá trị này. Không có gì bị xóa. Container vẫn giữ nguyên ID, writable layer và log.
docker compose stop
docker compose ps -adocker compose ps khi chạy riêng chỉ hiển thị các container đang chạy. Vì vậy, sau khi chạy stop, lệnh này in ra một bảng trống và khiến bạn nghĩ rằng các container đã bị xóa. ps -a bao gồm cả các container đã dừng. Tại đó, bạn sẽ thấy trạng thái Exited bên cạnh từng service, cùng với exit code mà tiến trình trả về. Một lần shutdown sạch thường hiển thị Exited (0), nhưng không phải lúc nào cũng vậy. Một số server hoàn tất graceful shutdown rồi phát lại tín hiệu stop, khiến tiến trình kết thúc do tín hiệu đó. Uvicorn hoạt động đúng như vậy, nên một lần stop có trật tự vẫn có thể để lại mã khác 0. Mã khác 0 cũng có thể cho biết tiến trình đã lỗi hoặc bị kill sau khi hết thời gian chờ. Khởi động lại chúng bằng docker compose start; lệnh này sử dụng lại chính các container đó.
Vì các container vẫn còn tồn tại, mọi dữ liệu được ghi bên trong chúng nhưng nằm ngoài volume vẫn được giữ lại. Trong đó có package bạn cài thủ công bằng docker compose exec và file cấu hình bạn chỉnh sửa bên trong container. Đây là lý do thực tế để ưu tiên stop trong khi debug: bạn có thể khởi động lại với đúng trạng thái cũ.
docker compose down: container và network bị xóa
down dừng các container rồi xóa chúng cùng với network mặc định mà Compose tạo cho project. Tài liệu Docker mô tả lệnh này là dừng container và xóa container, network, volume và image do up tạo ra. Tuy nhiên, volume và image chỉ bị xóa khi bạn yêu cầu bằng -v và --rmi.
docker compose down
docker compose ps -a
docker network lsSau down, ps -a không in gì cho project và network <project>_default cũng không còn. Tên project được lấy từ tên thư mục project, trừ khi bạn đặt name: trong file Compose, đặt COMPOSE_PROJECT_NAME hoặc truyền -p. Mọi thay đổi trong writable layer của container giờ không thể khôi phục. Vì vậy, hãy xem down là lệnh loại bỏ container nhưng giữ lại dữ liệu bạn lưu trong volume.
Nếu Compose không tìm thấy file cấu hình trong thư mục hiện tại hoặc các thư mục cha, đồng thời bạn không chỉ định file bằng -f hoặc COMPOSE_FILE, Compose sẽ trả về no configuration file provided: not found. Compose không biết bạn muốn thao tác với project nào nên từ chối chạy. Dùng docker compose -f /srv/myapp/compose.yaml down khi bạn không đứng trong thư mục project.
docker compose down có xóa volume của tôi không?
Không. Named volume được khai báo trong key cấp cao nhất volumes sẽ tồn tại sau down, và vẫn tồn tại sau khi container gắn volume đó bị xóa. Đây là lo ngại phổ biến nhất về lệnh này. Compose v5.7.0 đã thay đổi down -v: hiện tại Compose bỏ qua các named volume thuộc project khác hoặc được tạo bên ngoài Compose, đồng thời hiển thị cảnh báo.
Hãy tạo một stack để kiểm tra. Ghi nội dung sau vào compose.yaml trong một thư mục trống có tên voltest.
services:
db:
image: postgres:16.4
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:Khởi động stack rồi ghi một row để bạn có thể nhận ra sau này.
docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "create table marker (note text);"
docker compose exec -T db psql -U postgres -c "insert into marker values ('survived');"Bây giờ xóa container và kiểm tra volume.
docker compose down
docker volume lsOutput vẫn liệt kê voltest_pgdata. Container đã bị xóa nhưng dữ liệu vẫn còn. Khởi động lại stack rồi đọc row đó.
docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "select * from marker;"Bạn nhận được một row chứa survived. Container mới là một container khác với ID khác, nhưng được gắn vào cùng volume. Nếu muốn hiểu tổng thể hơn, hướng dẫn cơ bản về Compose giải thích named volume so với bind mount và vị trí thực tế của từng loại trên host.
-v phá hủy chính xác những gì
-v (dạng đầy đủ --volumes) xóa các named volume không phải external được khai báo trong phần volumes của file Compose và thuộc project này, cùng các anonymous volume gắn với các container. Trong Compose v5.7.0, named volume có ownership label của project khác hoặc không có project label sẽ bị bỏ qua kèm cảnh báo; nếu không thể kiểm tra ownership, command sẽ fail và giữ lại volume. Hãy chạy command này trên đúng stack đó.
docker compose down -v
docker volume lsvoltest_pgdata không còn được liệt kê. Khởi động lại stack. Postgres entrypoint sẽ thấy data directory trống nên khởi tạo một cluster mới. Container log ghi rõ điều này.
The files belonging to this database system will be owned by user "postgres".
PostgreSQL init process complete; ready for start up.Nếu thấy block đó trên một stack đã chạy nhiều tháng, nghĩa là Postgres đang khởi tạo một data directory trống. Bảng marker của bạn đã mất và cách duy nhất để khôi phục là dùng backup.
Một số storage không bao giờ bị -v xóa. Bind mount là một host path, nên Docker chỉ unmount nó còn các file vẫn giữ nguyên vị trí. Volume có đánh dấu external: true được khai báo là thuộc về một thành phần bên ngoài project này, nên Compose không bao giờ xóa nó. Named volume mà bạn đã xóa khỏi file Compose trước khi chạy down -v không còn được khai báo. Vì vậy Compose không biết phải xóa nó và volume bị bỏ lại dưới dạng orphan trong docker volume prune -a sau khi không còn container nào tham chiếu đến nó.
Trường hợp cuối thường gây nhầm lẫn khi refactor. Xóa một service và volume của nó khỏi file, chạy down -v, volume vẫn còn vì file không còn nhắc đến nó. Hãy chạy down -v trước khi sửa file, không phải sau đó.
Khi thực sự cần --force-recreate
docker compose up -d không dựng lại toàn bộ mọi thứ mỗi lần chạy. Compose lưu hash của cấu hình đã resolve của từng service dưới dạng label trên container. Trong Compose v5.7.0, container đang chạy sẽ được giữ nguyên khi hash cấu hình, image ID và digest của image-volume khớp nhau, các kết nối network dự kiến và các mount named volume đều tồn tại, đồng thời không có parent đang chia sẻ namespace hoặc volume bị recreate. Khi đó, bạn nhận được Container voltest-db-1 Running thay vì Recreated. Đây gần như luôn là hành vi bạn muốn, vì nó giúp up -d an toàn khi chạy lặp lại.
Đó cũng là lý do một số chỉnh sửa có vẻ không có tác dụng. Compose hash service definition đã resolve, không hash nội dung của các file mà definition đó trỏ tới. File cấu hình được mount vào container và chỉ được đọc một lần lúc startup sẽ không kích hoạt recreate khi bạn chỉnh sửa file, vì mount path không thay đổi. Service vẫn tiếp tục chạy với các giá trị đã đọc lúc boot.
docker compose up -d --force-recreateLệnh này dừng và xóa từng container, rồi tạo container mới từ cùng definition. Hãy dùng lệnh này sau khi chỉnh sửa file cấu hình được mount, hoặc khi container đã lệch sang một trạng thái mà bạn không thể giải thích. Các volume không bị tác động, nên database vẫn tồn tại sau force recreate. Để lấy image mới hơn trên cùng một tag, bạn cũng cần thêm pull.
docker compose pull
docker compose up -dpull tải image ID mới, sau đó up -d nhận thấy image ID này khác với image ID của container đang chạy và tự recreate container. Nếu thêm --force-recreate mà không có pull, bạn sẽ nhận được container mới từ cùng image cũ. Vì vậy, câu “tôi đã force recreate nhưng vẫn là phiên bản cũ” xuất hiện rất thường xuyên.
docker compose restart không làm bất kỳ việc nào trong số đó. Lệnh này chỉ restart các container hiện có mà không áp dụng thay đổi vào cấu hình của chúng, nên biến môi trường hoặc port mapping đã thay đổi sẽ không có hiệu lực. Nếu bạn đã chỉnh sửa file, hãy dùng up -d.
Mô hình cần ghi nhớ
Container có thể thay thế. Container là một process kèm một lớp ghi tạm mỏng, và Compose có thể tạo container thay thế từ file và image. Volume không thể thay thế, vì chúng chứa bản sao duy nhất của state mà không file nào trong repository của bạn có thể tạo lại.
Mỗi verb của Compose đều tương ứng với sự phân tách này. stop và start giữ nguyên container. down và up thay thế container nhưng giữ lại volume. down -v là command thông thường duy nhất xóa state, nên command này yêu cầu một flag rõ ràng. Trước khi chạy command đó trên bất kỳ hệ thống thực nào, hãy xác nhận bạn có backup và đã restore backup đó ít nhất một lần.
Logic tương tự cũng áp dụng cho secret. Password được thiết lập qua POSTGRES_PASSWORD chỉ được dùng để đặt password database khi database khởi tạo lần đầu. Vì vậy, thay đổi password trong file môi trường rồi chạy up -d sẽ không thay đổi password đã lưu. Container là container mới, còn volume là volume cũ, và volume cũ vẫn chứa password cũ. Cách Compose xử lý file môi trường và secret giải thích layer nào được ưu tiên khi cùng một biến được đặt hai lần.
Các trạng thái lỗi và chuỗi bạn sẽ thấy
no configuration file provided: not found có nghĩa là Compose không tìm thấy file cấu hình trong thư mục hiện tại hoặc khi tìm lên các thư mục cha, -f hoặc COMPOSE_FILE. Truyền -f với đường dẫn đầy đủ.
Network voltest_default Resource is still in use trên down trong Compose v5.7.0 có nghĩa là vẫn còn container kết nối với project network, thường là các container bên ngoài project này được khởi động thủ công bằng docker run --network. Xóa các container đó, rồi chạy lại down.
Found orphan containers (voltest-old-1) for this project xuất hiện sau khi bạn đổi tên hoặc xóa một service. Compose hiện tại liệt kê tên trực tiếp và phân tách bằng dấu phẩy. Các bản Compose v2 cũ hơn in cùng cảnh báo nhưng đặt tên trong dấu ngoặc vuông, như trong ([voltest-old-1]). Container cũ vẫn còn project label. docker compose down --remove-orphans sẽ xóa các container đó.
Error response from daemon: remove voltest_pgdata: volume is in use trên docker volume rm thủ công có nghĩa là vẫn còn container tham chiếu đến volume, kể cả container đã dừng. Chạy docker compose down trước, rồi xóa volume, hoặc dùng down -v. Với project lớn hơn, một Compose stack nhiều service cho thấy một project có thể tích lũy bao nhiêu volume.
FAQ
docker compose down có xóa database của tôi không?
Không, nếu database nằm trong named volume hoặc bind mount. down xóa các container và network của project, còn volume vẫn nằm trên disk cùng toàn bộ dữ liệu. Lần docker compose up -d tiếp theo sẽ gắn container mới vào cùng volume đó và dữ liệu vẫn còn. docker compose down -v xóa các named volume không phải external được khai báo trong phần volumes của file Compose và thuộc project này.
Sự khác nhau giữa stop và down là gì nếu tôi muốn dùng lại container?
stop giữ lại container, nên docker compose start đưa bạn trở lại đúng container đó với cùng writable layer. Mọi thứ bạn cài đặt hoặc chỉnh sửa thủ công bên trong container vẫn còn. down xóa container, nên lần up -d tiếp theo sẽ tạo container mới từ image và các thay đổi thủ công đó sẽ mất. Khi đang debug, hãy dùng stop.
Làm cách nào để xóa mọi thứ mà một project Compose đã tạo?
docker compose down -v --rmi all --remove-orphans xóa các container, network của project, các named volume không phải external được khai báo trong file và thuộc project này, các image mà service đã dùng, cùng các orphan container của project. Lệnh này không tác động đến bind mount hoặc volume được đánh dấu external: true. Hãy kiểm tra những gì sắp bị xóa bằng docker volume ls trước khi chạy lệnh.
Tại sao container bỏ qua thay đổi tôi thực hiện trong file cấu hình đã mount?
Compose quyết định có tạo lại container hay không bằng cách so sánh hash của service definition đã được resolve. Hash này không bao gồm nội dung của file đã mount. Path không thay đổi, nên Compose giữ container đang chạy với các giá trị đã đọc lúc khởi động. Chạy docker compose up -d --force-recreate để tạo container mới và đọc lại file.
Tại sao POSTGRES_PASSWORD mới của tôi không có tác dụng sau khi thay đổi?
Postgres image chỉ dùng POSTGRES_PASSWORD để đặt database password khi khởi tạo một data directory trống. Volume của bạn đã chứa một cluster được khởi tạo, nên biến này bị bỏ qua và password cũ vẫn được áp dụng. Kết nối bằng password mới sẽ trả về password authentication failed for user "postgres". Đổi password bằng ALTER USER bên trong database đang chạy, hoặc chấp nhận mất dữ liệu và bắt đầu lại bằng docker compose down -v.