1. Tổng quan.
Redis là hệ thống lưu trữ dữ liệu key-value, Kubernetes là một nền tảng quản lý và triển khai ứng dụng trong các containers, và Helm là một công cụ giúp quản lý và cài đặt các ứng dụng trên Kubernetes bằng cách sử dụng các gói gọi là charts.
- Kubernetes: Kubernetes là một nền tảng mã nguồn mở dùng để quản lý và triển khai các ứng dụng được đóng gói trong các containers. Nó giúp tự động hóa việc triển khai, mở rộng và quản lý các ứng dụng. Kubernetes cung cấp các khả năng như việc quản lý tài nguyên, cân bằng tải, phục hồi tự động, và khả năng mở rộng linh hoạt.
- Helm: Helm là một công cụ quản lý gói và cài đặt ứng dụng trên Kubernetes. Nó cho phép bạn đóng gói ứng dụng vào các gói được gọi là “charts” để dễ dàng chia sẻ và cài đặt. Mỗi chart bao gồm các file mô tả tài nguyên Kubernetes (ví dụ: deployments, services, configmaps) và các giá trị cấu hình tùy chỉnh (values) cho các ứng dụng. Helm giúp đơn giản hóa việc quản lý và cài đặt ứng dụng trên Kubernetes.
- Redis: Redis là một hệ thống lưu trữ dữ liệu cơ bản dựa trên cấu trúc dữ liệu key-value. Nó thường được sử dụng để lưu trữ dữ liệu tạm thời, cache, thông tin phiên, và nhiều ứng dụng khác. Redis hỗ trợ nhiều loại dữ liệu như strings, hashes, lists, sets, sorted sets và nhiều chức năng khác. Nó nổi tiếng với hiệu suất cao và khả năng mở rộng.
2. Redis Cluster là gì?
Redis Cluster: là một tính năng của Redis cho phép bạn triển khai và quản lý một cụm (cluster) các máy chủ Redis để cải thiện khả năng sẵn sàng, hiệu suất và khả năng mở rộng của hệ thống. Redis Cluster giúp bạn chia dữ liệu thành nhiều mảng, gọi là “slots,” và phân phối chúng trên các node khác nhau trong cụm.
Một số điểm quan trọng về Redis Cluster:
- Phân chia dữ liệu: Dữ liệu được chia thành nhiều slots (khoảng 16384 slots) và phân phối đều đặn trên các node trong cụm.
- Sẵn sàng và sao lưu: Redis Cluster cung cấp khả năng sao lưu dữ liệu trên nhiều node, giúp đảm bảo sẵn sàng và khả năng khôi phục dữ liệu khi có sự cố.
- Hiệu suất: Khi tăng số lượng node, Redis Cluster có thể cân bằng tải tự động để tối ưu hiệu suất của hệ thống.
- Tích hợp tối ưu hóa: Redis Cluster cung cấp tích hợp với các tính năng như client-side sharding (phân chia client) và automatic partitioning (phân chia tự động), giúp người dùng tương tác với cụm một cách dễ dàng.
- Khả năng mở rộng: Bạn có thể mở rộng Redis Cluster bằng cách thêm node mới vào cụm.
Lưu ý rằng việc triển khai và quản lý một Redis Cluster đòi hỏi sự hiểu biết về cách hoạt động của Redis và cụm cũng như việc cấu hình một cách chính xác để đảm bảo tính sẵn sàng và hiệu suất tốt.
3. Khái niệm về Redis Master, Redis Replicas và Redis Headless.
Redis Master là node chính quản lý việc ghi dữ liệu, Redis Replicas là các bản sao dữ liệu từ Redis Master để đảm bảo sẵn sàng và tăng hiệu suất đọc, và Redis Headless Service là một dịch vụ trong Kubernetes để cung cấp tên miền DNS cho các Pod Redis để truy cập trực tiếp.
- Redis Master: Redis Master là node chính trong một cụm Redis Cluster hoặc một triển khai Redis có sao lưu. Nó chịu trách nhiệm cho việc ghi dữ liệu và quản lý dữ liệu. Các node Redis Replicas được sao lưu từ Redis Master để đảm bảo sẵn sàng dữ liệu và tăng khả năng đọc.
- Redis Replicas: Redis Replicas (hoặc Redis Slave) là các bản sao dữ liệu được tạo ra từ Redis Master. Chúng không có quyền ghi dữ liệu mà chỉ đọc. Việc sử dụng Redis Replicas giúp tăng hiệu suất đọc và cung cấp khả năng sẵn sàng. Nếu Redis Master gặp sự cố, bạn có thể chuyển đổi các Replica thành Master để tiếp tục hoạt động.
- Redis Headless Service: Trong triển khai Redis trên Kubernetes, một Redis Headless Service thường được tạo để tạo ra một tên miền DNS cho mỗi Pod Redis. Điều này cho phép bạn truy cập từng Pod Redis thông qua tên DNS của nó. Headless Service thường được sử dụng trong các trường hợp cần thực hiện truy vấn đến các Pod cụ thể mà không cần cân bằng tải, ví dụ như trong Redis Cluster hoặc khi bạn muốn thao tác với các node cụ thể trong một Redis replica set.
4. Thực hành triển khai Redis Cluster sử dụng Heml.
Bước 1 – Thêm Bitnami vào Helm Repo.
Bạn có thể sử dụng cú pháp dưới để thêm 1 Helm repo.
helm repo add [repo-name] [repo-address]
Ví dụ dưới đây mình sẽ thêm repo https://charts.bitnami.com/bitnami
và đặt tên cho nó là bitnami.
$ helm repo add bitnami https://charts.bitnami.com/bitnami
"bitnami" has been added to your repositories
Sau khi thêm repo xong bạn hãy cập nhật lại repo này.
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "longhorn" chart repository
...Successfully got an update from the "nginx-stable" chart repository
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈
Sử dụng lệnh helm repo list sẽ giúp bạn xem danh sách các repo có trong hệ thống.
$ helm repo list
NAME URL
nginx-stable https://helm.nginx.com/stable
longhorn https://charts.longhorn.io
bitnami https://charts.bitnami.com/bitnami
Bước 2 – Triển khai Redis Cluster.
Mặc định các bạn có thể sử dụng lệnh dưới để cài đặt nhanh 1 Redis Cluster nhưng tôi khuyên chúng ta không nên làm vậy vì chúng ta nên thay đổi một số giá trị để nó phù hợp với môi trường của bạn. Nếu bạn muốn trải nghiệm hãy bỏ qua bước này và thực hiện các bước tiếp theo.
helm install redis-test bitnami/redis
Hãy tải về Helm chart bitnami/redis từ kho lưu trữ, bạn sẽ nhận được file nén *.tgz.
helm fetch bitnami/redis
Bạn sử dụng lệnh dưới để verify lại kết quả tải về thành công.
$ ls . | grep *.tgz
Để giải nén một file .tgz
(tarball) của Helm chart, bạn cần sử dụng câu lệnh tar
để giải nén file này. Dưới đây là cách giải nén Helm chart Redis từ file redis-17.15.4.tgz
:
tar -xzvf redis-17.15.4.tgz
Di chuyển vào thư mục đã giải nén và kiểm tra sự tồn tại của file valule.yaml.
$ cd redis/
$ ls . | grep values.yaml
values.yaml
Hãy dùng công cụ đọc file để đọc file value.yaml và chỉnh sử 1 số thông tin mà bạn mong muốn, ví dụ của mình là thông tin storageClass vì mình đã có 1 Longhorn Storage và cài đặt dung lượng phân vùng cho master và replica.
global:
storageClass: "longhorn"
master:
storageClass: "longhorn"
size: 50Gi
replica:
storageClass: "longhorn"
size: 100Gi
Dùng lệnh dưới đây để list ra các storageClass đang có trong hệ thống của bạn.
$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
longhorn (default) driver.longhorn.io Delete Immediate true 92d
Mình tạo 1 file yaml để khởi tạo 1 namespace tách biệt với các ứng dụng khác.
cat > namespace.yaml << 'OEF'
apiVersion: v1
kind: Namespace
metadata:
name: redis
OEF
Triển khai file yaml đã tạo.
$ kubectl apply -f namespace.yaml
namespace/redis created
Kết quả mình đã có 1 namespace tên là redis.
$ kubectl get ns redis
NAME STATUS AGE
redis Active 10s
Triển khai Redis bằng Helm như sau:
helm install redis-test \
--set persistence.storageClass=longhorn \
--set redis.replica.persistence.storageClass=longhorn \
--set volumePermissions.enabled=true \
--namespace=redis \
--values /home/redis/redis/values.yaml \
bitnami/redis
Trong đó, --set persistence.storageClass=longhorn
và --set redis.replica.persistence.storageClass=longhorn
đảm bảo rằng bạn đang sử dụng StorageClass “longhorn” cho cả PVC chính và PVC của replica.
- Đảm bảo rằng bạn đã chỉ định tên của namespace (trong ví dụ này, namespace là “redis”) bằng cách sử dụng tùy chọn
--namespace
. --values /home/redis/redis/values.yaml
cho phép bạn sử dụng filevalues.yaml
tùy chỉnh từ thư mục/home/redis/redis
.
Nhớ rằng bạn cần đảm bảo file values.yaml
tùy chỉnh chứa các khóa cấu hình mà Helm chart yêu cầu và tương thích với cấu trúc của Helm chart.
Đây là ví dụ đầu ra của nó khi triển khai thành công.
$ helm install redis-test \
> --set persistence.storageClass=longhorn \
> --set redis.replica.persistence.storageClass=longhorn \
> --set volumePermissions.enabled=true \
> --namespace=redis \
> --values /home/redis/redis/values.yaml \
> bitnami/redis
NAME: redis-test
LAST DEPLOYED: Thu Aug 17 09:55:05 2023
NAMESPACE: redis
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redis
CHART VERSION: 17.15.4
APP VERSION: 7.2.0
** Please be patient while the chart is being deployed **
Redis® can be accessed on the following DNS names from within your cluster:
redis-test-master.redis.svc.cluster.local for read/write operations (port 6379)
redis-test-replicas.redis.svc.cluster.local for read-only operations (port 6379)
To get your password run:
export REDIS_PASSWORD=$(kubectl get secret --namespace redis redis-test -o jsonpath="{.data.redis-password}" | base64 -d)
To connect to your Redis® server:
1. Run a Redis® pod that you can use as a client:
kubectl run --namespace redis redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.0-debian-11-r0 --command -- sleep infinity
Use the following command to attach to the pod:
kubectl exec --tty -i redis-client \
--namespace redis -- bash
2. Connect using the Redis® CLI:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-test-master
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h redis-test-replicas
To connect to your database from outside the cluster execute the following commands:
kubectl port-forward --namespace redis svc/redis-test-master 6379:6379 &
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h 127.0.0.1 -p 6379
Bước 3 – Xác nhận các dịch vụ triển khai đã chạy.
Bạn có thể verify lại PersistentVolume (PV) và PersistentVolumeClaim (PVC).
$ kubectl get pv,pvc -n redis
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-1a48197a-16bc-48de-a8b5-733754331550 100Gi RWO Delete Bound devops-tools-master/jenkins-pv-claim longhorn 44d
persistentvolume/pvc-3121a890-df7a-4928-b41f-17024fb7df29 10Gi RWO Delete Bound wiki-hoanghd/website-mysql-pvc longhorn 44d
persistentvolume/pvc-3bda4320-e917-462f-85d9-f144edfd5621 100Gi RWO Delete Bound redis/redis-data-redis-test-replicas-0 longhorn 19s
persistentvolume/pvc-3fc21d5b-b3e8-49eb-aa82-dc40c1ccbfef 100Gi RWO Delete Bound devops-tools-slave/jenkins-pv-claim longhorn 44d
persistentvolume/pvc-6001eab0-493e-4182-be42-6afc5891fb8d 10Gi RWO Delete Bound matbao/website-mysql-pvc longhorn 44d
persistentvolume/pvc-b41d891f-38a6-455d-a7f3-b649b5fa367c 50Gi RWO Delete Bound matbao/website-wp-pvc longhorn 44d
persistentvolume/pvc-b895c850-092c-40f0-a307-e12fbcfe6e23 50Gi RWO Delete Bound wiki-hoanghd/website-wp-pvc longhorn 44d
persistentvolume/pvc-cbe5eda4-13f5-4028-9067-dd1a130252cc 50Gi RWO Delete Bound redis/redis-data-redis-test-master-0 longhorn 19s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/redis-data-redis-test-master-0 Bound pvc-cbe5eda4-13f5-4028-9067-dd1a130252cc 50Gi RWO longhorn 21s
persistentvolumeclaim/redis-data-redis-test-replicas-0 Bound pvc-3bda4320-e917-462f-85d9-f144edfd5621 100Gi RWO longhorn 21s
Hoặc có thể verify trên Longhorn storage.
Bước 4 – Tạo môi trường test.
Lấy thông tin về secret và giải mã secret base64
export REDIS_PASSWORD=$(kubectl get secret --namespace redis redis-test -o jsonpath="{.data.redis-password}" | base64 --decode)
Dòng lệnh này thực hiện các bước sau:
kubectl get secret --namespace default redis-test -o jsonpath="{.data.redis-password}"
: Lấy thông tin về secret có tênredis-test
trong namespace
. Trong đó,redis
redis-password
là một trường dữ liệu trong secret chứa mật khẩu của Redis.base64 --decode
: Giải mã dữ liệu base64 của trườngredis-password
, để lấy ra mật khẩu thật sự.export REDIS_PASSWORD=$(...)
: Gán mật khẩu Redis đã giải mã vào biến môi trườngREDIS_PASSWORD
.
Kết quả của dòng lệnh này là bạn đã tạo một biến môi trường REDIS_PASSWORD
chứa mật khẩu của Redis để có thể sử dụng trong các lệnh hoặc mã nguồn khác mà bạn cần truy cập vào Redis.
Lưu ý rằng lệnh này đang giả định rằng bạn đang sử dụng namespace redis
. Nếu Redis được triển khai trong một namespace khác, bạn cần thay đổi --namespace default
thành --namespace <tên-namespace>
tương ứng.
Kết quả.
$ echo $REDIS_PASSWORD
n3V8kJjllf
Tạo một Pod có tên redis-client
trong namespace redis
.
kubectl run --namespace redis redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:6.2.5-debian-10-r63 --command -- sleep infinity
Lệnh trên sẽ thực hiện các bước sau:
kubectl run --namespace redis redis-client --restart='Never'
: Tạo một Pod có tênredis-client
trong namespaceredis
và chỉ định rằng nó sẽ không khởi động lại khi kết thúc.--env REDIS_PASSWORD=$REDIS_PASSWORD
: Đặt biến môi trườngREDIS_PASSWORD
trong Pod bằng giá trị của biến môi trườngREDIS_PASSWORD
mà bạn đã xuất trước đó.--image docker.io/bitnami/redis:6.2.5-debian-10-r63
: Sử dụng hình ảnh Redis từ Docker Hub.--command -- sleep infinity
: Chạy lệnhsleep infinity
bên trong Pod, dẫn đến việc Pod sẽ chạy vô thời hạn (không bao giờ dừng) vì lệnhsleep infinity
đợi mãi mã không bao giờ kết thúc.
Nhưng dòng lệnh này không có mục tiêu rõ ràng. Thường thì người ta sử dụng một Pod như vậy để thực hiện các tác vụ kiểm tra, gỡ lỗi hoặc thao tác tạm thời với hệ thống. Trong trường hợp này, Pod redis-client
sẽ không làm gì ngoài việc “ngủ” vô thời hạn.
Nếu bạn cần thực hiện một tác vụ cụ thể bên trong Pod, hãy thay sleep infinity
bằng lệnh cụ thể bạn muốn chạy.
Tạo một phiên làm việc tương tác (interactive session) bên trong container của Pod redis-client
, trong đó bạn có thể sử dụng dòng lệnh bash
để thực hiện các lệnh hoặc kiểm tra trong môi trường của container.
kubectl exec --tty -i redis-client --namespace redis -- bash
Lệnh trên sẽ thực hiện các bước sau:
kubectl exec --tty -i redis-client --namespace redis -- bash
: Thực hiện lệnhexec
để thực thi lệnh bên trong container của Podredis-client
trong namespaceredis
.--tty -i
: Tạo một kết nối tương tác và allocate một terminal (TTY) cho việc truy cập vào container.--namespace redis
: Xác định namespace trong đó Podredis-client
được triển khai.-- bash
: Chạy một phiên bản của dòng lệnhbash
bên trong container. Điều này cho phép bạn truy cập vào môi trường dòng lệnh của container để thực hiện các tác vụ bổ sung bên trong.
Nếu bạn vào được container thành công, bạn sẽ có kết quả như dưới.
$ kubectl exec --tty -i pod/redis-client --namespace redis -- bash
I have no name!@redis-client:/$
redis-cli -h redis-test-master -a $REDIS_PASSWORD
sử dụng redis-cli
để kết nối đến máy chủ Redis có tên là redis-test-master
. Điều này đặc biệt hữu ích trong môi trường Redis có cấu hình replica, nơi bạn muốn tương tác trực tiếp với master node để thực hiện các thao tác chỉnh sửa dữ liệu (ví dụ: ghi dữ liệu mới).
$ redis-cli -h redis-test-master -a $REDIS_PASSWORD
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
redis-cli -h redis-test-replicas -a $REDIS_PASSWORD
sử dụng redis-cli
để kết nối đến máy chủ Redis có tên là redis-test-replicas
. Điều này thường được sử dụng để truy vấn các replica nodes, nơi dữ liệu chỉ được đọc và không nên thay đổi (ví dụ: truy vấn dữ liệu).
$ redis-cli -h redis-test-replicas -a $REDIS_PASSWORD
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Nhớ rằng cách bạn tương tác với master và replica nodes phụ thuộc vào mục đích của bạn. Master node thường được sử dụng để thực hiện các thao tác ghi dữ liệu, trong khi replica nodes thường được sử dụng để đọc dữ liệu và tăng tính sẵn sàng và hiệu suất của hệ thống.
Sử dụng lệnh PING
để kiểm tra Redis đã hoạt động.
$ redis-test-replicas:6379> PING
PONG
Trong Redis, lệnh PING
là một trong những lệnh cơ bản nhất và được sử dụng để kiểm tra xem máy chủ Redis có hoạt động bình thường hay không. Khi bạn chạy lệnh PING
trong redis-cli
, Redis server sẽ trả về PONG
nếu máy chủ đang hoạt động đúng cách.
Trong trường hợp bạn đưa ra, khi bạn thực hiện redis-cli
để kết nối đến máy chủ Redis có tên redis-test-replicas
và chạy lệnh PING
, kết quả trả về là PONG
. Điều này cho thấy rằng máy chủ Redis redis-test-replicas
đang hoạt động và phản hồi bình thường.
Lệnh PING
và phản hồi PONG
thường được sử dụng trong các tác vụ kiểm tra hoặc đồng bộ hóa đơn giản để đảm bảo rằng máy chủ Redis vẫn hoạt động và có thể gửi và nhận dữ liệu.
Bước 5 – Tạo Ingress.
Ingress là một tài nguyên trong Kubernetes cho phép bạn quản lý các quy tắc định tuyến và các luồng lưu lượng truy cập đến các dịch vụ trong cluster.
Vì các service mình để ở chế độ ClusterIP nên mình sẽ dùng Ingress để cho phép các kết nối từ bên ngoài vào trong Redis.
Dùng lệnh kubectl get svc -n redis để list các service của Redis.
$ kubectl get svc -n redis
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
redis-test-headless ClusterIP None <none> 6379/TCP 172m
redis-test-master ClusterIP 10.107.225.158 <none> 6379/TCP 172m
redis-test-replicas ClusterIP 10.104.33.176 <none> 6379/TCP 172m
Giả sử mình tạo Ingress cho redis-test-master. Hãy chạy lệnh dưới để vào lấy thông tin service name và port của kubectl get svc -n redis.
kubectl edit svc/redis-test-master -n redis
Hai thông tin trên nằm ở vùng khoanh đỏ như hình dưới.
Tạo 1 file manifest với nội dung dưới.
cat > master-redis-ingress.yml << 'OEF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: redis-ingress
namespace: redis
spec:
ingressClassName: nginx
rules:
- host: master-redis.hoanghd.com
http:
paths:
- backend:
service:
name: tcp-redis
port:
number: 6379
path: /
pathType: Prefix
OEF
Dưới đây là giải thích cho các phần quan trọng trong tài nguyên Ingress trên:
apiVersion: networking.k8s.io/v1
: Đây là phiên bản API mà tài nguyên Ingress đang sử dụng.kind: Ingress
: Đây là loại tài nguyên, trong trường hợp này là Ingress.metadata
: Đây là thông tin về tài nguyên, bao gồm tên và namespace của Ingress.spec
: Phần này chứa cấu hình cho Ingress.ingressClassName: nginx
: Đây là tên của Ingress Controller mà bạn muốn sử dụng để xử lý các quy tắc Ingress. Trong trường hợp này, nó được gọi là “nginx”.rules
: Đây là nơi bạn xác định các quy tắc định tuyến.host: master-redis.hoanghd.com
: Đây là tên miền của máy chủ mà Ingress sẽ xử lý lưu lượng truy cập đến.http
: Đây xác định rằng bạn đang xử lý lưu lượng truy cập HTTP.paths
: Đây là một danh sách các đường dẫn mà bạn muốn Ingress định tuyến đến.backend
: Đây là dịch vụ mục tiêu mà lưu lượng truy cập sẽ được định tuyến đến.service
: Đây là tên của dịch vụ mục tiêu.name: tcp-redis
: Đây là tên của dịch vụ mục tiêu là “tcp-redis”.
port
: Đây là cổng của dịch vụ mục tiêu.number: 6379
: Đây là số cổng (port) của dịch vụ mục tiêu là 6379.
path: /
: Đây là đường dẫn đích mà lưu lượng truy cập sẽ được định tuyến đến. Trong trường hợp này, nó là root (“/”).pathType: Prefix
: Đây chỉ định kiểu đường dẫn (path type) cho việc định tuyến. Trong trường hợp này, nó là “Prefix”, nghĩa là các URL bắt đầu bằng đường dẫn cụ thể sẽ được định tuyến đến dịch vụ.
Triển khai nó.
$ kubectl apply -f redis-ingress.yml
ingress.networking.k8s.io/jenkins-ingress created
Đây là Ingress sau khi tạo xong.
$ kubectl get ingress -n redis
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins-ingress nginx master-redis.hoanghd.com 192.168.13.221 80 13s
Kết quả.
$ telnet master-redis.hoanghd.com 80
Trying 192.168.13.221...
Connected to master-redis.hoanghd.com.
Escape character is '^]'.
Tương tự bạn có thể tạo Ingress cho redis-test-replicas theo cách trên.