Docker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách

  1. Trang chủ
  2. Blog
  3. DevOps

DevOps

Khối lượng Docker so với liên kết gắn kết: Lưu trữ dữ liệu vùng chứa đúng cách

Xóa vùng chứa và dữ liệu của nó sẽ đi cùng với nó, trừ khi bạn lưu trữ nó ở nơi nào đó an toàn hơn. Tìm hiểu sự khác biệt giữa các ổ đĩa, liên kết gắn kết và tmpfs, thời điểm sử dụng từng ổ và cách sao lưu những nội dung quan trọng.

Đọc 9 phút
Khối lượng Docker so với gắn kết liên kết: duy trì dữ liệu vùng chứa đúng cách

Điểm chính

  • Lớp có thể ghi của vùng chứa sẽ bị xóa cùng với vùng chứa, vì vậy dữ liệu quan trọng cần được gắn kết.
  • Các tập được đặt tên được quản lý bởi Docker và là lựa chọn thông thường cho cơ sở dữ liệu và dữ liệu sản xuất.
  • Các liên kết gắn kết ánh xạ một thư mục máy chủ, điều này khiến chúng trở nên lý tưởng cho mã trực tiếp trong quá trình phát triển.
  • docker compose down -v xóa các tập, vì vậy hãy sử dụng nó cẩn thận và giữ các bản sao lưu đã được kiểm tra.

Bạn khởi động cơ sở dữ liệu trong một vùng chứa, thêm một số dữ liệu, xóa vùng chứa và bắt đầu một cơ sở dữ liệu mới. Dữ liệu đã biến mất. Hầu hết mọi người đều học được bài học này một cách khó khăn. Các khối Docker và các liên kết gắn kết tồn tại để giữ cho dữ liệu tồn tại ngoài vòng đời của bất kỳ vùng chứa nào.

Hướng dẫn này giải thích cách hoạt động của từng loại và cách chọn. Các lệnh và tệp ở đây là các ví dụ tiêu chuẩn, dựa trên hoạt động được ghi lại trong tài liệu của Docker và chúng tôi không chạy chúng cho bài viết này, vì vậy hãy thử chúng trước trên dữ liệu dùng một lần. Thông tin chi tiết có thể khác nhau giữa các phiên bản Docker và trên Docker Desktop. Nếu bạn chưa quen với vùng chứa, hãy bắt đầu với Hướng dẫn về Docker dành cho người mới bắt đầu của chúng tôi.

Tại sao dữ liệu vùng chứa biến mất

Hình ảnh Docker được tạo từ các lớp chỉ đọc. Khi một vùng chứa khởi động, Docker sẽ thêm một lớp mỏng có thể ghi lên trên và mọi thay đổi sẽ xuất hiện ở đó. Lớp đó vẫn tồn tại khi dừng và khởi động lại, nhưng nó sẽ bị xóa khi vùng chứa bị xóa.

docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# ... create tables and add data ...
docker rm -f db
docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# The data you added is not there

Đây là do thiết kế vì nó cho phép bạn thay thế các thùng chứa một cách tự do. Điều đó có nghĩa là bất cứ thứ gì bạn cần giữ đều phải nằm bên ngoài vùng chứa. Có ba cách để làm điều đó:

Loại Được lưu trữ trong Sống sót sau khi loại bỏ container?
Tập được đặt tên Một khu vực được quản lý bởi Docker Có
Gắn kết Đường dẫn máy chủ mà bạn chọn Có
gắn kết tmpfs Bộ nhớ máy chủ Không

Khối lượng Docker và liên kết gắn kết cạnh nhau

Khía cạnh Tập được đặt tên Gắn kết
Được quản lý bởi Docker bạn
Vị trí Khu vực lưu trữ của Docker Bất kỳ đường dẫn nào trên máy chủ
Phụ thuộc vào thư mục máy chủ? Không Có
Chỉnh sửa từ máy chủ Lúng túng bởi thiết kế Dễ dàng, thay đổi xuất hiện ngay lập tức
Mục tiêu trống được điền sẵn từ hình ảnh? Có Không, đường dẫn máy chủ ẩn nó
Các lệnh CLI của Docker Có, docker volume Không
Trình điều khiển để lưu trữ từ xa Có Không
Tốt nhất cho Cơ sở dữ liệu, dữ liệu sản xuất Mã nguồn đang được phát triển

Tập được đặt tên

Ổ đĩa là bộ lưu trữ được tạo và quản lý bởi Docker. Bạn gọi nó bằng tên và bạn không cần quan tâm nó sống ở đâu.

docker volume create pgdata

docker run -d --name db \
  -e POSTGRES_PASSWORD=devonly \
  -v pgdata:/var/lib/postgresql/data \
  postgres:17

Bây giờ các tệp cơ sở dữ liệu nằm trong pgdata. Xóa vùng chứa và bắt đầu một vùng chứa mới có cùng dung lượng và dữ liệu của bạn sẽ vẫn ở đó. Trên Linux, các ổ đĩa thường nằm trong /var/lib/docker/volumes/, nhưng bạn không nên chỉnh sửa trực tiếp các tệp đó. Trên Docker Desktop, chúng tồn tại bên trong một máy ảo chứ không phải trong một thư mục thông thường.

Đường dẫn bên trong vùng chứa phụ thuộc vào hình ảnh, vì vậy hãy kiểm tra tài liệu của hình ảnh. Gắn vào đường dẫn sai là một lỗi kinh điển: mọi thứ dường như đều hoạt động nhưng dữ liệu vẫn đang được ghi vào lớp vùng chứa. Các phiên bản chính mới hơn của hình ảnh cũng có thể thay đổi đường dẫn này, vì vậy hãy đọc ghi chú phát hành trước khi nâng cấp.

Docker sẽ tự động tạo một ổ đĩa được đặt tên nếu nó không tồn tại. Một tập ẩn danh, được tạo không có tên, cũng hoạt động nhưng nó có ID ngẫu nhiên dài và rất dễ bị mất dấu. Luôn đặt tên cho các tập của bạn.

Gắn kết

Một liên kết gắn kết ánh xạ một đường dẫn máy chủ cụ thể trực tiếp vào vùng chứa. Cả hai bên đều nhìn thấy các tập tin giống nhau ngay lập tức. Điều này làm cho nó trở nên hoàn hảo cho việc phát triển, vì các chỉnh sửa trong trình soạn thảo của bạn sẽ có hiệu lực trong vùng chứa đang chạy mà không cần xây dựng lại:

docker run -d --name web \
  -p 8080:80 \
  -v "$(pwd)/site:/usr/share/nginx/html:ro" \
  nginx:1.27

Chỉnh sửa tệp trong site/, làm mới trình duyệt và bạn sẽ thấy sự thay đổi. :ro làm cho giá trị gắn kết chỉ đọc bên trong vùng chứa, đây là một thói quen tốt khi vùng chứa không cần phải ghi vào đó.

Giá treo ràng buộc đi kèm với một số đánh đổi:

  • Chúng ràng buộc bạn với máy chủ. Đường dẫn phải tồn tại trên mỗi máy nên việc thiết lập khó có thể di chuyển được.
  • Chúng ẩn nội dung của hình ảnh. Nếu bạn gắn lên /app, bất cứ thứ gì có trong hình ảnh sẽ trở nên vô hình. Một ví dụ phổ biến là node_modules bị mất tích.
  • Chúng làm lộ máy chủ. Một thùng chứa có giá đỡ có thể ghi có thể thay đổi hoặc xóa các tệp máy chủ thực. Không bao giờ gắn các đường dẫn nhạy cảm như / hoặc ổ cắm Docker trừ khi bạn hiểu đầy đủ về rủi ro.
  • Hiệu suất có thể khác nhau. Trên Docker Desktop dành cho macOS và Windows, việc chia sẻ tệp vượt qua ranh giới ảo hóa và có thể chậm hơn so với trên Linux.

gắn kết tmpfs

Giá trị gắn kết tmpfs tồn tại trong bộ nhớ của máy chủ và không bao giờ được ghi vào lớp chứa. Nó biến mất khi vùng chứa dừng lại, vì vậy nó phù hợp với các tệp tạm thời, bộ đệm và dữ liệu nhạy cảm tồn tại trong thời gian ngắn:

docker run -d --tmpfs /app/cache:size=64m myapp:1.0

tmpfs có sẵn trên máy chủ Linux. Nó cũng có thể tăng tốc cơ sở dữ liệu trong môi trường thử nghiệm dùng một lần, nơi bạn không quan tâm đến việc lưu giữ dữ liệu.

-v hay –mount?

Cả hai cờ đều hoạt động. --mount dài hơn nhưng rõ ràng hơn và nhiều người thích nó trong các tập lệnh hơn:

# Short form
docker run -v pgdata:/var/lib/postgresql/data postgres:17

# Explicit form
docker run --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres:17

# Bind mount, read-only
docker run --mount type=bind,source="$(pwd)"/site,target=/usr/share/nginx/html,readonly nginx:1.27

Có một sự khác biệt có ý nghĩa. Với -v, đường dẫn máy chủ bị thiếu sẽ được tạo cho bạn dưới dạng thư mục trống, có thể ẩn lỗi đánh máy. Thay vào đó, với --mount và loại liên kết, Docker sẽ báo lỗi. Ngoài ra, với -v, phía bên trái quyết định loại: tên có nghĩa là ổ đĩa và đường dẫn có nghĩa là liên kết gắn kết. Vì vậy -v data:/x và -v ./data:/x làm những việc rất khác nhau.

Các tập trong Docker Compose

Hầu hết các dự án thực tế đều khai báo bộ nhớ trong tệp Soạn thảo. Cái này sử dụng cả hai loại, mỗi loại cho công việc thích hợp của nó:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src      # bind mount: live code
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: devonly
    volumes:
      - pgdata:/var/lib/postgresql/data   # named volume: data

volumes:
  pgdata:

Các tập được đặt tên phải được khai báo trong phần volumes cấp cao nhất. Soạn tiền tố tên thực tế với tên dự án. Hãy xem hướng dẫn Docker Compose của chúng tôi để biết hướng dẫn đầy đủ.

Mẹo: docker compose down giữ lại các tập được đặt tên nhưng docker compose down -v xóa chúng cùng với dữ liệu của bạn. Hãy đặc biệt cẩn thận về các tập lệnh và lịch sử shell bao gồm -v.

Các lệnh âm lượng hữu ích

Lệnh Nó làm gì
khối lượng docker ls Liệt kê các tập
tên tạo khối lượng docker Tạo một khối lượng
tên kiểm tra khối lượng docker Hiển thị chi tiết, bao gồm cả vị trí của nó
tên khối lượng docker rm Xóa một ổ đĩa và dữ liệu của nó
docker khối lượng mận Loại bỏ các tập đĩa không sử dụng
hệ thống docker df -v Hiển thị việc sử dụng đĩa, bao gồm cả ổ đĩa

Kiểm tra những gì prune sẽ xóa trước khi bạn xác nhận vì thao tác này không thể hoàn tác. Các tập đĩa hiện không có vùng chứa nào sử dụng vẫn có thể chứa dữ liệu quan trọng.

Sao lưu và khôi phục một ổ đĩa

Một ổ đĩa có thể được sao lưu bằng cách chạy một vùng chứa có thời gian sử dụng ngắn để gắn cả ổ đĩa và thư mục máy chủ:

# Back up
docker run --rm \
  -v pgdata:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

# Restore into a new volume
docker volume create pgdata_restored
docker run --rm \
  -v pgdata_restored:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

Đối với cơ sở dữ liệu trực tiếp, việc sao chép các tệp như thế này có thể ghi lại trạng thái không nhất quán. Trước tiên hãy dừng vùng chứa hoặc tốt hơn là sử dụng công cụ riêng của cơ sở dữ liệu, chẳng hạn như pg_dump cho PostgreSQL. Và bản sao lưu mà bạn chưa bao giờ khôi phục thực sự chỉ là hy vọng, vì vậy hãy kiểm tra việc khôi phục.

Quyền tập tin

“Quyền bị từ chối” là vấn đề phổ biến nhất với thú cưỡi. Các tệp giữ ID người dùng và nhóm số của chúng trên Linux, vì vậy nếu một vùng chứa chạy với tư cách người dùng 1000 và thư mục máy chủ thuộc về một người dùng khác thì việc ghi sẽ không thành công. Một số cách để khắc phục điều này:

  • Chạy vùng chứa với người dùng phù hợp: docker run --user "$(id -u):$(id -g)" ...
  • Thiết lập quyền sở hữu chính xác đối với hình ảnh của bạn, như được mô tả trong các phương pháp hay nhất về Dockerfile của chúng tôi.
  • Ưu tiên các ổ đĩa được đặt tên cho dữ liệu, vì ổ đĩa mới sẽ có quyền sở hữu thư mục hình ảnh khi nó được sử dụng lần đầu tiên.
  • Trên các hệ thống sử dụng SELinux, các liên kết gắn kết có thể cần nhãn :z hoặc :Z.

Hãy tránh sự cám dỗ của chmod 777, như hướng dẫn của chúng tôi về các lệnh Linux giải thích.

Bạn nên sử dụng cái nào?

Tình huống sử dụng
Dữ liệu cơ sở dữ liệu Tập được đặt tên
Mã nguồn chỉnh sửa trực tiếp Gắn kết
Tệp cấu hình từ kho lưu trữ của bạn Gắn kết liên kết chỉ đọc
Chia sẻ dữ liệu giữa các container Tập được đặt tên
Bộ đệm tạm thời hoặc tập tin cào tmpfs
Cơ sở dữ liệu thử nghiệm vứt đi tmpfs hoặc không có mount
Mã ứng dụng trong sản xuất Xây dựng nó thành hình ảnh

Hàng cuối cùng quan trọng. Trong quá trình sản xuất, mã thuộc về hình ảnh nên những gì bạn kiểm tra cũng chính là những gì bạn chạy. Trong các cụm, việc lưu trữ dữ liệu lại hoạt động khác đi, thông qua các khối lượng liên tục, được đề cập trong tài liệu Kubernetes rộng hơn. Hướng dẫn Docker vs Kubernetes của chúng tôi giải thích mối liên hệ của cả hai.

Những lỗi thường gặp

  • Gắn sai đường dẫn. Dữ liệu vẫn tồn tại trong lớp vùng chứa và biến mất sau đó.
  • Chạy down -v một cách ngẫu nhiên. Thao tác này sẽ xóa các tập được đặt tên của bạn.
  • Sử dụng các đường dẫn tương đối với -v. Các biểu mẫu như -v data:/x tạo ra một tập thay vì ánh xạ thư mục.
  • Đặt bí mật vào các liên kết gắn kết có thể ghi. Gắn chúng ở chế độ chỉ đọc hoặc sử dụng tính năng bí mật.
  • Trỏ hai vùng chứa cơ sở dữ liệu vào một ổ đĩa. Điều này có thể làm hỏng dữ liệu.
  • Không có bản sao lưu. Ổ đĩa không phải là bản sao lưu. Nó sống trên cùng một đĩa.

Lời kết

Nguyên tắc chung là ngắn gọn: đặt tên cho các ổ đĩa cho dữ liệu, liên kết gắn kết cho mã bạn đang chỉnh sửa và tmpfs cho những thứ không nên tồn tại lâu dài. Hãy thử nó trên cơ sở dữ liệu dùng một lần. Tạo một tập được đặt tên, thêm một hàng, xóa vùng chứa, bắt đầu một vùng mới và xác nhận rằng hàng của bạn vẫn tồn tại. Sau đó thực hành sao lưu và khôi phục trước khi bạn cần.

Câu hỏi thường gặp

Sự khác biệt giữa ổ Docker và giá treo liên kết là gì?

Một ổ đĩa được quản lý bởi Docker và được lưu trữ trong khu vực riêng của nó. Giá đỡ liên kết ánh xạ đường dẫn máy chủ cụ thể mà bạn kiểm soát, trực tiếp vào vùng chứa.

Việc dừng một container có xóa dữ liệu của nó không?

Không. Dữ liệu trong lớp có thể ghi vẫn tồn tại khi dừng và khởi động lại. Nó sẽ bị mất khi vùng chứa được lấy ra, trừ khi nó được lưu trữ trong một ổ đĩa hoặc liên kết gắn kết.

Khối lượng Docker có tồn tại sau khi soạn thảo docker không?

Có, các tập được đặt tên vẫn còn sau khi soạn thảo docker. Việc thêm cờ -v sẽ xóa chúng cùng với mọi dữ liệu chúng chứa.

Khối lượng Docker được lưu trữ ở đâu?

Trên Linux, thường ở dưới /var/lib/docker/volumes. Trên Docker Desktop, chúng sống bên trong một máy ảo. Sử dụng docker Volume Inspection để xem vị trí.

Nhiều container có thể chia sẻ một khối lượng không?

Có, nhiều vùng chứa có thể gắn một tập. Ứng dụng phải xử lý quyền truy cập đồng thời một cách an toàn và cơ sở dữ liệu thường không nên chia sẻ tệp dữ liệu theo cách này.

Tiếp tục học hỏi

Làm việc với Stack Quora

Cần trợ giúp về kiểm tra, WordPress hoặc SEO?

Chúng tôi giúp các nhóm phát triển phần mềm tốt hơn và phát triển trang web của họ. Hãy cho chúng tôi biết bạn đang làm gì và chúng tôi sẽ đề xuất bước tiếp theo rõ ràng.

Tiếp tục đọc

Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại

Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.

Trí tuệ nhân tạo

Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó

Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …

Đọc bài viết →
DevOps

Giải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng

Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…

Đọc bài viết →
Phát triển phần mềm

Giải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429

Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …

Đọc bài viết →
Tự động hóa kiểm thử

Chế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối

Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…

Đọc bài viết →
Kiểm thử phần mềm

Giải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%

Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…

Đọc bài viết →
Cơ sở dữ liệu & SQL

DELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại

DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ

Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…

Đọc bài viết →
Phát triển phần mềm

Giao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch

Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …

Đọc bài viết →
Phát triển phần mềm

Giải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng

Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…

Đọc bài viết →
Phát triển phần mềm

Hàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng

Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …

Đọc bài viết →
Trí tuệ nhân tạo

Đại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy

Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …

Đọc bài viết →
DevOps

Giám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết

Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…

Đọc bài viết →
DevOps

Docker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách

Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …

Đọc bài viết →
Tự động hóa kiểm thử

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…

Đọc bài viết →
Phát triển phần mềm

Git merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào

Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.

Đọc bài viết →
Phát triển phần mềm

List comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh

List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.

Đọc bài viết →
Cơ sở dữ liệu & SQL

Giải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)

Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.

Đọc bài viết →