Xin chào! Trong đợt nghiên cứu vừa rồi tại công ty, nhóm mình có được tìm hiểu basic về Docker bao gồm: Docker Daemon, Docker Container, Docker Image, Docker Network, Docker Storage... Riêng mình thì được tìm hiểu sâu hơn về phần Docker Storage nên nay mạo muội viết một bài blog chia sẻ cho các bạn khái quát về Storage - một thành phần vô cùng quan trọng trong kiến trúc Docker.

Vấn đề với Storage trong Docker

Mặc định tất cả các file được tạo ra trong container được chứa ở một lớp gọi là writable container layer . Điều đó có nghĩa rằng:

  • Khi container bị xoá đi, mọi dữ liệu sẽ bốc hơi.
  • Khó có thể lấy data ra khỏi container ra dùng cho các process khác.
  • Khi container chạy, writable layer gắn chặt với máy host nên khó có thể di chuyển data trong lẫn ngoài container.
  • writable layer cần có storage driver để quản lý các file hệ thống, mà các storage driver này cung cấp các filesystem sử dụng Linux kernel. => Làm giảm performance  hệ thống.

Khái quát về Docker Storage

Như các bạn thấy ở trên, rất nhiều vấn đề nhức nhối khi sử dụng storage. Để giải quyết các vấn đề này, Docker đã nghiên cứu và đưa ra một cơ chế tương đối đầy đủ để quản lý data của các container đó là Docker Storage.

Bản chất của Docker Storage là cơ chế cho phép lưu trữ data của các container vào máy host bằng cách mount một folder từ container vào máy host. Điều này giải quyết được các vấn đề nêu trên, đồng thời một số các folder chứa setting hay log có thể được đọc dễ dàng hơn trong quá trình troubleshoot.

Syntax khai báo

  • -v(--volume): syntax này thường được sử dụng cho các container đơn lẻ, tất cả các tuỳ chọn trong một trường, ngăn cách bởi dấu :.

Ví dụ:

docker run -d --name=nginxtest -v nginx-vol:/usr/share/nginx/html nginx:latest
  • --mount: thường được dùng cho swarm service, chia các tuỳ chọn ra theo các cặp <key>=<value> và ngăn cách nhau bởi dấu , .

Ví dụ:

docker run -d --name=nginxtest --mount source=nginx-vol,destination=/usr/share/nginx/html nginx:latest

Ban đầu -v hoặc –volume flag được dùng cho standalone container và –mount flag được dùng cho swarm services. Tuy nhiên từ phiên bản Docker 17.06 bạn có thể sử dụng –mount flag cho standalone container. Nói chung điểm khác biệt duy nhất chính là là cú pháp và  sở thích :v . Trong khi  -v yêu cầu phải khai báo đúng thứ tự, thì --mount lại linh hoạt, không cần thứ tự. Tuy nhiên cú pháp của --mount lại tương đối dài dòng, gõ khá mệt.

Các kiểu mount của Docker Storage

Có 3 kiểu mount chính đó là:

  • volumes: data được chứa trong filesystem của máy host quản lý bởi Docker.
  • bind mounts: data có thể nằm ở bất kỳ đâu trên máy host, không được quản lý bởi Docker.
  • tmpfs: data được chứa ở memory của máy host, không được lưu trữ ở  hệ thống file của máy chủ. Data sẽ mất đi khi container bị dừng hay xoá đi.

Mặc dù chúng ta có chọn kiểu mount nào đi chăng nữa, data trong container vẫn không bị biến đổi, tồn tại dưới dang file và thư mục trong filesystem của container. Giờ chúng ta cùng tìm hiểu chi tiết hơn đối với từng kiểu mount nhé.

bind mounts

bind mounts xuất hiện rất sớm cùng với Docker, nó có hiệu năng tốt do phụ thuộc vào cấu trúc filesystem của máy host. Với bind mounts, file và thư mục được mount từ máy host vào container, sử dụng đường dẫn tuyệt đối và data có thể được lưu trữ bất cứ ở đâu trên máy chủ. Chúng ta không bắt buộc phải mount với một thư mục không tồn tại. Nếu mount dữ liệu tới một thư mục không tồn tại, nó sẽ tự động được tạo ra theo yêu cầu.

Có một số điểm cần lưu ý khi sử dụng với bind mounts như sau:

  • Khi mount từ host với một folder có chứa dữ liệu trong container, dữ liệu trong container hiện có sẽ bị ẩn đi cho tới khi liên kết này bị unmount.
  • Một điều không biết là tốt hay xấu khi sử dụng bind mounts, đó là chúng ta có thể chỉnh sửa, thêm mới, xoá các system files và directories trong quá trình sử dụng container. Đây là một tính năng liên quan đến bảo mật, liên quan đến tác động của các Docker non-process tới các file hệ thống. Vì vậy các bạn nên hết sức cẩn thận khi mount folder là một directory hay file quan trọng.

Với các tính năng trên, bind mounts rất phù hợp, tiện lợi khi:

  • Chia sẻ các file cấu hình từ docker host tới container.
  • Chia sẻ các thư mục source code hoặc môi trường từ docker host với container.
  • Chia sẻ dữ liệu khi cấu trúc filesystem của docker host là rõ ràng và phù hợp với các yêu cầu của bind mount.

Tuy nhiên, bind mounts không phải là không có các điểm yếu. Cùng kể ra một vài điểm yếu nào:

  • bind mounts chỉ dừng lại ở việc synced folder.
  • Sử dụng đường dẫn tuyệt đối khiến cho việc di chuyển dữ liệu khó khăn và ảnh hưởng tới container khi muốn di rời data.
  • Không sử dụng được Docker CLI.
  • Có thể chỉnh sửa System file, như mình đã nói ở trên :D.

volumes

Volumes là phiên bản cải tiến cho bind mounts, và bản chất của nó cũng tương tự so với bind mounts, nhưng được quản lý Docker. Vì vậy, chỉ những process của Docker mới có thể can thiệp được vào thư mục mount này. Mount giữa host và container được gọi là một volume. Và data được lưu trữ tại Docker area ( trên Linnux là /var/lib/docker/volumes/ ) Chúng ta có thể tạo volume tronng lúc tạo container hoặc service hoặc sử dụng câu lệnh docker volume create bằng Docker CLI.

Có thể kể ra rất nhiều điểm vượt trội của volumes so với bind mounts:

  • Dễ backup, restore và migrate.
  • Chúng ta có thể quản lý thêm, sửa, xoá volume sử dụng Docker CLI  hoặc Docker API.
  • Sử dụng được trên cả Linux và Windows.
  • Do được quản lý bằng CLI nên dễ quản lý  hơn và dễ dàng chia sẻ volume cho các container khác.
  • Một ưu điểm vượt trội đó là thay vì store volumes trong  /var/lib/docker/volumes/ , ta có thể store thẳng volume lên remote host hoặc cloud.
  • Sử dụng volume không làm tăng dung lượng của container sử dụng vì nó nằm ngoài lifecycle của container.

Một số chú ý khi sử dụng volumes:

  • Nếu mount một volume vào trong một thư mục của container, mà thư mục của container này đã có dữ liệu thì dữ liệu từ container sẽ được copy vào volume của docker host.
  • Thông thường nếu không tạo volume từ trước mà chạy container với volume mount thì Docker sẽ tự động tạo một volume và dữ liệu sẽ vẫn tồn tại ngoài vòng đời của container.
  • Khi container bị xoá đi thì volume vẫn tồn tại.

Với những tiện lợi kể trên, volumes được sử dụng rất nhiều và được Docker recommend sử dụng thay thế cho bind mounts.  Volumes được sử dụng trong việc:

  • Chia sẻ data giữa các container (rõ ràng).
  • Lưu dữ liệu tới một remote server hoặc cloud để chia sẻ với các host khác.
  • Khi cần backup, restore hoặc migrate dữ liệu từ docker host này sang docker host khác.
  • Làm những thứ mà bind mounts không thể làm được :D.

tmpfs

Nếu volumesbind mounts giúp bạn chia sẻ file giữa host và container thì tmpfs khá là dị biệt. Khi sử dụng container với kiểu mount là tmpfs, data sẽ không được lưu vào lớp writable layer, cũng không được lưu vào filesystem của máy host, mà được lưu thẳng vào memory. Và khi container chỉ cần ngừng thôi, thì data cũng sẽ mất luôn.

Với tmpfs, có một vài chú ý sau:

  • Mang tính chất tạm thời, không thể share mount giữa các container.
  • Chỉ sử dụng được khi host là Linux.

Với tính cách khá "dị" của mình, tmpfs được sử dụng để:

  • Tạm thời chứa các file "nhạy cảm" mà bạn không muốn duy trì trong máy host hoặc container layer.
  • Khi bạn muốn bảo mật, hoặc muốn đảm bảo hiệu suất container khi ứng dụng cần ghi một số lượng lớn dữ liệu không liên tục.

Lời kết

Bài viết trên mình đã nói khái quát về Docker Storage cũng như về 3 kiểu mount của nó. Hy vọng bài viết giúp bạn tóm lược lại các đặc điểm chính về storage trong Docker. Hẹn gặp lại các bạn trong các bài viết sau!