- vừa được xem lúc

[Kubernetes Series] - Bài 6 - Volume: gắn disk storage vào container

0 0 16

Người đăng: Quân Huỳnh

Theo Viblo Asia

Giới thiệu

Chào các bạn tới với series về kubernetes. Đây là bài thứ 6 trong series của mình, ở các bài trước chúng ta đã nói hết về những resource giúp chúng ta chạy ứng dụng trong môi trường kubernetes như Pod, ReplicaSet. Cách để deploy ứng dụng khi có version mới sử dụng Deployment. Ở bài này chúng ta sẽ nói về Volume, cách để container truy cập được disk storage của node, và là cách để những container chạy chung Pod có thể chia sẻ storage với nhau.

Volume là gì?

Volume hiểu đơn giản chỉ là một mount point từ hệ thống file của server vào bên trong container.

Tại sao ta cần volume thì đối với container, những thứ ta ghi vào filesystem của nó thì chỉ tồn tại khi container còn chạy. Khi một thằng Pod bị xóa và tạo lại, container mới sẽ được tao ra, lúc này thì những thứ ta ghi ở container trước sẽ bị mất đi. Nếu ta muốn giữ lại những dữ liệu đó thì ta phải sử dụng volume.

Trong kubernetes thì sẽ có những loại volume như sau:

  • emptyDir
  • hostPath
  • gitRepo
  • nfs
  • gcePersistentDisk, awsElasticBlockStore, azureDisk (cloud storage)
  • cinder, cephfs, iscsi, flocker, glusterfs, quobyte, rbd, flexVolume, vsphereVolume, photonPersistentDisk, scaleIO
  • configMap, secret, downwardAPI
  • PersistentVolumeClaim

Những loại volume trên được phân chia thành 3 dạng chính:

  • Volume dùng để chia sẻ dữ liệu giữa các container trong Pod
  • Volume đính kèm vào trong filesystem một node
  • Volume đính kèm vào cluster và các node khác nhau có thể truy cập

Chúng ta không cần phải nhớ hết các loại volume, xài tới đâu thì ta google tìm kiếm tới đó. Ta chỉ cần nhớ một vài loại hay sử dụng nhất là emptyDir, hostPath, cloud storage, PersistentVolumeClaim. Các loại secret, downwardAPI, configMap ta sẽ nói ở các bài tiếp.

Khi ta chạy nhiều container trong cùng một Pod thì sẽ có lúc ta phát hiện rằng ta cần các container khác nhau có thể truy cập vào cùng một folder để ghi dữ liệu, và sẽ có những thằng container khác truy cập vào cùng một folder đó để lấy dữ liệu ra sử lý. Ta làm việc đó bằng cách nào? Thì kubernetes có cung cấp cho ta những loại volume khác nhau để làm được việc đó. Đầu tiên là emptyDir.

Sử dụng emptyDir volume để share data giữ các containers

emptyDir là loại volume đơn giản nhất, nó sẽ tạo ra một empty directory bên trong Pod, các container trong một Pod có thể ghi dữ liệu vào bên trong nó. Volume chỉ tồn tại trong một lifecycle của Pod, dữ liệu trong loại volume này chỉ được lưu trữ tạm thời và sẽ mất đi khi Pod bị xóa. Ta dùng loại volume này khi ta chỉ muốn các container có thể chia sẻ dữ liệu lẫn nhau và không cần lưu trữ dữ liệu lại. Ví dụ là dữ liệu log từ một thằng container chạy web API, và ta có một thằng container khác sẽ truy cập vào log đó để xử lý log.

Ta sẽ làm một ví dụ đơn giản cho dễ hiểu hơn, tạo một file emptydir.yaml với config như sau:

apiVersion: v1
kind: Pod
metadata: name: fortune
spec: containers: - name: html-generator image: luksa/fortune volumeMounts: - name: html # The volume called html is mounted at /var/htdocs in the container mountPath: /var/htdocs - name: web-server image: nginx:alpine ports: - containerPort: 80 protocol: TCP volumeMounts: - name: html # The volume called html is mounted at /usr/share/nginx/html in the container mountPath: /usr/share/nginx/html readOnly: true volumes: # define volumes - name: html # name of the volumes emptyDir: {} # define type is emptyDir

Code của script trong container luksa/fortune.

#!/bin/bash
trap "exit" SIGINT
mkdir /var/htdocs while :
do echo $(date) Writing fortune to /var/htdocs/index.html /usr/games/fortune > /var/htdocs/index.html sleep 10
done

Container html-generator này sẽ cứ mỗi 10 giây sẽ tạo ra một nội dung bất kì và lưu nó vào file index.html. Và ta sẽ có một container khác, tên là web-server, sẽ start một server và hosting nội dung ở folder /usr/share/nginx/html (folder mặc định của nginx).

Ở đây ta có một emptyDir volume tên là html, được mount vào container html-generator ở folder /var/htdocs và container html-generator sẽ tạo một file html index.html ở trong emptyDir volume này. Và emptyDir volume này được mount tới container web-server, ở folder /usr/share/nginx/html. Nên khi ta truy cập container web thì ta sẽ thấy được những nội dung mà container html-generator đã tạo ra.

Test xem nó có hoạt động đúng không.

kubectl apply -f emptydir.yaml

kubectl port-forward fortune 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

curl http://localhost:8080

Lưu ý là chỉ dùng emptyDir để chia sẻ dữ liệu giữa những container chứ không dùng để lưu persistent data. Tiếp theo là một loại volume rất hữu ích cho các static website là gitRepo.

Sử dụng gitRepo để clone git repository vào container

gitRepo là loại volume cũng giống emptyDir là sẽ tạo một empty folder, và sau đó nó sẽ clone code của git repository vào folder này.

Ví dụ như sau, tạo một file tên là gitrepo.yaml với config như sau:

apiVersion: v1
kind: Pod
metadata: name: gitrepo-volume-pod
spec: containers: - image: nginx:alpine name: web-server volumeMounts: - name: html mountPath: /usr/share/nginx/html readOnly: true ports: - containerPort: 80 protocol: TCP volumes: - name: html gitRepo: # gitRepo volume repository: https://github.com/luksa/kubia-website-example.git # The volume will clone this Git repository revision: master # master branch directory: . # cloned into the root dir of the volume.

Ở ví dụ này thì html volume được tạo ra với empty folder, sau đó code ở kubia-website-example repository sẽ được clone xuống ở root folder vì ta chỉ định . (dot), volume này được mount vào container web-server ở folder /usr/share/nginx/html. Khi ta truy cập vào Pod, ta sẽ thấy được nội dung static file của kubia-website-example git repository.

Đối với gitRepo volume thì hiện tại không có hỗ trợ private repository, muốn clone được private repository thì ta phải sử dụng một pattern gọi là sidecar containers. Mình sẽ viết một series về kubernetes pattern đển nói về các pattern trong kubernetes, sidecar containers sẽ được mình nói trong series đó sau.

2 loại volume ta vừa nói chỉ được dùng để share data giữ các container, nhưng trong thực tế thì ta lại có nhu cầu rất lớn về việc lưu trữ persistent data, ví dụ như là Pod chạy container database, ta đâu thể để Pod của chúng ta xóa đi là dữ liệu lưu trữ của ta bị mất được, nên kubernetes có cung cấp cho ta các loại volume để lưu trữ persistent data, đầu tiên ta sẽ nói về hostPath volume.

Sử dụng hostPath để truy cập filesystem của worker node

hostPath là loại volume sẽ tạo một mount point từ Pod ra ngoài filesystem của node. Đây là loại volume đầu tiên ta nói mà có thể dùng để lưu trữ persistent data. Dữ liệu lưu trong volume này chỉ tồn tại trên một worker node và sẽ không bị xóa đi khi Pod bị xóa.

Ví dụ như sau:

apiVersion: v1
kind: Pod
metadata: name: hostpath-volume
spec: containers: - image: nginx:alpine name: web-server volumeMounts: - name: html mountPath: /usr/share/nginx/html readOnly: true - name: log # log volume mountPath: /var/log/nginx # mounted at /var/log/nginx in the container ports: - containerPort: 80 protocol: TCP volumes: - name: html gitRepo: # gitRepo volume repository: https://github.com/luksa/kubia-website-example.git # The volume will clone this Git repository revision: master # master branch directory: . # cloned into the root dir of the volume. - name: log hostPath: # hostPath volume path: /var/log # folder of woker node

Ở đây ta sẽ xài lại ví dụ ở trên, và thêm vào một volume tên là log, sẽ được mount tới file system của worker node ở folder /var/log, và volume này sẽ được mount tới container web-server ở folder /var/log/nginx. Lúc này thì tất cả log của container sẽ được lưu trữ ở folder /var/log của worker node.

Đối với loại volume này thì Pod của ta cần phải được tạo đúng worker node thì ta mới có được dữ liệu trước đó, nếu Pod của ta được tạo ở một worker node khác thì chúng ta sẽ mất đi data, loại volume này ta không sử dụng nó cho việc lưu trữ persistent data hoàn toàn được. Cái ta muốn là dù Pod được tạo ở worker node nào thì dữ liệu của ta vẫn có, để mount được vào trong container.

Sử dụng cloud storage để lưu trữ persistent data

Loại volume này chỉ được hỗ trợ trên các nền tảng cloud, giúp ta lưu trữ persistent data, kể cả khi Pod được tạo ở các worker node khác nhau, dữ liệu của ta vẫn tồn tại cho container. 3 nền tảng cloud mà phổ biến nhất là AWS, Goolge Cloud, Azure tương ứng với 3 loại volume là gcePersistentDisk, awsElasticBlockStore, azureDisk.

Thì ở ví dụ này ta sẽ xài Google Cloud, nếu các bạn có tài khoản Google Cloud và có kiến thức về nó rồi thì nên làm theo, còn không thì ta chỉ xem ví dụ cho biết thêm. Ta dùng câu lệnh sau để tạo một Persistent Disk trên google cloud:

gcloud compute disks create --size=1GiB --zone=europe-west1-b mongodb

Tạo một file tên là gcepd.yaml với config như sau:

apiVersion: v1
kind: Pod
metadata: name: mongodb
spec: containers: - image: mongo name: mongodb ports: - containerPort: 27017 protocol: TCP volumeMounts: - name: mongodb-data mountPath: /data/db volumes: - name: mongodb-data gcePersistentDisk: # google cloud disk volume pdName: mongodb # name of the persistent disk on google cloud fsType: ext4

kubectl create -f gcepd.yaml

Ở đây ta sẽ tạo một volume loại gcePersistentDisk với name là mongodb-data và mount nó vào trong container mongodb ở folder /data/db.

Vì loại volume này ta sẽ sử dụng GCE persistent disk, nên nó không thuộc về bất cứ worker node nào mà sẽ nằm riêng lẻ một mình nó. Khi Pod của chúng ta dù được tạo ở bất kì worker node nào thì ta vẫn có thể mount được tới volume này. Và dữ liệu của volume này vẫn được giữ nguyên khi Pod xóa đi.

Để sử dụng volume của cloud storage khác thì ta chỉ cần thay đổi loại volume là được, rất đơn giản, ví dụ như sau:

apiVersion: v1
kind: Pod
metadata: name: mongodb
spec: ... volumes: - name: mongodb-data awsElasticBlockStore: # using AWS ElasticBlockStore instead of gcePersistentDisk pdName: aws-ebs # name of the EBS on AWS fsType: ext4

Bây giờ ta sẽ test thử bằng cách ghi dữ liệu vào trong mongodb-data container, và ta xóa Pod, khi ta tạo Pod lại, ta sẽ thấy dữ liệu của ta vẫn còn ở đó.

$ kubectl exec -it mongodb mongo
MongoDB shell version: 3.2.8
connecting to: mongodb://127.0.0.1:27017
Welcome to the MongoDB shell.
...
> use mystore
switched to db mystore
> db.foo.insert({name:'foo'})
WriteResult({ "nInserted" : 1 })
> db.foo.find()
{ "_id" : ObjectId("57a61eb9de0cfd512374cc75"), "name" : "foo" }

kubectl delete pod mongodb

kubectl create -f gcepd.yaml

$ kubectl exec -it mongodb mongo
MongoDB shell version: 3.2.8
connecting to: mongodb://127.0.0.1:27017
Welcome to the MongoDB shell.
...
> use mystore
switched to db mystore
> db.foo.find()
{ "_id" : ObjectId("57a61eb9de0cfd512374cc75"), "name" : "foo" }

Như chúng ta cần, dữ liệu của chúng ta vẫn còn.

Kết luận

Vậy là ta đã nói xong về một vài loại Volume trong kubernetes. Ta sử dụng volume khi muốn chia sẻ dữ liệu của các container trong Pod và cần lưu trữ persistent data. Cảm ơn các bạn đã đọc bài của mình. Nếu có thắc mắc hoặc cần giải thích rõ thêm chỗ nào thì các bạn có thể hỏi dưới phần comment. Ở bài này ta còn một loại volume nữa là PersistentVolumeClaim, đây là loại hay được sử dụng nhất, mình sẽ nói về nó ở bài tiếp theo.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 525

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 396

- vừa được xem lúc

Đặt tên commit message sao cho "tình nghĩa anh em chắc chắn bền lâu"????

. Lời mở đầu. .

1 1 737

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 358

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 449

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 433