548a64aaf996e62da258b6805a7fcce6.gif

点击上方「蓝字」关注我们

68b5d39ee9e11dddd53bd9289444a07b.png

ZooKeeper 基础

b60da6e2b8961fc3678cb69db155e496.png 78f03aca2c5b9cb9d9c8ef0eec1c47e6.png

    Apache ZooKeeper 是一个分布式的开源协调服务,用于分布式系统。ZooKeeper 允许你读取、写入数据和发现数据更新。数据按层次结构组织在文件系统中,并复制到 ensemble(一个 ZooKeeper 服务的集合) 中所有的 ZooKeeper 服务。对数据的所有操作都是原子的和顺序一致的。ZooKeeper 通过 Zab 一致性协议在 ensemble 的所有服务之间复制一个状态机来确保这个特性。

    ensemble 使用 Zab 协议选举一个 leader,在选举出 leader 前不能写入数据。一旦选举出了 leader,ensemble 使用 Zab 保证所有写入被复制到一个 quorum,然后这些写入操作才会被确认并对客户端可用。如果没有遵照加权 quorums,一个 quorum 表示包含当前 leader 的 ensemble 的多数成员。例如,如果 ensemble 有3个服务,一个包含 leader 的成员和另一个服务就组成了一个 quorum。如果 ensemble 不能达成一个 quorum,数据将不能被写入。

    ZooKeeper 在内存中保存它们的整个状态机,但是每个改变都被写入一个在存储介质上的持久 WAL(Write Ahead Log)。当一个服务故障时,它能够通过回放 WAL 恢复之前的状态。为了防止 WAL 无限制的增长,ZooKeeper 服务会定期的将内存状态快照保存到存储介质。这些快照能够直接加载到内存中,所有在这个快照之前的 WAL 条目都可以被安全的丢弃。

k8s集群信息

b60da6e2b8961fc3678cb69db155e496.png 78f03aca2c5b9cb9d9c8ef0eec1c47e6.png

5b5aab5092af028632e3c3229d73378f.png

创建一个zookeeper集群

b60da6e2b8961fc3678cb69db155e496.png 78f03aca2c5b9cb9d9c8ef0eec1c47e6.png
[root@worker01 middleware]# vim zk.yml#创建一个无头服务Headless serviceapiVersion: v1kind: Servicemetadata:  name: zk-hs  labels:    app: zkspec:  ports:  - port: 2888    name: server  - port: 3888    name: leader-election  clusterIP: None  selector:app: zk#创建一个service---apiVersion: v1kind: Servicemetadata:  name: zk-cs  labels:    app: zkspec:  type: ClusterIP  ports:  - port: 2181    targetPort: 2181    name: client  selector:app: zk#创建一个PDB,确保最大不可用pod数量1---apiVersion: policy/v1beta1kind: PodDisruptionBudgetmetadata:  name: zk-pdbspec:  selector:    matchLabels:      app: zk  maxUnavailable: 1
#创建有状态服务,3副本,pod反亲和性,节点亲和性,持久化存储[root@worker01 middleware]# cat zk-statefulset.yamlapiVersion: apps/v1kind: StatefulSetmetadata:  name: zkspec:  serviceName: zk-hs  replicas: 3  selector:    matchLabels:      app: zk  template:    metadata:      labels:        app: zk    spec:      affinity:        podAntiAffinity:          requiredDuringSchedulingIgnoredDuringExecution:            - labelSelector:                matchExpressions:                  - key: "app"                    operator: In                    values:                    - zk              topologyKey: "kubernetes.io/hostname"        nodeAffinity:          requiredDuringSchedulingIgnoredDuringExecution:            nodeSelectorTerms:            - matchExpressions:              - key: "app"                operator: In                values:                - "true"      containers:      - name: kubernetes-zookeeper        imagePullPolicy: IfNotPresent        image: leolee32/kubernetes-library:kubernetes-zookeeper1.0-3.4.10        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: zk-data          mountPath: /var/lib/zookeeper  volumeClaimTemplates:  - metadata:      name: zk-data    spec:      accessModes: [ "ReadWriteOnce" ]      resources:        requests:          storage: 10Gi
[root@worker01 middleware]# kubectl apply -f .     statefulset.apps/zk createdservice/zk-hs createdservice/zk-cs createdpoddisruptionbudget.policy/zk-pdb createdstatefulset.apps/zk configured

获取 StatefulSet 的 PersistentVolumeClaims

StatefulSet 控制器为 StatefulSet 中的每个 Pod 生成一个PersistentVolumeClaim。

4a109fe9073f950729fdeeb4e35c3b57.png当 zk StatefulSet 中的一个 Pod 被(重新)调度时,它总是拥有相同的 PersistentVolume,挂载到 ZooKeeper 服务的数据目录。即使在 Pods 被重新调度时,所有对 ZooKeeper 服务的 WALs 的写入和它们的全部快照都仍然是持久的。

pods查看

261494ace5812ed5bad68e1d6e5724a9.png

Service查看

cde8c3538771a174181d60a9d0037b1c.png

查看zk StatefulSet 中 Pods 的主机名和myid

0a157451b6691790d8cbba3cf410eaf9.png

 FQDN查看

f5054fc8e178d00e63c16281f577ad89.png

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

在 zk-0 Pod 中查看 zoo.cfg 文件的内容

2da8bcd3ed2dd999979f50fe8989f6ed.png

文件底部为 server.1、server.2 和 server.3,其中的 1、2和3分别对应 ZooKeeper 服务的 myid 文件中的标识符。它们被设置为 zk StatefulSet 中的 Pods 的 FQDNs。

我们现在来重建一下statefulset观察他的状态变化

创建 zk StatefulSet 时,StatefulSet 控制器按照 Pods 的序号索引顺序的创建每个 Pod,创建下一个 Pod 前会等待每个 Pod 变成 Running 和 Ready 状态

3e0915db25d320a449622988aa611631.png

另外,每个 Pod 的 A 记录仅在 Pod 变成 Ready状态时被录入。因此,ZooKeeper 服务的 FQDNs 只会解析到一个 endpoint,这保证了 ZooKeepers 的 zoo.cfg 文件中的 servers 属性代表了一个正确配置的 ensemble。

健康状态检测

使用 zkCli.sh 脚本在 zk-0 Pod 上写入 yes 到路径 /k8s

f24a4d43835c9fa516a08223f1588b35.png

在另一个pod zk-1上获取数据,查看数据已同步

3bdf6c38b5713cbc3a9739aef14fc447.png

pod的分布节点查看

3bd06c0285d4b91f0b44e05c062be861.png

可以确认StatefulSe 中所有的 Pods 都被部署在不同的节点,这是因为 StatefulSet 中的 Pods 指定了 PodAntiAffinity。requiredDuringSchedulingRequiredDuringExecution 告诉 Kubernetes 调度器,在以 topologyKey 指定的域中,绝对不要把带有键为 app,值为 zk 的标签的两个 Pods 调度到相同的节点。这也是为了防止由于某台机器断连引起服务中断,最佳实践是防止应用的多个示例在相同的机器上共存。

PodDisruptionBudget  zk-pdb查看

8edaabb664167a275c4fe56967597cc9.png

max-unavailable 字段指示 Kubernetes 在任何时候,zk StatefulSet 至多有1个 Pods 是不可用的。

Pod Disruption Budget (pod中断预算) 简称PDB,含义其实是终止pod前通过labelSelector机制获取正常运行的pod数目的限制,目的是对自愿中断的保护措施。Kubernetes version >= 1.7 才支持PodDisruptionBudget

环境变量查看

663e24a6d9951cea14366f2a0470bbce.png

65a04e6c976df05549adc6a0cc25a9e4.gif 8a644550dfee9bae3504e769dce71d13.gif e47c43f5f822cf5715b2a9da93e25fda.gif 

THE END

野有蔓草

野有蔓草,零露漙兮。

有美一人,清扬婉兮。

邂逅相遇,适我愿兮。

野有蔓草,零露瀼瀼。

有美一人,婉如清扬。

邂逅相遇,与子偕臧。

往期推荐

基于k8s的Prometheus服务自动发现配置

Kubernetes监控方案kube-prometheus部署指北

bd90f5844e2730b2e757faca32633e7d.png

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐