Certified Kubernetes Administrator (CKA) with Practice Tests - Phần 7: Storage
Table of contents
Storage in Docker
Khi bạn cài đặt Docker trên một hệ thống, nó sẽ tạo ra cấu trúc thư mục này tại /var/lib/docker/
. Nó chứa nhiều thư mục bên trong, được gọi là AUFS, containers, images, volumes, v.v. Đây là nơi Docker lưu trữ toàn bộ dữ liệu của nó theo mặc định.
Tất cả các tệp liên quan đến containers được lưu trữ trong thư mục containers
, và các tệp liên quan đến images được lưu trữ trong thư mục image
. Bất kỳ volume nào được tạo bởi các container Docker sẽ được lưu trữ trong thư mục volumes
.
Mỗi dòng lệnh trong tệp Dockerfile tạo ra một lớp mới (layer) trong Docker image, chỉ chứa những thay đổi so với lớp trước đó.
Vì mỗi lớp (layer) chỉ lưu trữ các thay đổi so với lớp trước đó, điều này cũng được thể hiện qua kích thước của image. Nếu bạn nhìn vào image Ubuntu cơ bản, kích thước của nó khoảng 120 MB. Các gói APT mà tôi cài đặt có kích thước khoảng 300 MB, và các lớp còn lại thì nhỏ hơn. Để hiểu rõ hơn về lợi ích của kiến trúc phân lớp này, hãy xem xét một ứng dụng thứ hai.
Ứng dụng này có một Dockerfile khác nhưng rất giống với ứng dụng đầu tiên của chúng ta, vì nó sử dụng cùng base image là Ubuntu, sử dụng các dependency Python và Flask giống nhau, nhưng lại sử dụng mã nguồn khác để tạo ra một ứng dụng khác. Do đó, điểm entry point (entry point) của nó cũng khác.
Khi tôi chạy lệnh docker build
để tạo một image mới cho ứng dụng này, vì ba lớp đầu tiên của cả hai ứng dụng là giống nhau, Docker sẽ không xây dựng lại ba lớp đầu tiên. Thay vào đó, nó tái sử dụng ba lớp đã được xây dựng cho ứng dụng đầu tiên từ bộ nhớ cache. Docker chỉ tạo hai lớp cuối cùng với mã nguồn mới và entry point mới.
Tất cả các lớp này được tạo ra khi chúng ta chạy lệnh docker build
để tạo thành Docker image cuối cùng. Vì vậy, tất cả những lớp này đều là các lớp của Docker image.
Khi quá trình build hoàn thành, bạn không thể thay đổi nội dung của các lớp này. Vì vậy, chúng là chỉ đọc (read-only) và bạn chỉ có thể thay đổi chúng bằng cách khởi động một quá trình build mới.
Khi bạn chạy một container dựa trên image này bằng lệnh docker run
, Docker sẽ tạo một container dựa trên các lớp này và tạo một writable layer mới ở phía trên các lớp của image. Writable layer được sử dụng để lưu trữ dữ liệu do container tạo ra, chẳng hạn như tệp log do các ứng dụng ghi, các tệp tạm thời được tạo ra bởi container, hoặc bất kỳ tệp nào bị sửa đổi bởi người dùng trên container đó.
Tuy nhiên, vòng đời của lớp này chỉ kéo dài trong suốt thời gian container sống. Khi container bị hủy, lớp này và tất cả các thay đổi lưu trữ trong đó cũng sẽ bị hủy.
Chúng ta có thể thêm một persistent volume vào container. Để làm điều này, đầu tiên hãy tạo một volume bằng lệnh:
$ docker volume create data_volume
Sau đó, khi tôi chạy container Docker bằng lệnh docker run
, tôi có thể mount volume này vào lớp ghi của container bằng cách sử dụng tùy chọn -v
như sau:
$ docker run -v data_volume:/var/lib/mysql mysql
Điều này sẽ tạo ra một container mới và mount volume dữ liệu mà chúng ta đã tạo vào thư mục /var/lib/mysql
bên trong container. Vì vậy, tất cả dữ liệu được ghi bởi cơ sở dữ liệu thực tế sẽ được lưu trữ trên volume được tạo ra trên Docker host. Ngay cả khi container bị xóa, dữ liệu vẫn sẽ được duy trì và vẫn hoạt động.
Volumes
Để lưu trữ dữ liệu được xử lý bởi các container, chúng ta gắn một volume vào các container khi chúng được tạo.
Dữ liệu được xử lý bởi container sẽ được lưu trữ trong volume này, do đó nó được giữ lại vĩnh viễn. Ngay cả khi container bị xóa, dữ liệu được tạo hoặc xử lý bởi container vẫn tồn tại.
Các pod được tạo trong Kubernetes mang tính tạm thời theo bản chất. Khi một pod được tạo ra để xử lý dữ liệu và sau đó bị xóa, dữ liệu được xử lý bởi pod đó cũng bị xóa theo. Để khắc phục điều này, chúng ta gắn một volume vào pod. Dữ liệu được tạo ra bởi pod sẽ được lưu trữ trong volume, và ngay cả khi pod bị xóa, dữ liệu vẫn được giữ lại.
Hãy cùng xem một triển khai đơn giản về volumes. Chúng ta có một cluster Kubernetes với một nút duy nhất. Chúng ta tạo một pod đơn giản, pod này sẽ tạo ra một số ngẫu nhiên từ 1 đến 100 và ghi nó vào một tệp.
Sau đó, pod sẽ bị xóa cùng với số ngẫu nhiên đã tạo. Để giữ lại số được tạo bởi pod, chúng ta tạo một volume và một volume cần có dung lượng lưu trữ. Khi tạo một volume, bạn có thể chọn cấu hình dung lượng lưu trữ của nó theo nhiều cách khác nhau. Chúng ta sẽ xem xét các tùy chọn khác nhau sau, nhưng hiện tại, chúng ta sẽ cấu hình nó để sử dụng một thư mục trên máy chủ.
apiVersion: v1
kind: Pod
metadata:
name: random-number-generator
spec:
containers:
- image: alpine
name: alpine
command: ["/bin/sh","-c"]
args: ["shuf -i 0-100 -n 1 >> /opt/number.out;"]
volumeMounts:
- mountPath: /opt
name: data-volume
volumes:
- name: data-volume
hostPath:
path: /data
type: Directory
Bằng cách này, mọi tệp được tạo trong volume sẽ được lưu trữ trong thư mục data
trên nút của tôi. Khi volume đã được tạo, để truy cập nó từ một container, chúng ta gắn volume vào một thư mục bên trong container. Chúng ta sử dụng trường volumeMounts
trong mỗi container để gắn volume dữ liệu vào thư mục trong container.
Persistent Volumes
Khi chúng ta tạo volumes, chúng ta cấu hình volumes trong tệp định nghĩa pod, vì vậy mọi thông tin cấu hình cần thiết để cấu hình lưu trữ cho volume đều được đưa vào trong tệp định nghĩa pod.
Bây giờ, khi bạn có một môi trường lớn với nhiều người dùng triển khai nhiều pod, người dùng sẽ phải cấu hình lưu trữ mỗi lần cho từng pod. Dù sử dụng giải pháp lưu trữ nào, người dùng triển khai các pod sẽ phải cấu hình điều đó trong tất cả các tệp định nghĩa pod trong môi trường của mình.
Mỗi khi có thay đổi cần thực hiện, người dùng sẽ phải thực hiện chúng trên tất cả các pod của mình. Thay vào đó, bạn sẽ muốn quản lý lưu trữ một cách tập trung hơn. Bạn muốn nó được cấu hình sao cho một quản trị viên có thể tạo ra một kho lưu trữ lớn và sau đó để người dùng chia nhỏ các phần từ kho lưu trữ đó khi cần thiết. Đó chính là nơi mà persistent volumes có thể giúp chúng ta.
Một persistent volume là một kho lưu trữ toàn cụm được cấu hình bởi quản trị viên để sử dụng bởi người dùng triển khai ứng dụng trên cụm. Người dùng giờ đây có thể chọn lưu trữ từ kho này bằng cách sử dụng persistent volume claims.
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-vol1
spec:
accessModes:
- ReadWriteOne
capacity:
storage: 1Gi
hostPath:
path: /tmp/data
Persistent Volume Claims
Persistent Volumes và Persistent Volume Claims là hai đối tượng riêng biệt trong không gian tên của Kubernetes. Quản trị viên tạo ra một tập hợp các persistent volumes, và người dùng tạo persistent volume claims để sử dụng lưu trữ.
Khi persistent volume claims được tạo ra, Kubernetes sẽ liên kết các persistent volumes với các claims dựa trên yêu cầu và các thuộc tính được thiết lập trên volume. Mỗi Persistent Volume Claim sẽ được liên kết với một Persistent Volume duy nhất. Trong quá trình liên kết, Kubernetes cố gắng tìm một Persistent Volume có dung lượng đủ lớn như yêu cầu của claim. Và bất kỳ thuộc tính yêu cầu nào khác, chẳng hạn như các chế độ truy cập (access modes), chế độ volume (volume modes), lớp lưu trữ (storage class), v.v.
Bạn muốn sử dụng một volume cụ thể, bạn vẫn có thể sử dụng nhãn (labels) và bộ chọn (selectors) để liên kết với các volume phù hợp.
Nếu không có volume nào có sẵn, persistent volume claim sẽ ở trạng thái pending cho đến khi các volume mới được cung cấp cho cụm. Khi các volume mới có sẵn, claim sẽ tự động được liên kết với volume mới đó.
Định nghĩa PersistentVolumeClaim:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
apiVersion: v1
kind: Pod
metadata:
name: webapp
spec:
containers:
- name: event-simulator
image: kodekloud/event-simulator
env:
- name: LOG_HANDLERS
value: file
volumeMounts:
- mountPath: /log
name: log-volume
volumes:
- name: log-volume
persistentVolumeClaim:
claimName: claim-log-1
Subscribe to my newsletter
Read articles from Phan Văn Hoàng directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by