Sự khác biệt giữa docker compose stop và down
Lệnh stop chỉ dừng container, còn down xóa cả container và network. Cả hai đều giữ lại dữ liệu trong volume trừ khi bạn dùng thêm cờ -v để xóa sạch hoàn toàn hệ thống.
Câu trả lời ngắn gọn
docker compose stop dừng các container và giữ chúng lại trên ổ đĩa. docker compose down dừng các container sau đó xóa chúng cùng với network mà Compose đã tạo cho dự án. Cả hai lệnh này đều không tác động đến các named volume. Cơ sở dữ liệu của bạn chỉ bị xóa khi bạn thêm -v, ví dụ như trong docker compose down -v, lệnh này sẽ xóa các named volume đã khai báo trong phần volumes của file Compose.
Đó là toàn bộ sự khác biệt trong một đoạn văn. Phần còn lại của hướng dẫn này sẽ chứng minh điều đó với một volume Postgres mà bạn có thể thấy nó vẫn tồn tại sau lệnh down và biến mất khi dùng 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: các container vẫn tồn tại
stop gửi tín hiệu SIGTERM đến tiến trình chính trong mỗi container, đợi một khoảng thời gian, sau đó 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 cho phép thay đổi giá trị này. Không có gì bị xóa. Container vẫn giữ nguyên ID, lớp ghi (writable layer), địa chỉ IP đã cấp và các log của nó.
docker compose stop
docker compose ps -adocker compose ps khi chạy độc lập chỉ hiển thị các container đang chạy, vì vậy sau khi dùng stop, nó sẽ in ra một bảng trống và người dùng thường nghĩ rằng các container đã biến mất. ps -a bao gồm cả các container đã dừng, và đó là nơi bạn sẽ thấy trạng thái Exited (0) bên cạnh mỗi service. Hãy khởi động lại chúng bằng docker compose start, lệnh này sẽ sử dụng lại chính xác các container cũ.
Vì các container vẫn tồn tại, mọi dữ liệu được ghi bên trong chúng nằm ngoài volume vẫn còn đó. Điều này bao gồm cả gói phần mềm bạn đã cài đặt thủ công bằng docker compose exec và tệp cấu hình bạn đã chỉnh sửa bên trong container. Đây là lý do thực tế để ưu tiên dùng stop trong quá trình debug: bạn có thể khởi động lại và giữ nguyên trạng thái cũ.
docker compose down: xóa các container và network
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 dự án. Tài liệu Docker mô tả lệnh này là dừng và xóa các container, network, volume và image được tạo bởi up, nhưng phần volume và image chỉ xảy ra khi bạn yêu cầu bằng -v và --rmi.
docker compose down
docker compose ps -a
docker network lsSau khi chạy down, ps -a sẽ không hiển thị gì cho dự án đó và network <project>_default cũng đã bị xóa. Tên dự án được lấy từ tên thư mục trừ khi bạn thiết lập name: trong file Compose hoặc truyền tham số -p. Mọi thay đổi bạn thực hiện bên trong lớp ghi được (writable layer) của container giờ đây không thể khôi phục, vì vậy hãy coi down là lệnh hủy bỏ container và chỉ giữ lại dữ liệu bạn đã lưu trong các volume.
Chạy lệnh này trong sai thư mục sẽ dẫn đến lỗi no configuration file provided: not found. Compose không biết bạn đang nhắm đến dự án nào nên nó sẽ từ chối thực hiện. Hãy sử dụng docker compose -f /srv/myapp/compose.yaml down khi bạn không ở trong thư mục dự án.
Lệnh docker compose down có xóa các volume của tôi không?
Không. Một named volume được khai báo dưới khóa cấp cao nhất volumes sẽ tồn tại lâu hơn down, và nó cũng tồn tại lâu hơn container mà nó được gắn vào. Đây là nỗi lo phổ biến nhất về lệnh này, và câu trả lời vẫn nhất quán trên Compose v2.
Hãy thiết lập một stack để bạn có thể kiểm tra. Đặt nội dung này vào compose.yaml trong một thư mục trống có tên là voltest.
services:
db:
image: postgres:16.4
restart: unless-stopped
environment:
POSTGRES_PASSWORD: example
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:Khởi chạy nó và ghi một dòng mà bạn sẽ 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ờ hãy xóa container và kiểm tra volume.
docker compose down
docker volume lsKết quả đầu ra vẫn liệt kê voltest_pgdata. Container đã mất nhưng dữ liệu thì không. Hãy chạy lại stack và đọc dòng đó.
docker compose up -d
sleep 10
docker compose exec -T db psql -U postgres -c "select * from marker;"Bạn sẽ nhận được một dòng chứa survived. Container mới là một container khác với ID khác, được gắn vào cùng một volume. Nếu bạn muốn cái nhìn tổng quan hơn, hướng dẫn cơ bản về Compose sẽ đề cập đến named volume so với bind mount và vị trí thực tế của từng loại trên host.
Lệnh down -v thực sự xóa những gì
-v (dạng đầy đủ --volumes) xóa các volume được đặt tên đã khai báo trong phần volumes của tệp Compose, cùng với các volume ẩn danh gắn với container. Hãy chạy lệnh này với cùng một stack.
docker compose down -v
docker volume lsvoltest_pgdata không còn được liệt kê nữa. Khởi động lại stack và entrypoint của Postgres sẽ thấy thư mục dữ liệu trống, do đó nó khởi tạo một cluster mới. Log của container hiển thị 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.Việc thấy khối log đó trên một stack đã chạy nhiều tháng nghĩa là volume đã bị xóa. Bảng marker của bạn đã mất và cách duy nhất để khôi phục là dùng bản backup.
Một số bộ nhớ không bao giờ bị xóa bởi -v. Bind mount là một đường dẫn trên host, nên Docker chỉ ngắt kết nối (unmount) và tệp tin của bạn vẫn nằm nguyên tại đó. Một volume được đánh dấu external: true được khai báo thuộc về một thành phần bên ngoài dự án này, và Compose không bao giờ xóa nó. Một volume được đặt tên mà bạn đã xóa khỏi tệp Compose trước khi chạy down -v sẽ không còn được khai báo, vì vậy Compose không biết để xóa nó và nó bị bỏ lại như một volume mồ côi đối với docker volume prune.
Trường hợp cuối cùng này thường gây lỗi cho người dùng trong quá trình refactor. Nếu bạn xóa một service và volume của nó khỏi tệp, sau đó chạy down -v, volume đó vẫn tồn tại vì tệp không còn đề cập đến nó nữa. Hãy chạy down -v trước khi bạn chỉnh sửa tệp, không phải sau đó.
Khi nào bạn thực sự cần --force-recreate
docker compose up -d không xây dựng lại toàn bộ hệ thống mỗi lần chạy. Compose lưu trữ một hash của cấu hình đã phân giải cho mỗi service dưới dạng một label trên container. Nếu hash khớp và ID của image khớp, container sẽ được giữ nguyên và bạn nhận được Container voltest-db-1 Running thay vì Recreated. Đây là hành vi bạn gần như luôn mong muốn, vì nó giúp việc chạy up -d trở nên an toàn khi thực hiện nhiều lần.
Đây cũng là lý do tại sao một số thay đổi có vẻ không có tác dụng. Compose tạo hash cho định nghĩa service đã phân giải, không phải nội dung của các file mà định nghĩa đó trỏ tới. Một file cấu hình được mount vào container và đọc một lần khi khởi động sẽ không kích hoạt việc tạo lại khi bạn chỉnh sửa nó, vì đường dẫn mount không thay đổi. Service vẫn tiếp tục chạy với các giá trị mà nó đã đọc lúc khởi động.
docker compose up -d --force-recreateLệnh này dừng và xóa từng container, sau đó tạo một container mới từ cùng định nghĩa đó. Hãy sử dụng nó sau khi chỉnh sửa một file cấu hình đã mount, và khi một container rơi vào trạng thái mà bạn không thể giải thích được. Các volume không bị ảnh hưởng, vì vậy database vẫn tồn tại sau khi force recreate. Để cập nhật image mới hơn trên cùng một tag, bạn cần thực hiện cả lệnh pull.
docker compose pull
docker compose up -dpull lấy ID image mới, và up -d sau đó thấy ID image khác với container đang chạy nên sẽ tự động tạo lại nó. Việc thêm --force-recreate mà không có pull chỉ tạo ra một container mới từ cùng một image cũ. Đó là lý do tại sao "Tôi đã force recreate mà nó vẫn là phiên bản cũ" là một phàn nàn rất phổ biến.
docker compose restart không thực hiện bất kỳ điều nào trong số này. Nó khởi động lại các container hiện có và hoàn toàn không đọc lại file Compose, vì vậy một biến môi trường hoặc cấu hình port mapping đã thay đổi sẽ không được áp dụng. Nếu bạn đã chỉnh sửa file, hãy sử dụng up -d.
Mô hình tư duy cần ghi nhớ
Container có thể thay thế được. Một container là một tiến trình cộng với một lớp ghi mỏng, và Compose có thể tạo ra một container giống hệt từ file trong khoảng một giây. Volume không thể thay thế, vì chúng chứa bản sao duy nhất của trạng thái mà không file nào trong repository của bạn có thể tái tạo lại.
Mỗi động từ của Compose đều tuân theo sự phân chia đó. stop và start giữ lại container. down và up thay thế container và giữ lại volume. down -v là lệnh thông thường duy nhất xóa trạng thái, đó là lý do tại sao nó cần một flag rõ ràng. Trước khi gõ lệnh này trên bất kỳ hệ thống thực tế nào, hãy xác nhận bạn đã có bản sao lưu mà bạn đã khôi phục ít nhất một lần.
Logic tương tự áp dụng cho các secret. Mật khẩu được thiết lập thông qua POSTGRES_PASSWORD chỉ được đọc lần đầu tiên khi database khởi tạo, vì vậy việc thay đổi nó trong file môi trường của bạn và chạy up -d sẽ dẫn đến password authentication failed for user "postgres". Container là mới còn volume là cũ, và volume cũ vẫn giữ mật khẩu cũ. Cách Compose giải quyết các file env và secret giải thích lớp nào sẽ được ưu tiên khi cùng một biến được thiết lập hai lần.
Các chế độ lỗi và thông báo bạn sẽ gặp
no configuration file provided: not found nghĩa là Compose đang chạy trong một thư mục không có compose.yaml và không có docker-compose.yml. Hãy truyền -f kèm theo đường dẫn đầy đủ.
network voltest_default has active endpoints trên down nghĩa là một container nằm ngoài dự án này đang được gắn vào mạng của dự án, thường là container được khởi chạy thủ công bằng docker run --network. Hãy xóa container đó, sau đó 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. Container cũ vẫn còn mang nhãn dự án. docker compose down --remove-orphans sẽ xóa các nhãn này và việc chạy lệnh này trên một stack đang hoạt động bình thường là an toàn.
Error response from daemon: remove voltest_pgdata: volume is in use khi thực hiện docker volume rm thủ công nghĩa là vẫn còn container tham chiếu đến volume đó, bao gồm cả các container đã dừng. Hãy chạy docker compose down trước, sau đó xóa volume, hoặc chỉ cần dùng down -v. Với một dự án lớn hơn, một stack Compose đa dịch vụ sẽ cho thấy số lượng volume mà một dự án có thể tích lũy.
FAQ
Lệnh docker compose down có xóa cơ sở dữ liệu của tôi không?
Không, nếu cơ sở dữ liệu nằm trong một named volume hoặc bind mount. down xóa các container và network của dự án, còn volume vẫn nằm trên đĩa với dữ liệu nguyên vẹn. Lệnh docker compose up -d tiếp theo sẽ gắn một container mới vào cùng volume đó và dữ liệu vẫn ở đó. Chỉ có docker compose down -v mới xóa các named volume, và chỉ xóa những volume được khai báo trong phần volumes của file Compose.
Sự khác biệt giữa stop và down đối với container mà tôi muốn sử dụng lại là gì?
stop giữ lại container, vì vậy docker compose start đưa bạn trở lại đúng container đó với cùng lớp ghi (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, vì vậy lệnh up -d tiếp theo sẽ tạo một container mới từ image và các thay đổi thủ công đó sẽ bị mất. Trong khi đang debug, hãy sử dụng stop.
Làm thế nào để xóa mọi thứ mà một dự án Compose đã tạo ra?
docker compose down -v --rmi all --remove-orphans xóa các container, network của dự án, các named volume được khai báo trong file, các image mà dịch vụ đã sử dụng và bất kỳ container nào vẫn còn gắn nhãn với tên dự án. Nó không tác động đến các bind mount hoặc các volume được đánh dấu external: true. Hãy kiểm tra những gì bạn sắp xóa bằng docker volume ls trước khi chạy lệnh này.
Tại sao container của tôi bỏ qua thay đổi tôi đã thực hiện đối với file cấu hình được mount?
Compose quyết định có tạo lại container hay không bằng cách so sánh mã hash của định nghĩa dịch vụ đã phân giải, và mã hash đó không bao gồm nội dung của file được mount. Đường dẫn không thay đổi, nên Compose để container tiếp tục chạy với các giá trị mà nó đã đọc khi khởi động. Hãy chạy docker compose up -d --force-recreate để tạo một container mới đọc lại file đó.
Tại sao POSTGRES_PASSWORD mới của tôi không hoạt động sau khi tôi thay đổi nó?
Image Postgres chỉ đọc POSTGRES_PASSWORD khi nó khởi tạo một thư mục dữ liệu trống. Volume của bạn đã chứa một cluster đã khởi tạo, vì vậy biến này bị bỏ qua và mật khẩu cũ vẫn được áp dụng. Bạn sẽ thấy password authentication failed for user "postgres". Hãy thay đổi mật khẩu bằng ALTER USER bên trong cơ sở dữ liệu đang chạy, hoặc chấp nhận mất dữ liệu và bắt đầu lại với docker compose down -v.