Kubernetes搭建有状态zookeeper集群

文章引导

前言
环境准备
部署NFS
部署StorageClass存储类(动态制备 PersistentVolume)
部署ZooKeeper
ZooKeeper健康检查

前言

ZooKeeper是一个用于维护配置信息、命名、提供分布式同步和提供组服务的集中式服务。所有这些类型的服务都以某种形式被分布式应用程序使用。每次实现它们时,都要做大量的工作来修复不可避免的错误和竞争条件。由于实现这些类型的服务很困难,应用程序最初通常会吝啬它们,这使得它们在发生更改时很脆弱,很难管理。即使操作正确,在部署应用程序时,这些服务的不同实现也会导致管理的复杂性。
ZooKeeper Wiki上了解更多关于ZooKeeper。

NFS:网络文件系统,英文Network File System(NFS),是由SUN公司研制的UNIX表示层协议(presentation layer protocol),能使使用者访问网络上别处的文件就像在使用自己的计算机一样。

StorageClass存储类:(简称SC)
介绍:StorageClass 为管理员提供了描述存储 “类” 的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。这个类的概念在其他存储系统中有时被称为 “配置文件”。

创建PV有两种方法,第一种手动去写/创建PV的yaml文件,就叫做静态制备,如果遇到成百上千个需要创建PV的环境,那么对于集群管理员是一个耗时耗力的事情;现在使用sc存储类来进行动态制备。只需要管理员规定一个模板,PVC来遵循这个模板,那么就PV就会自动自动创建
本次文章采用动态制备

环境准备

CPU架构系统版本Docker版本K8S版本
x86_64CentOS 7.819.03.12v1.19.9

部署NFS

  1. 通过yum下载nfs相关组件,rpcbind:是一个RPC服务,主要是在nfs共享时候负责通知客户端,服务器的nfs端口号的。简单理解rpc就是一个中介服务
yum install -y nfs-utils rpcbind

在这里插入图片描述

  1. 创建共享的目录并授权(一定要授权不然,不会会权限不够)
mkdir /root/nfs
chmod 777 /root/nfs

在这里插入图片描述

  1. 编辑nfs共享配置文件
vim /etc/exports
#写入以下配置
/root/nfs *(rw,no_root_squash,no_all_squash,sync)

在这里插入图片描述

/root/nfs             #代表共享的目录
*                     #代表不限制IP连接
rw                    #可进行读写
no_root_squash        #NFS客户端使用root连接服务器端时,那么对于服务端共享目录也具有共享权限
no_all_squash         #(默认)访问用户先与本机用户匹配,匹配失败后再映射为匿名用户或用户组
sync                  #文件写入的时候同时写入硬盘
  1. 启动rpcbind和nfs(需要先启动rpcbind,后启动nfs)
systemctl start rpcbind
systemctl enable rpcbind           #加入开机自启
systemctl start nfs
systemctl enable nfs 
  1. 查看共享目录
showmount -e localhost             #localhost(指本机 127.0.0.1 的意思)

在这里插入图片描述
6. 通过其他服务器测试挂载nfs磁盘

yum install -y nfs-utils                        #下载nfs-utils
mkdir /test                                     #创建要被挂载的目录
mount 10.64.95.18:/root/nfs/mysql /test   #IP地址是nfs服务器地址和共享目录,后者是本机目录

注意:挂载端需要下载第一步中的:nfs-utils,不会挂载的时候会提示以下错误
在这里插入图片描述

部署StorageClass(动态制备 PersistentVolume)

由于Kubernetes没有NFS驱动,也默认不支持NFS类型的StorageClass,从而需要外部驱动并修改配置文件

vim /etc/kubernetes/manifests/kube-apiserver.yaml  #打开apiserver的yaml文件

添加以下配置

- --feature-gates=RemoveSelfLink=false

在这里插入图片描述

然后通过cat命令能查到配置
在这里插入图片描述
因为是自动应用,可以不用重启apiserver,如果不生效就通过以下命令重启下apiserver

systemctl restart kubelet

下载外部的制备器(内部含镜像文件,可提前下载)
访问github,下载deployment.yaml和rbac.yaml的两个文件,访问不到的话可以使用以下配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest                                    #镜像
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs				#可以按照自己的命名更改
            - name: NFS_SERVER
              value: 10.10.10.60				#NFS服务器地址
            - name: NFS_PATH
              value: /ifs/kubernetes			#共享目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.10.10.60					#NFS服务器地址
            path: /ifs/kubernetes				#共享目录
deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  
rbac.yaml

开始安装

kubectl apply -f rbac.yaml 			#yaml文件里包含命名空间,可根据自身情况修改
kubectl apply -f deployment.yaml	#yaml文件里面的下载策略,建议修改为imagePullPolicy: IfNotPresent

查看制备器的状态
在这里插入图片描述
创建StorageClass

[root@ks8-master ~]# vim storageclass.yaml 
[root@ks8-master ~]# cat storageclass.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: nfs # 这个就是deployemnt的yaml文件中的环境变量:PROVISIONER_NAME
parameters:
  archiveOnDelete: "false"
allowVolumeExpansion: true
[root@ks8-master ~]# kubectl apply -f storageclass.yaml 

查看创建的StorageClass
在这里插入图片描述
测试

[root@ks8-master pvc]# vim auto-pvc.yaml

#storageClassName要和刚才创建的storageClass一样
[root@ks8-master pvc]# cat pvc1.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: aotu-pvc-test
  namespace: ggzj
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Gi
  storageClassName: managed-nfs-storage

[root@ks8-master pvc]# kubectl apply -f auto-pvc.yaml
persistentvolumeclaim/aotu-pvc-test created

[root@ks8-master pvc]# kubectl get pvc
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
aotu-pvc-test   Bound    pvc-af12e765-3459-4b7a-acdb-744fb81b2bb5   20Gi       RWX            managed-nfs-storage   13s

删除测试PVC

[root@ks8-master pvc]# kubectl delete -f auto-pvc.yaml
persistentvolumeclaim "aotu-pvc-test" deleted
[root@ks8-master pvc]# kubectl get pv

注意:deployment的yaml文件的PROVISIONER_NAME的环境变量的值必须与StorageClass的yaml文件的provisioner的值对应
StorageClass的yaml文件的name值必须与PVC的yaml文件的storageClassName值对应

部署ZooKeeper

这里引用kubernetes的官方文档

  1. 创建一个zookeeper的yaml文件并保存,包含一个无头服务、 一个 Service、 一个 PodDisruptionBudget 和一个 StatefulSet。(本文章的K8s的版本较低,故不能使用PodDisruptionBudget 已经注释)。
apiVersion: v1
kind: Service
metadata:
  name: zk-hs
  labels:
    app: zk
spec:
  ports:
  - port: 2888
    name: server
  - port: 3888
    name: leader-election
  clusterIP: None
  selector:
    app: zk
---
apiVersion: v1
kind: Service
metadata:
  name: zk-cs
  labels:
    app: zk
spec:
  ports:
  - port: 2181
    name: client
  selector:
    app: zk
#---
#apiVersion: policy/v1
#kind: PodDisruptionBudget
#metadata:
#  name: zk-pdb
#spec:
#  selector:
#    matchLabels:
#      app: zk
#  maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: zk
spec:
  selector:
    matchLabels:
      app: zk
  serviceName: zk-hs
  replicas: 3
  updateStrategy:
    type: RollingUpdate
  podManagementPolicy: OrderedReady
  template:
    metadata:
      labels:
        app: zk
    spec:
      affinity:                                      #节点亲和性必须要三个工作节点
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - zk
              topologyKey: "kubernetes.io/hostname"
      containers:
      - name: kubernetes-zookeeper
        imagePullPolicy: Always
        image: "registry.k8s.io/kubernetes-zookeeper:1.0-3.4.10"  #镜像拉取不下来可以按照下面注意里面的镜像
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            memory: "1Gi"
            cpu: "0.5"
        ports:
        - containerPort: 2181
          name: client
        - containerPort: 2888
          name: server
        - containerPort: 3888
          name: leader-election
        command:
        - sh
        - -c
        - "start-zookeeper \
          --servers=3 \
          --data_dir=/var/lib/zookeeper/data \
          --data_log_dir=/var/lib/zookeeper/data/log \
          --conf_dir=/opt/zookeeper/conf \
          --client_port=2181 \
          --election_port=3888 \
          --server_port=2888 \
          --tick_time=2000 \
          --init_limit=10 \
          --sync_limit=5 \
          --heap=512M \
          --max_client_cnxns=60 \
          --snap_retain_count=3 \
          --purge_interval=12 \
          --max_session_timeout=40000 \
          --min_session_timeout=4000 \
          --log_level=INFO"
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - "zookeeper-ready 2181"
          initialDelaySeconds: 10
          timeoutSeconds: 5
        livenessProbe:
          exec:
            command:
            - sh
            - -c
            - "zookeeper-ready 2181"
          initialDelaySeconds: 10
          timeoutSeconds: 5
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/zookeeper
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
  volumeClaimTemplates:
  - metadata:
      name: datadir
      annotations:
        volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"   #managed-nfs-storage为我们创建的storage-class名称
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi

注意:image中的镜像可能拉去不下来,请使用这个景象mirrorgooglecontainers/kubernetes-zookeeper:1.0-3.4.10

volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"  #这里面的storage-class的值必须为上述的storage-class名字
  1. 创建zk集群
[root@ks8-master ~] kubectl apply -f zookeeper.yaml
service/zk-hs created
service/zk-cs created
statefulset.apps/zk created
  1. 查看创建状态,等待所有POD的状态都显示 Running
[root@ks8-master ~] kubectl get pods -w -l app=zk
NAME      READY     STATUS    RESTARTS   AGE
zk-0      1/1       Running   0         40s
zk-1      1/1       Running   0         40s
zk-2      1/1       Running   0         40s
  1. 开始验证ZK集群
    促成 Leader 选举
    由于在匿名网络中没有用于选举 leader 的终止算法,Zab 要求显式的进行成员关系配置, 以执行 leader 选举。Ensemble 中的每个服务器都需要具有一个独一无二的标识符, 所有的服务器均需要知道标识符的全集,并且每个标识符都需要和一个网络地址相关联。

(1) 使用命令 kubectl exec 获取 zk StatefulSet 中 Pod 的主机名。
StatefulSet 控制器基于每个 Pod 的序号索引为它们各自提供一个唯一的主机名。 主机名采用 <statefulset 名称>-<序数索引> 的形式。 由于 zk StatefulSet 的 replicas 字段设置为 3,这个集合的控制器将创建 3 个 Pod,主机名为:zk-0、zk-1 和 zk-2。

[root@ks8-master ~] for i in 0 1 2; do kubectl exec zk-$i -- hostname; done
zk-0
zk-1
zk-2

ZooKeeper ensemble 中的服务器使用自然数作为唯一标识符, 每个服务器的标识符都保存在服务器的数据目录中一个名为 myid 的文件里。

(2) 检查每个服务器的 myid 文件的内容。由于标识符为自然数并且序号索引是非负整数,你可以在序号上加 1 来生成一个标识符。

[root@ks8-master ~] for i in 0 1 2; do echo "myid zk-$i";kubectl exec zk-$i -- cat /var/lib/zookeeper/data/myid; done
myid zk-0
1
myid zk-1
2
myid zk-2
3

(3) 获取 zk StatefulSet 中每个 Pod 的全限定域名(Fully Qualified Domain Name,FQDN)
zk-hs Service 为所有 Pod 创建了一个域:zk-hs.default.svc.cluster.local。

[root@ks8-master ~] for i in 0 1 2; do kubectl exec zk-$i -- hostname -f; done
zk-0.zk-hs.default.svc.cluster.local
zk-1.zk-hs.default.svc.cluster.local
zk-2.zk-hs.default.svc.cluster.local

Kubernetes DNS 中的 A 记录将 FQDN 解析成为 Pod 的 IP 地址。 如果 Kubernetes 重新调度这些 Pod,这个 A 记录将会使用这些 Pod 的新 IP 地址完成更新, 但 A 记录的名称不会改变。

(4) ZooKeeper 在一个名为 zoo.cfg 的文件中保存它的应用配置。 使用 kubectl exec 在 zk-0 Pod 中查看 zoo.cfg 文件的内容。
文件底部为 server.1、server.2 和 server.3,其中的 1、2 和 3 分别对应 ZooKeeper 服务器的 myid 文件中的标识符。 它们被设置为 zk StatefulSet 中的 Pods 的 FQDNs。

[root@ks8-master ~] kubectl exec zk-0 -- cat /opt/zookeeper/conf/zoo.cfg
clientPort=2181
dataDir=/var/lib/zookeeper/data
dataLogDir=/var/lib/zookeeper/log
tickTime=2000
initLimit=10
syncLimit=2000
maxClientCnxns=60
minSessionTimeout= 4000
maxSessionTimeout= 40000
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
server.1=zk-0.zk-hs.default.svc.cluster.local:2888:3888
server.2=zk-1.zk-hs.default.svc.cluster.local:2888:3888
server.3=zk-2.zk-hs.default.svc.cluster.local:2888:3888

ZooKeeper健康检查

最基本的健康检查是向一个 ZooKeeper 服务器写入一些数据,然后从另一个服务器读取这些数据。
[root@ks8-master ~] kubectl exec zk-0 zkCli.sh create /hello world

最后会输出以下内容:

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
Created /hello

使用下面的命令从 zk-1 Pod 获取数据。

[root@ks8-master ~] kubectl exec zk-1 zkCli.sh get /hello

最后会消费以下内容:

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
world					#获取内容
cZxid = 0x100000002
ctime = Thu Dec 08 15:13:30 UTC 2016
mZxid = 0x100000002
mtime = Thu Dec 08 15:13:30 UTC 2016
pZxid = 0x100000002
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值