Kubernetes 因其快速部署新应用程序的能力而广受欢迎。得益于“基础设施即数据”(特别是 YAML),今天您可以表达所有 Kubernetes 资源,例如 Pod, 部署, 服务, 卷等,在 YAML 文件中。这些默认对象使 DevOps 和 SRE 工程师更容易完全表达其工作负载,而无需学习如何在 Python、Java 或 Ruby 等编程语言中编写代码。
Kubernetes 专为自动化而设计。开箱即用,您从 Kubernetes 的核心获得了大量内置自动化功能。它可以通过简化、自动化的部署、更新(滚动更新)以及几乎零停机时间地管理您的应用程序和服务来加快您的开发过程。但是,Kubernetes 本身无法为有状态应用程序自动执行该过程。例如,假设您在多个节点上运行了一个有状态的工作负载,例如数据库应用程序。如果大部分节点都宕机了,您将需要根据特定步骤从特定快照中重新加载数据库。使用 Kubernetes 中现有的默认对象、类型和控制器,这将无法实现。
想想为有状态应用程序扩展节点,或升级到新版本,或进行灾难恢复——这些操作通常需要非常具体的步骤,并且通常需要人工干预。Kubernetes 不可能了解所有有状态的、复杂的、集群化的应用程序。Kubernetes 本身不知道,例如,Redis 数据库集群的配置值,以及其排列的成员资格和有状态的、持久性的存储。此外,在 Kubernetes 中扩展有状态应用程序并非易事,需要人工干预。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: web
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
在上面的示例中,名为 nginx-deployment
的部署对象是在命名空间“web”下创建的,由 .metadata.name
字段指示。它创建了两个复制的 Pod,由 .spec.replicas
字段指示。 .spec.selector
字段定义了部署如何找到要管理的 Pod。在这种情况下,您选择一个在 Pod 模板中定义的标签(app: nginx)。模板字段包含以下子字段:Pod 使用 .metadata.labels
字段标记为 app: nginx
,并且 Pod 模板的规范指示 Pod 运行一个容器 nginx,它运行 Docker Hub 镜像中的 nginx,版本为 1.14.2。最后,它创建一个容器并将其命名为 nginx。
运行以下命令以创建部署资源
kubectl create -f nginx-dep.yaml
让我们通过运行以下命令来验证部署是否成功创建
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 63s
上面的示例显示了命名空间中的部署名称。它还显示了对用户可用的应用程序副本数量。您还可以看到,已更新的所需副本数量为 2,以实现所需状态。
您可以运行 kubectl describe
命令以获取部署资源的详细信息。要显示特定资源或一组资源的详细信息:
kubectl describe deploy
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 30 Dec 2019 07:10:33 +0000
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 0 available | 2 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.7.9
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available False MinimumReplicasUnavailable
Progressing True ReplicaSetUpdated
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-6dd86d77d (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 90s deployment-controller Scaled up replica set nginx-deployment-6dd86d77d to 2
部署负责保持一组 Pod 运行,但同样重要的是公开这些 Pod 的接口,以便其他外部进程可以访问它们。这就是服务资源的作用。服务资源让您可以公开在 Pod 中运行的应用程序,使其可从集群外部访问。让我们创建一个服务资源定义,如下所示
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: LoadBalancer
上面的 YAML 规范创建一个名为“nginx-service”的新服务对象,它针对任何带有 app=nginx
标签的 Pod 的 TCP 端口 80。
kubectl get svc -n web
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service LoadBalancer 10.107.174.108 localhost 80:31596/TCP 46s
让我们将部署扩展到 4 个副本。我们将使用 kubectl scale
命令,后跟部署类型、名称和所需的实例数量。输出类似于此:
kubectl scale deployments/nginx-deployment --replicas=4
deployment.extensions/nginx-deployment scaled
已应用更改,我们有 4 个应用程序实例可用。接下来,让我们检查 Pod 的数量是否发生了变化。现在应该有 4 个 Pod 在集群中运行(如下面的图表所示)
kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 4/4 4 4 4m
有 4 个 Pod,具有不同的 IP 地址。更改已在部署事件日志中注册。
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-6dd86d77d-b4v7k 1/1 Running 0 4m32s 10.1.0.237 docker-desktop none none
nginx-deployment-6dd86d77d-bnc5m 1/1 Running 0 4m32s 10.1.0.236 docker-desktop none none
nginx-deployment-6dd86d77d-bs6jr 1/1 Running 0 86s 10.1.0.239 docker-desktop none none
nginx-deployment-6dd86d77d-wbdzv 1/1 Running 0 86s 10.1.0.238 docker-desktop none none
删除其中一个 Web 服务器 Pod 将触发控制平面中的工作,以恢复四个副本的所需状态。Kubernetes 启动一个新的 Pod 来替换已删除的 Pod。在本节中,替换的 Pod 显示了 STATUS 为 ContainerCreating
kubectl delete pod nginx-deployment-6dd86d77d-b4v7k
您会注意到,Nginx 静态 Web 服务器可以与任何其他副本或替换其中一个副本的新 Pod 交换。它不以任何方式存储数据或维护状态。Kubernetes 不需要做任何特殊安排来替换失败的 Pod,或通过添加或删除服务器副本来扩展应用程序。现在您可能在想,如果要存储应用程序的状态怎么办?好问题。
在 Kubernetes 中扩展无状态应用程序很容易,但有状态应用程序并非如此。有状态应用程序需要人工干预。上下启停 Pod 并不那么简单。每个节点都有一个标识,并附带一些数据。删除 Pod 意味着丢失其数据并中断系统。
考虑一个 Kubernetes 集群,其中 6 个工作节点托管一个 Nginx Web 应用程序,该应用程序连接到一个持久性卷,如上所示。以下是 StatefulSets YAML 文件的代码片段
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
Kubernetes 将物理存储设备以名为 持久卷 的对象的形式提供给您的集群。每个持久卷都由一个 Kubernetes Pod 通过发出 持久卷声明 对象(也称为 PVC)来使用。PVC 对象允许 Pod 使用持久卷中的存储。假设我们要将一个集群从 5 个节点缩减到 3 个节点。突然移除 2 个节点是一个可能造成破坏的操作。这可能会导致所有数据副本丢失。处理节点移除的更好方法是,在执行实际的 Pod 删除操作之前,先将要移除的节点上的数据迁移到系统中的其他节点。需要注意的是,StatefulSet 控制器本质上是通用的,它不可能知道所有可能的管理数据迁移和复制的方法。然而,在实际应用中,StatefulSet 通常不足以处理生产环境中复杂、分布式有状态工作负载系统。
那么,如何解决这个问题呢?这就是 Operator 的作用。Operator 的开发是为了处理默认 Kubernetes 控制器无法处理的复杂、有状态应用程序。虽然像 StatefulSet 这样的 Kubernetes 控制器非常适合部署、维护和扩展简单的无状态应用程序,但它们不具备处理有状态资源的访问,也不具备升级、调整大小和备份更复杂的集群应用程序(如数据库)的功能。Kubernetes Operator 弥合了 Kubernetes 提供的功能和自动化与您的软件如何使用 Kubernetes 之间的差距,实现了与您的软件相关的任务自动化。
Operator 本质上是一个特定于应用程序的控制器,可以帮助您管理 Kubernetes 应用程序。它是一种打包、运行和维护 Kubernetes 应用程序的方式。它旨在扩展 Kubernetes 的功能,并简化应用程序管理。这对于有状态应用程序尤其有用,因为有状态应用程序包括持久存储和其他应用程序外部的元素,可能需要额外的工作来管理和维护。
Kubernetes Operator 使用 Kubernetes API 代表 Kubernetes 用户创建、配置和管理复杂有状态应用程序的实例。有一个名为 OperatorHub.io 的公共存储库,旨在成为查找 Kubernetes Operator 后端服务的公共注册中心。通过 Operator Hub,开发人员可以轻松地基于 Operator 创建应用程序,而无需从头开始构建 Operator 的复杂性。
以下是几个流行的 Kubernetes Operator 及其功能和能力的示例。
Operator 通过扩展 Kubernetes 控制平面和 API 来工作。Operator 允许您定义一个自定义控制器,该控制器会监视您的应用程序并根据其状态执行自定义任务。您要监视的应用程序通常在 Kubernetes 中定义为一个新对象:一个 自定义资源 (CR),它具有自己的 YAML 规范和对象类型,API 服务器可以很好地理解。这样,您就可以在自定义规范中定义任何特定条件来监视,并在实例与规范不匹配时对其进行协调。Operator 的控制器与规范进行协调的方式与本机 Kubernetes 控制器非常类似,尽管它主要使用自定义组件。
Redis 创建了一个 Operator,它部署并管理 Redis Enterprise Cluster 的生命周期。 Redis Enterprise Operator 是在 Kubernetes 中部署和维护 Redis Enterprise 集群最快、最有效的方式。Operator 从单个 Kubernetes 控制平面创建、配置和管理 Redis Enterprise 部署。这意味着您可以通过创建本机对象(如部署、副本集、有状态集等)来管理 Kubernetes 上的 Redis Enterprise 实例。Operator 允许完全控制 Redis Enterprise 集群的生命周期。
Redis Enterprise Operator 充当 自定义控制器,用于自定义资源 Redis Enterprise Cluster,或 “REC”,它通过 Kubernetes CRD (客户资源定义) 定义,并使用 YAML 文件部署。Redis Enterprise Operator 充当 Kubernetes 基础设施和 Redis Enterprise 集群之间的逻辑“粘合剂”。
Redis Enterprise Operator 支持两个自定义资源定义 (CRD)
它的工作原理如下
考虑下面的 YAML 文件
apiVersion: app.redislabs.com/v1
kind: RedisEnterpriseCluster
metadata:
name: rec
spec:
# Add fields here
nodes: 3
如果您将节点数量更改为 5,Operator 会与 StatefulSet 交谈,并将副本数量从 3 更改为 5。一旦发生这种情况,Kubernetes 将接管并一次启动一个新节点,并相应地部署 Pod。当每个节点就绪后,新节点将加入集群并变为可用于 Redis Enterprise 主节点。
apiVersion: app.redislabs.com/v1
kind: RedisEnterpriseDatabase
metadata:
name: redis-enterprise-database
spec:
redisEnterpriseCluster:
name: redis-enterprise
Memory: 2G
为了创建数据库,Operator 会发现资源,与集群 RestAPI 交谈,然后创建数据库。服务器与 API 交谈并发现它。DB 为该数据库创建 Redis 数据库服务端点,该端点将可用。
在下一教程中,您将学习如何从头开始使用 Redis Enterprise Kubernetes Operator,包括如何执行非平凡的任务,如备份、还原、横向扩展等等。敬请关注!
确保您的系统中安装了 Docker。
如果您是新手,请参考 Docker 的安装指南 在 Mac 上安装 Docker。
要拉取并启动 Redis Enterprise 软件 Docker 容器,请在您的操作系统的终端或命令行中运行此 docker run 命令。