I know I'm going to need Redis in the future for some buffering between database and functions. There is lots of uses for Redis, in-memory data structure store ( also known as database in Ram ). I had particular use for Redis when I had a lot of
worker scripts that would normally write to SQL database ( MariaDB ) and to the same table and line which on occasion resulted in lock. So all the workers started to write to Redis server, and as Honey badger Redis don't give a fuck about huge loads and just take it... I than wrote simple single
db worker that on its own time and speed offloaded data to database.
You can read much more about Redis here: https://redis.io its not that difficult.
There are multiple ways to deploy Redis, with multiple master - slave nodes and so on... but for my purpose I need only one. If node fails where it runs, Kubernetes will start it on another, so High Availability is acceptable with small outage till it starts elsewhere.
I usually don't store long term data in Redis and consume them as fast as I can however this whole thing is in Ram, the pod dies the data dies with it. Redis support two types of persistence. Regular backups every X seconds or minutes ( snapshots ) or kind of log that keep every transaction as it happens and this is replayed back when Redis starts up. I'm going for the second one here since it offers backup near 1:1 always. Honestly read about both methods here: https://redis.io/topics/persistence . We are going with
For persistent storage I'm going to use 5GB Longhorn distributed storage I setup before.
So, create one directory where we keep configs. This guide assume you have same setup as my K3s server or close enough.
mkdir redis-deployment cd redis-deployment
I'm going to put everything related to Redis to its own namespace.
kubectl create namespace redis-server
Persistent storage PVC
pvc.yaml file and create claim for 5GB
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: redis-pvc namespace: redis-server spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 5Gi
kubectl apply -f pvc.yaml
We have disk, next the main deployment. I will use basically official Redis docker container, since its produced for arm64 and we do not need to do any special stuff.
Official Docker repository is here: https://hub.docker.com/_/redis/
apiVersion: apps/v1 kind: Deployment metadata: name: redis-server namespace: redis-server spec: replicas: 1 selector: matchLabels: app: redis-server template: metadata: labels: app: redis-server name: redis-server spec: nodeSelector: node-type: worker containers: - name: redis-server image: redis args: ["--appendonly", "yes"] ports: - name: redis-server containerPort: 6379 volumeMounts: - name: lv-storage mountPath: /data env: - name: ALLOW_EMPTY_PASSWORD value: "yes" volumes: - name: lv-storage persistentVolumeClaim: claimName: redis-pvc
Nothing special in this deployment. I have explained these values before. Only new argument is:
- args - which is way to pass arguments to docker image. If you look at the official repository, these arguments are the one that turn on persistence.
#Apply kubectl apply -f deployment.yaml
It might take a minute to start, but for me it deployed without an issue.
root@control01:/home/ubuntu/redis-kubernetes# kubectl get pods -n redis-server NAME READY STATUS RESTARTS AGE redis-server-55ddccf85-xfg87 1/1 Running 0 41m
root@control01:/home/ubuntu/redis-kubernetes# kubectl logs redis-server-55ddccf85-xfg87 -n redis-server 1:C 06 Feb 2021 20:19:53.989 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 1:C 06 Feb 2021 20:19:53.989 # Redis version=6.0.10, bits=64, commit=00000000, modified=0, pid=1, just started 1:C 06 Feb 2021 20:19:53.989 # Configuration loaded 1:M 06 Feb 2021 20:19:53.997 * Running mode=standalone, port=6379. 1:M 06 Feb 2021 20:19:53.997 # Server initialized 1:M 06 Feb 2021 20:19:54.004 * Ready to accept connections
Ready to accept connections is what you want to see 🙂
I like for Redis to have it own IP so not only pods in the same namespace can reach it, but everybody around !
You should know by now, that for this I'm using
MetalLB on my Kubernetes cluster.
apiVersion: v1 kind: Service metadata: name: redis-server namespace: redis-server spec: selector: app: redis-server type: LoadBalancer ports: - name: redis-port protocol: TCP port: 6379 targetPort: 6379 loadBalancerIP: 192.168.0.234
192.168.0.234 is next free IP from my MetalLB IP pool so this is where my Redis will live.
#Apply kubectl apply -f service.yaml
Check if everything is ok:
root@control01:/home/ubuntu/redis-kubernetes# kubectl get svc -n redis-server NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE redis-server LoadBalancer 10.43.203.164 192.168.0.234 6379:30771/TCP 41m
I'm adding new entry to every kubernetes node for Redis.
echo '192.168.0.234 redis redis.cube.local' >> /etc/hosts
And off you go to every node via Ansible...
ansible cube -b -m copy -a "src=/etc/hosts dest=/etc/hosts"
ubuntu@control01:~$ telnet redis.cube.local 6379 Trying 192.168.0.234... Connected to redis. Escape character is '^]'.
Done and done. Redis is up and running on Raspberry Pi 4 Kubernetes cluster, Ubuntu arm64. If your mouth is dry like mine now, you will get something to drink and maybe help me to get some liquids too 🙂 ( smooth I know /s )