Khi làm việc trên Docker, một công cụ mã nguồn mở hỗ trợ đóng gói ứng dụng phần mềm bạn sẽ bắt gặp thuật ngữ Docker Container – một run-time enviroment cho phép người dùng chạy ứng dụng độc lập. Trong quá trình thao tác với Docker Container chắc hẳn bạn sẽ cần thiết chia sẻ dữ liệu giữa các Docker Container với nhau. Bài viết này, Vietnix sẽ hướng dẫn bạn cách chia sẻ dữ liệu giữa các Docker Containers nhanh chóng nhất.
Giới thiệu tổng quan về Docker
Docker được biết đến là một phần mềm đóng gói ứng dụng được các lập trình viên sử dụng rất phổ biến. Docker cung cấp cho các ứng dụng phần mềm một hệ thống các file chứa tất cả những gì cần để khởi chạy. Trong đó, việc sử dụng Docker Container sẽ giúp cho phần mềm hoạt động độc lập mà không phụ thuộc vào vị trí triển khai bởi run-time environment của nó là nhất quán.
Nói chung, các Docker Container đều mang tính tạm thời, chỉ chạy trong khoảng thời gian lệnh được thực hiện trong container cho đến khi hoàn tất. Tuy nhiên, nhiều khi các ứng dụng sẽ cần chia sẻ truy cập dữ liệu hoặc lưu trữ dữ liệu sau khi một container bị xóa.
Cơ sở dữ liệu, nội dung được tạo bởi người dùng cho một website và log files là một vài ví dụ về dữ liệu không có thực hoặc không có trong Docker Image nhưng ứng dụng cần truy cập đến. Bạn sẽ cần sử dụng Docker Volumes để truy cập liên tục vào dữ liệu được cung cấp.
Docker Volumes có thể được tạo và đính kèm cùng lệnh tạo container hoặc được tạo độc lập với một container khác.
Yêu cầu để thực hiện được cách chia sẻ dữ liệu giữa các Docker Containers
Để thực hiện được thao hướng dẫn dưới đây, bạn cần chuẩn bị một server Ubuntu 20.04 với các yêu cầu sau:
- Một non-root user với đặc quyền truy cập sudo.
- Cài sẵn Docker trên máy chủ.
Lưu ý, các lệnh docker
cho Docker data volumes trong hướng dẫn dưới đây nên hoạt động trên các system khác miễn là đã cài sẵn Docker và sudo user đã được thêm vào nhóm user.
Cài đặt Docker trên VPS là một gợi ý hoàn hảo cho những ai muốn triển khai các ứng dụng trên môi trường ảo hóa. Ngoài ra, nó còn có thể giúp bạn quản lý và triển khai các ứng dụng một cách hiệu quả hơn. Vietnix hiện đang cung cấp dịch vụ VPS tốc độ cao với mức giá phải chăng, giúp bạn chủ động cài đặt và quản lý ứng dụng.
Nhanh tay liên hệ Vietnix để được tư vấn gói VPS phù hợp với nhu cầu phát triển ngay hôm nay.
Hướng dẫn các bước chia sẻ dữ liệu giữa các Docker Container
Để có thể chia sẻ dữ liệu giữa các Docker Container, bạn thực hiện theo 4 bước dưới đây.
Bước 1: Tạo một Independent Volume
Như đã được giới thiệu ở phiên bản 1.9 của Docker, lệnh docker volume creat
cho phép bạn tạo một volume mà không phụ thuộc bất kỳ container nào. Bạn sẽ sử dụng lệnh này để thêm một volume có tên là DataVolume1
:
$ docker volume create --name DataVolume1
Khi tên volume được hiển thị có nghĩa là lệnh trên đã chạy thành công.
Output
DataVolume1
Để sử dụng volume này, bạn cần tạo một container mới từ Ubuntu image. sử dụng flag --rm
để tự động xóa nó đi khi bạn thoát ra. Bạn cũng sẽ sử dụng -v
để gắn volume mới. -v
yêu cầu tên của volume, dấu hai chấm và sau đó là đường dẫn chính xác đến nơi volume sẽ xuất hiện trong container. Nếu các thư mục trong đường dẫn không tồn tại như một phần của image, chúng sẽ được tạo khi khởi chạy lệnh. Nếu chúng tồn tại, volume được gắn sẽ ẩn nội dung hiện có đi.
$ docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu
Trong container, bạn hãy viết một số dữ liệu vào volume:
root@802b0a78f2ef:/# echo "Example1" > /datavolume1/Example1.txt
Do bạn đã sử dụng flag --rm
, container của bạn sẽ tự động xóa khi bạn thoát ra. Tuy nhiên, volume của bạn vẫn có thể truy cập được.
root@802b0a78f2ef:/# exit
Bạn có thể xác nhận rằng volume đã có trên hệ thống bằng cách sử dụng docker volume inspect
:
$ docker volume inspect DataVolume1
Output
[
{
"CreatedAt": "2018-07-11T16:57:54Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/DataVolume1/_data",
"Name": "DataVolume1",
"Options": {},
"Scope": "local"
}
]
Lưu ý, bạn hoàn toàn có thể xem dữ liệu trên server tại đường dẫn được liệt kê là Mountpoint
. Tuy nhiên bạn nên tránh làm thay đổi chúng, bởi việc này có thể gây ra lỗi thất thoát dữ liệu nếu các ứng dụng hoặc container không nhận thức được sự thay đổi đó.
Tiếp theo, bạn hãy khởi động một container mới và gắn DataVolume1
:
$ docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu
Xác minh các nội dung:
root@d73eca0365fc:/# cat /datavolume1/Example1.txt
Output
Example1
Thoát container:
root@d73eca0365fc:/# exit
Với bước thực hiện ở trên, bạn đã tạo xong một volume, gắn volume này với một container và xác nhận lại thông tin sau khi hoàn tất
Bước 2: Tạo một Volume khi Container bị xóa
Trong bước tiếp theo, bạn cần tạo một volume đồng thời với container, sau đó xóa container đó đi và gắn volume vào một container mới.
Bạn sử dụng lệnh docker run
để tạo một container mới sử dụng Ubuntu image cơ bản. Flag -t
sẽ cung cấp cho bạn một terminal và flag -i
cho phép bạn tương tác với terminal. Để rõ hơn, bạn sử dụng --name
để xác định container.
Flag -v
cho phép bạn tạo một volume mới, được đặt là DataVolume2
. Sử dụng dấu hai chấm để tách tên này từ đường dẫn gắn volume trong container. Cuối cùng, bạn chỉ định Ubuntu image cơ bản và phụ thuộc lệnh mặc định trong tệp Docker của Ubuntu image cơ bản, bash
để truy cập shell:
$ docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu
Lưu ý, flag -v
rất linh hoạt, có thể liên kết hoặc đặt tên cho một volume chỉ với một vài điều chỉnh trong cú pháp. Nếu đối số đầu tiên bắt đầu bằng /
hoặc ~/
, có nghĩa là bạn đang tạo một volume. Hãy loại bỏ nó đồng nghĩa với việc bạn đang đặt tên cho volume. Ví dụ:
-v /path:/path/in/container
gắn với thư mục máy chủ,/path
tại/path/in/container
-v path:/path/in/container
đồng nghĩa với việc tạo một volume có tênpath
và nó không có mối quan hệ nào với máy chủ.
Khi đó, trong container, bạn viết một số dữ liệu vào volume:
root@87c33b5ae18a:/# echo "Example2" > /datavolume2/Example2.txt
cat /datavolume2/Example2.txt
Output
Example2
Bây giờ, bạn thoát khỏi container:
root@87c33b5ae18a:/# exit
Khi bạn khởi động lại container, volume sẽ tự động kết nối:
$ docker start -ai Container2
Bạn sử dụng câu lệnh sau đây để xác định rằng volume đã được kết nối và dữ liệu của bạn vẫn còn đó:
root@87c33b5ae18a:/# cat /datavolume2/Example2.txt
Output
Example2
Cuối cùng, bạn thoát ra và dọn dẹp lại:
root@87c33b5ae18a:/# exit
Docker sẽ không cho phép bạn xóa một volume nếu volume đó đang được một container sử dụng. Nếu bạn thử xóa chúng, hãy quan sát thông báo trả về:
$ docker volume rm DataVolume2
Thông báo trả về sẽ cho bạn biết rằng volume vẫn đang được sử dụng và cung cấp ID của container:
Output
Error response from daemon: unable to remove volume: remove DataVolume2: volume is in use - [d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63]
Bạn có thể sử dụng ID trên để xóa container:
$ docker rm d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
Output
d0d2233b668eddad4986313c7a4a1bc0d2edaf0c7e1c02a6a6256de27db17a63
Việc xóa container sẽ không làm ảnh hưởng đến volume. Bạn có thể thấy nó vẫn tồn tại trên hệ thống bằng cách liệt kê các volume với lệnh docker volume ls
:
$ docker volume ls
Output
DRIVER VOLUME NAME
local DataVolume2
Bạn có thể sử dụng lệnh docker volume rm
để xóa volume:
$ docker volume rm DataVolume2
Ở bước này, bạn đã tạo một volume trống đồng thời khi tạo một container. Bước tiếp theo, bạn sẽ được hướng dẫn những vấn đề liên quan khi tạo một volume với một container đã có sẵn dữ liệu.
Bước 3: Tạo một volume từ một Existing Directoty có dữ liệu
Việc tạo một volume độc lập với docker volume create
và tạo một volume khi tạo một container là tương tự nhau kèm theo một ngoại lệ. Nếu bạn tạo một volume cùng lúc với container và cung cấp đường dẫn đến thư mục chứa dữ liệu trong image gốc thì dữ liệu đó sẽ được sao chép vào volume.
Ví dụ, bạn tạo một container và thêm dữ liệu volume tại /var
– một thư mục chứa dữ liệu trong image gốc:
$ docker run -ti --rm -v DataVolume3:/var ubuntu
Tất cả dữ liệu trong thư mục /var
của image gốc được sao chép vào volume và bạn có thể gắn volume đó vào một container mới.
Bạn thoát container hiện tại:
root@87c33b5ae18a:/# exit
Bây giờ, thay vì việc dựa vào lệnh bash
mặc định của image gốc, bạn sẽ phải dùng đến lệnh ls
của mình để hiển thị nội dung của volume mà không cần nhập shell:
$ docker run --rm -v DataVolume3:/datavolume3 ubuntu ls datavolume3
Thư mục datavolume3
hiện có một bản sao nội dung từ thư mục /var
của image gốc:
Output
backups
cache
lib
local
lock
log
mail
opt
run
spool
tmp
Cách này không thể giúp bạn gắn /var
nhưng có thể hữu ích nếu bạn đã tạo ra image của chính mình và muốn lưu trữ dữ liệu một cách dễ dàng. Ví dụ tiếp theo sẽ hướng dẫn bạn cách để một volume có thể được chia sẻ giữa nhiều container.
Bước 4: Chia sẻ dữ liệu giữa nhiều Docker Container
Các ví dụ trên thực hiện gắn một volume vào một container. Thông thường, bạn sẽ cần nhiều container đi kèm với cùng một volume. Điều này tương đối đơn giản, tuy nhiên bạn cần lưu ý rằng hiện tại docker không xử lý khóa tập tin. Nếu bạn cần nhiều container ghi vào volume, các ứng dụng chạy trong những container đó phải được thiết kế để ghi vào các cơ sở dữ liệu được chia sẻ để tránh mất mát dữ liệu.
Tạo Container4 và DataVolume4
Sử dụng lệnh docker run
để tạo một container mới có tên là Container4
và kết nối một dữ liệu volume:
$ docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu
Tiếp theo bạn tạo một tệp và thêm đoạn text:
root@db6aaead532b:/# echo "This file is shared between containers" > /datavolume4/Example4.txt
Sau đó, bạn thoát khỏi container:
root@db6aaead532b:/# exit
Bước này sẽ đưa bạn quay lại với dấu nhắc lệnh của máy chủ, tại đây bạn sẽ tạo một container mới với vai trò mount dữ liệu volume từ Container4
.
Tạo Container5 và mount các volume từ Container4
Bạn tạo Container5
và mount các volume từ Container4
:
$ docker run -ti --name=Container5 --volumes-from Container4 ubuntu
Kiểm tra tính liên tục của dữ liệu:
root@81e7a6153d28:/# cat /datavolume4/Example4.txt
Output
This file is shared between containers
Bạn thêm một đoạn text từ Container5
:
root@81e7a6153d28:/# echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt
Cuối cùng, bạn thoát ra khỏi container:
root@81e7a6153d28:/# exit
Tiếp theo, bạn cần kiểm tra lại dữ liệu có trong Container4
.
Xem các thay đổi được thực hiện trong Container5
Bạn kiểm tra lại xem các thay đổi đã được ghi vào dữ liệu volume bởi Container5
chưa bằng cách khởi động lại Container4
:
$ docker start -ai Container4
Kiểm tra các thay đổi:
root@db6aaead532b:/# cat /datavolume4/Example4.txt
Output
This file is shared between containers
Both containers can write to DataVolume4
Khi bạn đã xác minh được cả hai container đều có thể đọc và ghi dữ liệu từ dữ liệu volume, bạn thoát khỏi container:
root@db6aaead532b:/# exit
Bạn cần nhớ rằng Docker không xử lý bất kỳ file lock nào, do đó các ứng dụng phải tự xử lý file lock. Bạn có thể mount một Docker volume bằng cách chỉ cho quyền đọc dữ liệu để bảo đảm rằng sự cố mất mát dữ liệu sẽ không xảy ra khi một container yêu cầu quyền truy cập read-only bằng cách thêm :ro
.
Bắt đầu Container 6 và mount Volume Read-Only
Sau khi một volume đã mount với một container, thay vì unmount nó như thường làm với hệ thống Linux thông thường, bạn có thể tạo một container mói được mount theo cách bạn muốn, nếu cần bạn loại bỏ container trước đó. Để tạo volume read-only, bạn ủ dụng :ro
ỏ cuối tên container:
$ docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu
Bạn kiểm tra trạng thái read-only bằng cách thử xóa file ví dụ của bạn:
root@81e7a6153d28:/# rm /datavolume4/Example4.txt
Output
rm: cannot remove '/datavolume4/Example4.txt': Read-only file system
Cuối cùng, bạn thoát khỏi container và dọn dẹp các container và volume ví dụ trên:
root@81e7a6153d28:/# exit
Như vậy, bạn đã hoàn thành các bước, bạn dọn dẹp các container và volume của mình.
$ docker rm Container4 Container5 Container6
$ docker volume rm DataVolume4
Trong ví dụ này, bạn đã thực hiện xong cách chia sẻ dữ liệu giữa hai container bằng cách sử dụng data volume và cách mount data volume dưới dạng read-only.
Lời kết
Như vậy, Vietnix đã hướng dẫn cho bạn cách tạo một data volume cho phép dữ liệu tồn tại thông qua việc xóa container. Với cách này, bạn có thể chia sẻ data volume giữa các container với điều kiện ứng dụng đã thiết lập có thể xử lý file lock để ngăn việc mất mát dữ liệu. Cuối cùng, bạn có thể mount một data volume chia sẻ dưới chế độ read-only. Hy vọng những thông tin này sẽ giúp ích cho bạn trong công việc phát triển và triển khai ứng dụng của mình một cách hiệu quả nhất.