---
id: docker-volume
title: "Docker volume"
shortTitle: "Volume"
track: docker
trackTitle: "Docker"
order: 8
level: core
status: published
estimatedMinutes: 30
prerequisites:
  - docker-compose
next: docker-registry
reviewedAgainst: 2026-10-12
sources:
  - title: "Docker volumes"
    url: https://docs.docker.com/engine/storage/volumes/
  - title: "Bind mounts"
    url: https://docs.docker.com/engine/storage/bind-mounts/
---

# Docker volume

Xóa container là mất file trong layer ghi của nó. Volume là nơi dữ liệu còn lại sau `docker rm`.

## Để làm gì

Tạo named volume, ghi một file, xóa container, và đọc lại file từ container khác.

## Gồm những gì

- Named volume.
- Bind mount, khác volume ở chỗ nào.
- `docker volume rm` chỉ khi không còn container dùng.

Không gồm plugin volume của nhà cung cấp cloud.

## Dùng khi nào

Database lab, file upload, hoặc bất kỳ thứ không được đóng vào image. Image là phần mềm. Volume là dữ liệu.

Đừng bind-mount cả thư mục home vào container chỉ để đỡ phải học volume. Container lúc đó đọc được SSH key và file riêng của bạn.

## Kiến thức cốt lõi

Named volume do Docker tạo, nằm trong vùng đĩa của Docker. Bạn đặt tên, ví dụ `lab-data`, rồi gắn vào đường dẫn trong container: `-v lab-data:/data`. Hai container gắn cùng tên thì thấy cùng file, nếu cùng lúc ghi thì phải tự khóa. Container xóa rồi, volume vẫn còn cho đến khi `docker volume rm`.

Bind mount gắn một đường dẫn trên host. `-v C:\projects\app:/app` trên Docker Desktop là kiểu này. Sửa file trên host là process trong container thấy ngay. Quyền file và đường dẫn Windows dễ lệch với user trong container. Named volume đỡ việc đó khi bạn chỉ cần dữ liệu của Docker.

`docker volume prune` xóa volume không còn container nào tham chiếu. Đừng chạy trên máy đang giữ database lab.

## Lệnh và code mẫu

```bash
docker volume create lab-data
docker run --rm -v lab-data:/data alpine:3 sh -c "echo hello > /data/note.txt"
docker run --rm -v lab-data:/data alpine:3 cat /data/note.txt
docker volume rm lab-data
```

## Thực hành

1. Chạy bốn lệnh trên.
2. Giữa hai lần `docker run`, không có container nào còn sống vì `--rm`. File vẫn đọc được.
3. `docker volume rm` sau khi đã đọc.

## Kết quả mong đợi

Lệnh `cat` in `hello`. `docker volume rm` in tên `lab-data`.

## Checklist

- [ ] Dữ liệu cần giữ nằm trên volume hoặc đĩa được backup, không nằm trong container.
- [ ] Bind mount không trỏ vào thư mục chứa secret.
- [ ] `docker volume rm` trước khi kết thúc lab.

## Thẻ ôn

### docker-volume-bind
kind: distinguish
cue: Named volume nằm trong vùng đĩa của Docker và còn sau khi xóa container. Bind mount gắn thẳng một đường dẫn trên máy host.

Q: Bạn cần giữ dữ liệu qua lần xóa container. Một người đề xuất named volume, người kia đề xuất bind mount thư mục trên máy. Hai cách khác nhau ở chỗ nào, và bind mount dễ lệch ở đâu?

A: Named volume do Docker tạo và quản lý, nằm trong vùng đĩa của Docker, không phải một path bạn chỉ tay trên desktop. Xóa container không xóa volume đó. Bind mount gắn một đường dẫn có sẵn trên host vào container: sửa file trên host thì process trong container thấy ngay, hợp khi đang sửa code. Đổi lại, quyền file và cách viết đường dẫn trên Windows dễ lệch với user đang chạy trong container. Dữ liệu của service thì named volume thường đỡ việc hơn.

### docker-volume-rm
kind: trap
cue: Ghi database vào layer của container rồi `docker rm` là mất dữ liệu. Gắn volume vào đúng thư mục data của image trước.

Q: Postgres chạy trong container và ghi dữ liệu vào chính filesystem của container, không gắn volume. Bạn `docker rm` để tạo lại container cho sạch. Dữ liệu còn không?

A: Mất. Phần ghi thêm trong lúc container chạy nằm ở layer ghi, và layer đó biến mất cùng container. Image gốc không giữ những dòng database vừa insert. Muốn dữ liệu sống sót, gắn volume vào đúng thư mục mà image dùng để ghi, với Postgres là `/var/lib/postgresql/data`, rồi mới xóa container. Container mới gắn lại cùng volume thì đọc được dữ liệu cũ.

### docker-volume-home
kind: trap
cue: Bind-mount cả thư mục home để đỡ tạo volume sẽ để container đọc SSH key và file riêng trên máy host.

Q: Cho nhanh, bạn bind-mount cả thư mục home của mình vào container, thay vì tạo một volume riêng cho dữ liệu app. Container lúc đó đọc được những gì trên máy host?

A: Mọi thứ trong home mà user của container có quyền đọc, kể cả SSH key, token, và file riêng không liên quan tới app. Container không cần những thứ đó để chạy. Khi chỉ cần một chỗ chứa dữ liệu của Docker, named volume là đủ. Đừng bind-mount một thư mục đang chứa secret chỉ vì đỡ phải khai volume.

### docker-volume-survive
kind: command
cue: `docker run --rm` xóa container khi thoát, nhưng named volume `lab-data` vẫn còn. Container khác gắn lại cùng volume là đọc được file.

Q: Bạn chạy `docker run --rm -v lab-data:/data`, ghi một file vào `/data`, rồi container thoát. File còn ở đâu, và lệnh nào mới xóa được nó?

A: `--rm` chỉ xóa container khi process thoát. Named volume `lab-data` không đi theo container, nên file vẫn nằm trong volume. Container khác gắn cùng `-v lab-data:/data` sẽ thấy file đó. `docker volume rm lab-data` mới xóa dữ liệu, và Docker từ chối nếu còn container nào đang dùng volume. Đừng tưởng `--rm` dọn cả dữ liệu.

## Lỗi thường gặp

**Ghi database vào container rồi `docker rm`.** Data mất. Gắn volume vào thư mục data của image, ví dụ `/var/lib/postgresql/data` với Postgres, rồi mới xóa container.

**Hai container cùng bind một file SQLite.** Cả hai ghi, file hỏng. Để một writer, hoặc dùng database có khóa. Volume không giải quyết xung đột ghi đó.

## Nguồn

1. [Volumes](https://docs.docker.com/engine/storage/volumes/) — named volume và vòng đời.
2. [Bind mounts](https://docs.docker.com/engine/storage/bind-mounts/) — gắn đường dẫn host.

## Tiếp theo

[Container Registry](./05-registry.md)
