热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Kubernetes系列(四)StatefulSet

作者:LemonNan



作者: LemonNan
原文地址: https://juejin.im/post/6870071267438329869



Kubernetes 系列

  • Kubernetes系列(一) Pod

  • Kubernetes系列(二) Service

  • Kubernetes系列(三) Deployment


StatefulSet

前言

前几篇讲解的都是关于无状态的应用, 今天这篇介绍 Kubernetes 中的另一种应用, 有状态应用, 而 有状态的应用是由 StatefulSet 来进行管理部署 , **StatefulSet 也是 kubernetes 中的一种资源类型, 作用类似于无状态应用的 Deployment **.


操作的基础

最近的文章都是基于 minikube 进行的操作, 所以时不时的需要进入到 minikube 里面进行一些操作的验证, 所以把进入 minikube 的操作记录在这.

# minikube 默认用户名:docker 密码:tcuser , 我的地址是 192.168.99.100
ssh docker@192.168.99.100

概念介绍


无状态 VS 有状态

之前介绍的无状态应用, 看过的朋友一定有印象, 在 Deployment 控制器每次调度的时候, 比如关掉了一个 Pod, 然后再重新启动一个 Pod, 那 Pod 的名称一定是不相同的, 虽然前缀都一样, 但是后面的随机字符串每次都是不同的, 也就是如果之前对应服务保存了一些东西, 后面启动的 Pod 无法使用, 从这里就引申出了 能继续使用之前的比如持久化数据 , 也就是 有状态应用.

而有状态应用呢, 主要用于一些数据的保存和恢复, 简单来说就是, 可以恢复之前使用时的应用状态(信息及数据) .


Deployment VS StatefulSet

Deployment 中的Pod名称包含随机字符串, 索尼每次启动 Pod 的名称都不一样, 而 StatefulSet 每次启动的名称都会一样, Pod 名称是集群中的一个唯一标识.

基于 StatefulSet 创建的应用的启动顺序是有严格限制的, 其基于 init controller 实现. 当被创建的时候, StatefulSet 创建应用的顺序为 0 ~ N-1, 而删除的时候, 应用的终止顺序为 N-1 ~ 0. 而 Deployment 的创建是无序的.

当扩容的时候, 必须前面的 N 个容器都必须处于 Running 和 Ready 状态, 才能继续创建后面的容器.


Headless Service

在 StatefulSet 中, 使用的是 Headless Service (无头服务) , 与之前介绍的 Service 的区别就是它没有 Cluster IP, 解析它的名称的时候返回的是 该 Headless Service 对应的 Pod 的 Endpoint 列表 (也就是 Pod 列表, 在做微服务的时候, 使用它 – Headless Service 是个不错的选择).

Headless Service 在这里很重要, 因为它还会对 每个 Pod 都设置集群内部的一个 DNS 域名 , 集群中的 Pod 可以通过该域名相互通信.

Headless 下的 Pod 的 DNS 域名

$(podname).$(service name).$(namespace).svc.cluster.local

并且通过 statefulSet 创建的 有状态 Pod 的名称是在集群内部的唯一标识, 所以 通过这个域名访问到的, 可以确定就是集群内部的唯一的有状态的 Pod .


ConfigMap

本文会简单的使用到 Kubernetes 中的另一种资源类型 ConfigMap, 它可以作为环境变量、命令行参数或者存储卷中的配置文件, 它保存一些私密性不强的信息, 在这里我们使用它存储 redis 的一些简单配置.


配置文件 yaml

今天我们使用 redis 作为基础的容器镜像(这次放过nginx)


ConfigMap

在创建 StatefulSet 之前需要创建 存储redis配置的 configMap.

# ConfigMap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2020-09-07T12:01:49Z
name: lemonnan-redis-config
namespace: default
resourceVersion: "111"
selfLink: /api/v1/namespaces/default/configmaps/lemonnan-redis-config
uid: 11a0c66c-2d9a-4be9-b7ac-ec19037392a4
data:
redis-conf: |
appendonly yes
save 900 1
# cluster-enabled yes # 单机测试的时候先去掉这几个 cluster 的东西
# cluster-config-file /var/lib/redis/nodes.conf
# cluster-node-timeout 5000
dir /var/lib/redis # 用于存放数据的路径
port 6379


Headless Service

# headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: headless-service
spec:
selector:
app: label-redis # 管理拥有 app: label-redis 标签的Pod
ports:
- protocol: TCP
port: 6379
targetPort: 6379
clusterIP: None


StatefulSet

# Statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-redis
spec:
selector:
matchLabels:
app: label-redis
serviceName: headless-service
replicas: 1
template:
metadata:
labels:
app: label-redis
spec:
terminationGracePeriodSeconds: 30 # 默认30s
containers:
- name: pod-redis
imagePullPolicy: Never
image: redis:latest
command:
- redis-server # 使用指定路径 conf 启动redis
- "/etc/redis/redis.conf" # 使用 configMap 后存放的配置文件的路径
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: redis-conf # 配置文件 volume 名称
mountPath: /etc/redis # 容器中存储 redis.conf 的地址
- name: redis-data # 持久数据 volume 名称
mountPath: /var/lib/redis # 容器内的数据存放在这里(onfigMap 中的 dir 路径), 然后根据下面的 volume 模板进行数据持久化
volumes:
- name: redis-conf #
configMap:
name: lemonnan-redis-config # configMap 名称
items:
- key: redis-conf # configMap 名称
path: redis.conf # 这个是配置文件名称, 总的在容器中的路径就是 /etc/redis/redis.conf
volumeClaimTemplates: # 用于持久化的模板
- metadata:
name: redis-data
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200M


redis 单机

根据上面的配置文件创建好ConfigMap、Service、StatefulSet 之后, 创建redis单机相对来说还算是比较简单的, 基本上可以一路畅通无阻.


创建资源

创建 ConfigMap、HeadlessService、StatefulSet


进入redis pod


添加数据


重启 redis pod

使用 delete 命令, StatefulSet 会检测到 Pod 终止并且自动开启新的 Pod, 这里(箭头所指)的容器ID已经不一样了.


查看数据恢复

最后进入到重启后的 redis Pod, 检查上一次 Pod 关闭前添加进去的数据, 有没有持久化下来.


redis 集群

如果要设置redis集群的话, 需要在单机的基础上修改一下东西

1.首先需要把 ConfigMap 中关于 cluster 的信息打开

2.在 StatefulSet.yaml 中设置 spec.replicas: 6(3主3从), 并且在所有 redis启动后, 设置相应的集群信息.


修改配置

下面是修改后的配置

ConfigMap.yaml

# Configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: 2020-09-07T12:01:49Z
name: lemonnan-redis-config
namespace: default
resourceVersion: "111"
selfLink: /api/v1/namespaces/default/configmaps/lemonnan-redis-config
uid: 11a0c66c-2d9a-4be9-b7ac-ec19037392a4
data:
redis-conf: |
appendonly yes
save 900 1
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

StatefulSet.yaml

# StatefulSet.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-redis
spec:
selector:
matchLabels:
app: label-redis
serviceName: headless-service
replicas: 6
template:
metadata:
labels:
app: label-redis
spec:
terminationGracePeriodSeconds: 30 # 默认30s
containers:
- name: pod-redis
imagePullPolicy: Never
image: redis:latest
command:
- redis-server # 使用指定路径 conf 启动redis
- "/etc/redis/redis.conf" # 使用 configMap 后存放的配置文件的路径
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: redis-conf # 配置文件 volume 名称
mountPath: /etc/redis # 容器中存储 redis.conf 的地址
- name: redis-data # 持久数据 volume 名称
mountPath: /var/lib/redis # 容器内的数据存放在这里(onfigMap 中的 dir 路径), 然后根据下面的 volume 模板进行数据持久化
volumes:
- name: redis-conf #
configMap:
name: lemonnan-redis-config # configMap 名称
items:
- key: redis-conf # configMap 名称
path: redis.conf # 这个是配置文件名称, 总的在容器中的路径就是 /etc/redis/redis.conf
volumeClaimTemplates: # 用于持久化的模板
- metadata:
name: redis-data
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200M

创建完成之后,接下来开始配置 redis-cluster

首先根据之前 Headless 创建的 Pod 域名为

$(podname).$(service name).$(namespace).svc.cluster.local

so, 这里的话应该是

redis-app-0.headless-service.default.svc.cluster.local:6379
redis-app-1.headless-service.default.svc.cluster.local:6379
redis-app-2.headless-service.default.svc.cluster.local:6379
redis-app-3.headless-service.default.svc.cluster.local:6379
redis-app-4.headless-service.default.svc.cluster.local:6379
redis-app-5.headless-service.default.svc.cluster.local:6379

由于 redis-cluster 目前的版本还不支持域名的配置, so 这里我们还是使用 IP 进行搭建, 最终在redis Pod 中执行以下命令构建redis集群:

注意: 在执行下面的命令的时候, 如果是从上面过来的, 需要先将 /var/lib/redis 下的文件都删掉, 否则集群创建失败.

# 这几个是我本机上的redis pod 的ip地址
redis-cli --cluster create --cluster-replicas 1 \
172.17.0.2:6379 \
172.17.0.6:6379 \
172.17.0.7:6379 \
172.17.0.8:6379 \
172.17.0.9:6379 \
172.17.0.10:6379

创建结果

集群创建成功了, 然后测试设置数据

redis-cli 启动不加 -c 参数的话, 会报 MOVED 错误, 需要自己找到对应的redis节点进行设置, 加了 -c 参数后会自动重定向到对应节点, 具体见下图

到这里redis集群的搭建也完成了


总结

本文介绍了有状态应用相关的东西, 看似挺有用的, 能持久化数据, 宕机恢复后还能继续使用之前已经持久化下来的数据, 但实际上, 一般比较重要的组件/数据不会使用容器运行, 比如数据库, 有以下几个重要的原因:

1.容器占用资源过多很有可能会被 OS kill 掉, 而像数据库这样的组件被 kill 掉基本上就意味着数据丢失.

2.容器是在 OS 层面上做的一个逻辑层, 有一定的性能损耗, 并且数据库的成本也是很高的. 像比如传统的关系型数据库, 一般配置不高的服务器 TPS 本身就不高, 再弄一个逻辑层损耗一下性能, TPS 就更低了( 钱突然就没了 ).

so, 有状态应用的话一般使用也是用于存储一些不太重要的数据, 数据库这种存储比较重要信息的组件基本上不会使用容器进行管理.



推荐阅读
  • Envoy 流量分配策略优化
    在本研究中,我们对Envoy的流量分配策略进行了优化,旨在提高系统的稳定性和性能。实验环境包括一个前端代理服务(Envoy,IP地址为172.31.57.10)和五个后端服务。通过调整Envoy的配置,实现了更高效的流量分发和负载均衡,显著提升了整体系统的响应速度和可靠性。 ... [详细]
  • Ceph API微服务实现RBD块设备的高效创建与安全删除
    本文旨在实现Ceph块存储中RBD块设备的高效创建与安全删除功能。开发环境为CentOS 7,使用 IntelliJ IDEA 进行开发。首先介绍了 librbd 的基本概念及其在 Ceph 中的作用,随后详细描述了项目 Gradle 配置的优化过程,确保了开发环境的稳定性和兼容性。通过这一系列步骤,我们成功实现了 RBD 块设备的快速创建与安全删除,提升了系统的整体性能和可靠性。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 解读中台架构:微服务与分布式技术的区别及应用
    中心化与去中心化是长期讨论的话题。中心化架构的优势在于部署和维护相对简单,尤其在服务负载较为稳定的情况下,能够提供高效稳定的性能。然而,随着业务规模的扩大和技术需求的多样化,中心化架构的局限性逐渐显现,如扩展性和故障恢复能力较差。相比之下,微服务和分布式技术通过解耦系统组件,提高了系统的灵活性和可扩展性,更适合处理复杂多变的业务场景。本文将深入探讨中台架构中微服务与分布式技术的区别及其应用场景,帮助读者更好地理解和选择适合自身业务的技术方案。 ... [详细]
  • 基于域名、端口和IP的虚拟主机构建方案
    本文探讨了在单台物理服务器上构建多个Web站点的虚拟主机方案,详细介绍了三种主要的虚拟主机类型:基于域名、基于IP地址和基于端口的虚拟主机。每种类型的实现方式及其优缺点均进行了深入分析,为实际应用提供了全面的技术指导。 ... [详细]
  • 人人租机作为国内领先的信用免押租赁平台,为企业和个人提供全方位的新租赁服务。通过接入支付宝小程序功能,该平台实现了从零到百的迅猛增长,成为全国首家推出“新租赁小程序”开发服务的阿里巴巴小程序服务商(ISV)。这一创新举措不仅提升了用户体验,还显著增强了平台的市场竞争力。 ... [详细]
  • 本文深入探讨了Spring Cloud Eureka在企业级应用中的高级使用场景及优化策略。首先,介绍了Eureka的安全配置,确保服务注册与发现过程的安全性。接着,分析了Eureka的健康检查机制,提高系统的稳定性和可靠性。随后,详细讨论了Eureka的各项参数调优技巧,以提升性能和响应速度。最后,阐述了如何实现Eureka的高可用性部署,保障服务的连续性和可用性。通过这些内容,开发者可以更好地理解和运用Eureka,提升微服务架构的整体效能。 ... [详细]
  • 如何正确配置与使用日志组件:Log4j、SLF4J及Logback的连接与整合方法
    在当前的软件开发实践中,无论是开源项目还是日常工作中,日志框架都是不可或缺的工具之一。本文详细探讨了如何正确配置与使用Log4j、SLF4J及Logback这三个流行的日志组件,并深入解析了它们之间的连接与整合方法,旨在帮助开发者高效地管理和优化日志记录流程。 ... [详细]
  • 腾讯与阅文集团在技术领域展开合作,共同推进微服务框架Tars的发展。此次合作中,Tars新增了对PHP语言的支持,不仅强化了Tars-PHP作为客户端的功能,还显著提升了其在服务端的应用能力。这一改进旨在满足不同业务场景下的多样化需求,为开发者提供更加灵活和高效的技术解决方案。 ... [详细]
  • 阿里巴巴Java后端开发面试:TCP、Netty、HashMap、并发锁与红黑树深度解析 ... [详细]
  • 万物智联新时代!跨时代的智慧综合体开启全新领域探索
    万物智联新时代!跨时代的智慧综合体开启全新领域探索 ... [详细]
  • 工程项目管理系统源码简洁+好用+全面工程项目管理系统
    ​​工程项目管理系统是指从事工程项目管理的企业(以下简称工程项目管理企业)受业主委托,按照合同约定,代表业主对工程项目的组织 ... [详细]
  • 本文详细介绍了如何在Java Web服务器上部署音视频服务,并提供了完整的验证流程。以AnyChat为例,这是一款跨平台的音视频解决方案,广泛应用于需要实时音视频交互的项目中。通过具体的部署步骤和测试方法,确保了音视频服务的稳定性和可靠性。 ... [详细]
  • MySQL性能优化与调参指南【数据库管理】
    本文详细探讨了MySQL数据库的性能优化与参数调整技巧,旨在帮助数据库管理员和开发人员提升系统的运行效率。内容涵盖索引优化、查询优化、配置参数调整等方面,结合实际案例进行深入分析,提供实用的操作建议。此外,还介绍了常见的性能监控工具和方法,助力读者全面掌握MySQL性能优化的核心技能。 ... [详细]
  • DHCP三层交换机设置方式全局模式和接口模式设置方式和命令resetsave回车输入yreboot输入n输入y重启后就恢复默认设置了默认用户名密码adminAdmin@huawei ... [详细]
author-avatar
Q_jack
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有