k8s环境下单节点运行Redis集群

单机下用Redis二进制程序包搭建Redis集群的案例很多,用docker在单节点上搭集群的也很多,但是在k8s下单节点搭集群的就很少了,有的只是挂载一个临时目录,数据无法持久化,pod销毁后,数据就没了。在k8s环境下测试机又不够的情况下使用Redis集群就不太方便了,本文就是笔者的根据自身需要实践出来的,期间也找了很多网上资料,最后自己综合琢磨出的解决方案,由于对docker和k8s不是很精通,可能有其他更简单的方案,欢迎大家交流。

一、所需的背景知识

1、对docker,k8s有一定使用经验:会编写yaml文件,知道如何排查pod不能running的问题
2、在单机环境下搭建过Redis集群
3、如果以上的知识都不知道也没关系,本文尽量保证你按照步骤执行不出错。但是k8s环境你必须得有,基本的linux命令知识得有

二、软件版本

k8s v1.10.2
docker 18.03.1-ce, build 9ee9f40
Redis5.0.5

三、准备工作

 docker pull redis:5.0.5
 mkdir redis-cluster
 cd redis-cluster/
 mkdir data

创建多个节点的数据存储目录,避免Redis实例启动时配置文件冲突导致无法启动,在单台物理机上搭建过Redis集群的应该知道。建好6个节点的目录,后面会用到,这里的目录要注意权限问题,k8s启动的pod需要读写这里的文件夹

for port in `seq 7001 7006`; do \
  mkdir -p ./${port}/
done

创建完成后目录结构

目录结构

四、编辑yaml文件

创建k8s的yaml文件
回到redis-cluster目录下

1、创建ConfigMap

先创建redis.conf配置文件
vi redis-cm.yaml
将以下内容贴到文件中,保存退出

apiVersion: v1
kind: ConfigMap
metadata:
 name: redis-conf
data:
 redis.conf: |
         appendonly yes
         cluster-enabled yes
         cluster-config-file /var/lib/redis/nodes.conf
         cluster-node-timeout 5000
         dir /var/lib/redis
         port 6379

2、创建statefulset

vi redis-statefulset.yaml

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: redis-app
spec:
  serviceName: "redis-service"
  replicas: 6
  template:
    metadata:
      labels:
        app: redis
        appCluster: redis-cluster
    spec:
      nodeSelector:
        node: mfc    # 这里需要根据自己的k8s节点情况修改,本案例需修改成node-222
      terminationGracePeriodSeconds: 20
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - redis
              topologyKey: kubernetes.io/hostname
      containers:
      - name: redis
        image: "redis:latest"
        imagePullPolicy: IfNotPresent #默认情况是会根据配置文件中的镜像地址去拉取镜像,配置为本地有镜像不拉取远程,避免你的环境不能访问外网,拉取镜像失败
        command:
          - "redis-server"
        args:
          - "/etc/redis/redis.conf"
          - "--protected-mode"
          - "no"
        resources:
          requests:
            cpu: "100m"
            memory: "100Mi"
        ports:
            - name: redis
              containerPort: 6379
              protocol: "TCP"
            - name: cluster
              containerPort: 16379
              protocol: "TCP"
        volumeMounts:
          - name: "redis-conf"
            mountPath: "/etc/redis"
          - name: "redis-data"
            mountPath: "/var/lib/redis"
      volumes:
      - name: "redis-conf"
        configMap:
          name: "redis-conf"
          items:
            - key: "redis.conf"
              path: "redis.conf"
  volumeClaimTemplates:   #可看作pvc的模板
    - metadata:
      name: redis-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

3、创建pv的yaml文件

vi pv1.yaml

kind: PersistentVolume
apiVersion: v1
metadata:
  name: redis-pv-volume1
  labels:
    type: local
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /home/bboss/redis-cluster/data/7001/

/home/bboss/redis-cluster/data/7001/此目录为前面我们创建的redis数据存储的6个目录
将此文件复制5份,依次命名为pv2.yaml 到pv6.yaml
在对应的文件中将

name: redis-pv-volume1
path: /home/bboss/redis-cluster/data/7001/

这2处修改为对应文件编号的序号,例如pv2.yaml修改为

name: redis-pv-volume2
path: /home/bboss/redis-cluster/data/7002/

五、开始搭建集群

1、创建cm和pv如下图

km create -f redis-cm.yaml
km create -f pv1.yaml
image.png

2、创建statefulset

确定当前宿主机在k8s集群中的label

kubectl get nodes --show-labels
k8s集群机器ip和对应的label

如图,我当前部署的机器ip是222对应的node标签名为node-222
将redis-statefulset.yaml文件中node: mfc 修改为 node: node-222,稍后启动redis的pod是都会选择在node-222这个节点的机器上启动,这正是我们需要的,修改正确后

km create -f redis-statefulset.yaml

[注:我这里km是做了配置,km相当于是kubectl -n mfc-namespace 这是指定k8s的namespace的,我的namespace名是mfc-namespace,kubectl命令不指定-n 默认是使用default为名的namespace]

kubectl get pods  -n mfc-namespace | grep redis 

查看6个redis节点是否都启动完成

查看一下pod对应的ip,下一步配置集群需要知道各节点的ip,这ip是k8s分配的

kubectl get pods -o wide -n mfc-namespace | grep redis

验证一下pvc是否都bound了

kubectl get pvc -o wide -n mfc-namespace
redis节点的ip

3、初始化Redis集群

启动一个独立的redis

docker run -it redis:latest bash
redis-cli --cluster create 10.254.79.20:6379 10.254.79.21:6379 10.254.79.22:6379 10.254.79.23:6379 10.254.79.24:6379 10.254.79.25:6379 --cluster-replicas 1
初始化Redis集群
接上图

4、验证Redis集群

日志显示集群已经初始化好,slots也分配完成,验证一下集群
用redis-cli随便连接某个redis节点

/usr/local/bin/redis-cli -c -h 10.254.79.20 -p 6379
验证集群

搭建完成了,下面来看看本地存储的数据
随便进到某个目录下看看,如下图redis集群的数据已经落到物理机上了。

3号节点的数据文件

验证一下pod重启后集群数据是否还在

重启Redis集群

看ip还是原来的ip,这就是k8s定义statefulset的作用
通过刚才启动的独立redis再次连接集群看数据还在不在,如下图数据都还在

验证集群中已数据是否还在,如图数据都还在

5、创建headlessService

到这里我们的Redis集群已经是完全可用的了,但是我们的应用要使用该集群时配置ip不好记,这时就需要用到k8s中的Service
vi redis-headlessService.yaml

apiVersion: v1
kind: Service
metadata:
  name: redis-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    port: 6379
  clusterIP: None
  selector:
    app: redis
    appCluster: redis-cluster

执行 km create -f redis-headlessService.yaml 创建服务
查看服务

查看redis-service服务

另外用k8s启一个有nslookup或者ping工具的pod,验证一下服务名是否可以访问

验证服务名

k8s是自带dns功能的,k8s会根据serviceName生成对应的域名
如上图,可以看到节点1 (10.254.79.20)的完整域名是redis-app-0.redis-service.mfc-namespace.svc.cluster.local,在k8s中同一个namespace的服务只需要前面的子域名即可,后面的会默认补齐,本例中的serviceName是redis-app-0.redis-service,这是一个节点的服务名。对于整个集群的serviceName是redis-service

用刚才的docker启动的redis验证一下域名是否可以连接,如下图用域名连接失败,因为我们这个是用docker启动的不在k8s中,用pod的ip是可以连接的,因为pod的ip访问是走docker的网络。因为服务名是k8s做的路由,所以必须在k8s集群中注册才可以使用服务名互相访问。serviceName其实是在操作系统中做了一个转发的动作,通过iptales做策略实现的。

用域名连接失败

用redis集群中的任意一个节点验证,域名是可以访问的

用redis集群中的节点验证

六、总结

网上大部分文章都是类似的方案,使用pv,pvc做存储,有的pv是绑定的nfs,我也试过nfs碰到问题没解决只能想其他办法,但是我理解的是如果6个redis节点的配置文件nodes.conf和数据文件都在共享一个目录,那还是会有冲突,导致redis只能启动一个节点,而其他节点无法启动,除非能把文件命名定义成不同节点对应不同的文件名,因为没搭成功基于nfs的pvc存储,不知道是不是每个节点一个隔离的pvc,所以无法知道以后会再实践。所以本例主要是通过定义不同的pv把目录隔离开,但是定义StatefulSet时不好指定pvc,看到有文章用到volumeClaimTemplates(可看作pvc的模板)传输门于是问题就应然而解了,StatefulSet在创建pod时是前一个创建成功才继续下一个是有顺序的,同时创建pvc也是有顺序的,每个pvc绑定一个pv,这样6个节点的数据文件就自动绑定到各自的目录下了。
另外redis集群初始化不需要Ruby了,避免了安装ruby的麻烦。

七、参考资料

[https://www.cnblogs.com/tylerzhou/p/11027559.html]
[https://v1-12.docs.kubernetes.io/zh/docs/tasks/run-application/force-delete-stateful-set-pod/]
[https://juejin.im/post/5d206b1e5188252f275fdc95]
[https://www.cnblogs.com/breezey/p/6582082.html]
[https://juejin.im/post/5c989ff2f265da60f206ffe4#heading-7]
[https://www.jianshu.com/p/a5172b0eeae4]
https://www.cnblogs.com/xiaochangwei/p/7993065.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335