MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Redis在容器化与Kubernetes中的部署实践

2022-06-276.3k 阅读

一、Redis 简介

Redis 是一个开源的,基于内存的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 支持多种数据结构,如字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等,这使得它在不同的应用场景中都表现出色。例如,在 Web 应用中,Redis 可以作为缓存来存储经常访问的数据,从而减少数据库的负载;在实时分析场景中,Redis 可以用来存储和处理实时数据。

二、容器化技术基础

2.1 容器化概述

容器化技术是一种轻量级的虚拟化技术,它允许将应用程序及其依赖项打包到一个独立的、可移植的单元中,这个单元就是容器。与传统的虚拟机不同,容器共享宿主机的操作系统内核,因此容器启动速度更快,占用资源更少。容器化技术的核心优势在于可移植性、隔离性和易于部署,这使得应用程序可以在不同的环境中快速、一致地运行。

2.2 Docker 基础

Docker 是目前最流行的容器化平台之一。Docker 使用镜像(image)来构建容器,镜像是一个只读的模板,包含了运行应用程序所需的所有文件系统和配置。例如,我们可以创建一个包含 Redis 及其依赖的 Docker 镜像。通过以下命令可以在本地构建一个简单的 Docker 镜像:

# 使用官方 Redis 镜像作为基础
FROM redis:latest

# 设置工作目录
WORKDIR /app

# 可以将自定义配置文件复制到容器内
COPY redis.conf.

# 启动 Redis 服务
CMD ["redis-server", "redis.conf"]

上述 Dockerfile 首先指定了基于官方最新的 Redis 镜像,然后设置了工作目录,将自定义的 redis.conf 配置文件复制到容器内,最后启动 Redis 服务并加载自定义配置。通过 docker build -t my - redis:v1.0. 命令可以构建该镜像,其中 -t 用于指定镜像的标签(tag),. 表示当前目录。

三、Kubernetes 基础

3.1 Kubernetes 架构

Kubernetes(简称 K8s)是一个开源的容器编排系统,用于自动化部署、扩展和管理容器化应用程序。Kubernetes 架构主要由控制平面(Control Plane)和节点(Nodes)组成。控制平面负责管理集群的状态和资源,包括 API Server、Scheduler、Controller Manager 等组件。节点则是运行容器化应用的工作机器,每个节点上都运行着 kubelet、kube - proxy 等组件。

3.2 Kubernetes 资源对象

  1. Pod:Pod 是 Kubernetes 中最小的可部署和可管理的计算单元,一个 Pod 可以包含一个或多个紧密相关的容器。例如,我们可以创建一个包含 Redis 容器的 Pod。以下是一个简单的 Redis Pod 的 YAML 定义:
apiVersion: v1
kind: Pod
metadata:
  name: redis - pod
spec:
  containers:
  - name: redis - container
    image: redis:latest
    ports:
    - containerPort: 6379

上述 YAML 文件定义了一个名为 redis - pod 的 Pod,其中包含一个名为 redis - container 的容器,使用官方最新的 Redis 镜像,并暴露容器的 6379 端口。

  1. Service:Service 为一组 Pod 提供了一个稳定的网络端点。它可以将外部流量路由到对应的 Pod 上。对于 Redis,我们可以创建一个 ClusterIP 类型的 Service 来在集群内部提供服务,或者创建一个 NodePort 类型的 Service 来暴露服务到集群外部。以下是创建 ClusterIP 类型 Service 的 YAML 示例:
apiVersion: v1
kind: Service
metadata:
  name: redis - service
spec:
  selector:
    app: redis
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
  type: ClusterIP

上述 YAML 定义了一个名为 redis - service 的 Service,它通过 selector 选择标签为 app: redis 的 Pod,并将集群内部发往 6379 端口的 TCP 流量转发到这些 Pod 的 6379 端口上。

四、Redis 在容器化中的部署

4.1 单机 Redis 容器部署

  1. 拉取 Redis 镜像:首先,我们可以从 Docker Hub 拉取官方的 Redis 镜像。在终端中执行以下命令:
docker pull redis:latest
  1. 运行 Redis 容器:拉取镜像后,可以使用以下命令运行 Redis 容器:
docker run -d --name my - redis - container -p 6379:6379 redis:latest

上述命令中,-d 表示以守护进程模式运行容器,--name 为容器指定名称为 my - redis - container-p 将宿主机的 6379 端口映射到容器的 6379 端口,最后指定使用的镜像为 redis:latest。此时,我们就可以通过宿主机的 6379 端口访问 Redis 服务了。

4.2 配置 Redis 容器

在实际应用中,我们可能需要对 Redis 进行一些配置。可以通过挂载配置文件的方式来实现。首先,在本地创建一个 redis.conf 配置文件,例如:

# 开启持久化
appendonly yes
# 设置密码
requirepass mypassword

然后,使用以下命令运行 Redis 容器并挂载配置文件:

docker run -d --name my - redis - container -p 6379:6379 -v /path/to/redis.conf:/usr/local/etc/redis/redis.conf redis:latest redis - server /usr/local/etc/redis/redis.conf

上述命令中,-v 选项将本地的 redis.conf 配置文件挂载到容器内的 /usr/local/etc/redis/redis.conf 路径,并且指定 Redis 启动时加载该配置文件。

五、Redis 在 Kubernetes 中的部署

5.1 部署 Redis 单实例

  1. 创建 Redis Pod:我们已经在前面展示了 Redis Pod 的 YAML 定义,现在假设将其保存为 redis - pod.yaml。通过以下命令创建 Pod:
kubectl apply -f redis - pod.yaml
  1. 创建 Redis Service:同样,对于前面定义的 redis - service.yaml,使用以下命令创建 Service:
kubectl apply -f redis - service.yaml

此时,我们可以通过 redis - service 的 ClusterIP 在集群内部访问 Redis 服务。如果要在集群外部访问,可以将 Service 的类型改为 NodePort,并指定一个节点端口范围,例如:

apiVersion: v1
kind: Service
metadata:
  name: redis - service
spec:
  selector:
    app: redis
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
    nodePort: 30000
  type: NodePort

然后重新应用该 YAML 文件(kubectl apply -f redis - service.yaml),就可以通过任意节点的 30000 端口访问 Redis 服务。

5.2 部署 Redis 主从复制集群

  1. 主节点部署
    • 首先创建主节点的 Redis Pod。以下是一个主节点 Redis Pod 的 YAML 示例:
apiVersion: v1
kind: Pod
metadata:
  name: redis - master - pod
  labels:
    app: redis
    role: master
spec:
  containers:
  - name: redis - master - container
    image: redis:latest
    ports:
    - containerPort: 6379
    command: ["redis - server"]
    args: ["--appendonly", "yes"]
  • 创建主节点的 Service:
apiVersion: v1
kind: Service
metadata:
  name: redis - master - service
spec:
  selector:
    app: redis
    role: master
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
  type: ClusterIP
  1. 从节点部署
    • 从节点的 Redis Pod 需要配置 slaveof 指向主节点。以下是从节点 Redis Pod 的 YAML 示例:
apiVersion: v1
kind: Pod
metadata:
  name: redis - slave - pod -1
  labels:
    app: redis
    role: slave
spec:
  containers:
  - name: redis - slave - container -1
    image: redis:latest
    ports:
    - containerPort: 6379
    command: ["redis - server"]
    args: ["--slaveof", "redis - master - service", "6379"]
  • 从节点也可以创建对应的 Service,以便于管理和发现:
apiVersion: v1
kind: Service
metadata:
  name: redis - slave - service
spec:
  selector:
    app: redis
    role: slave
  ports:
  - protocol: TCP
    port: 6379
    targetPort: 6379
  type: ClusterIP

通过上述步骤,我们可以在 Kubernetes 集群中部署一个简单的 Redis 主从复制集群。主节点通过 redis - master - service 提供服务,从节点通过 slaveof 配置指向主节点,实现数据的复制。

5.3 部署 Redis Sentinel 集群

  1. Redis Sentinel 简介:Redis Sentinel 是 Redis 的高可用性解决方案,它可以监控 Redis 主从集群,在主节点出现故障时自动进行故障转移,将一个从节点提升为主节点。
  2. 部署 Redis Sentinel
    • 首先创建 Redis Sentinel 的配置文件 sentinel.conf
port 26379
sentinel monitor mymaster redis - master - service 6379 2
sentinel down - after - milliseconds mymaster 5000
sentinel failover - timeout mymaster 10000

上述配置中,sentinel monitor 用于指定要监控的主节点,mymaster 是主节点的名称,redis - master - service 是主节点的 Service 名称,2 表示需要至少 2 个 Sentinel 节点同意才能进行故障转移。

  • 然后创建 Redis Sentinel 的 Pod:
apiVersion: v1
kind: Pod
metadata:
  name: sentinel - pod -1
  labels:
    app: sentinel
spec:
  containers:
  - name: sentinel - container -1
    image: redis:latest
    ports:
    - containerPort: 26379
    command: ["redis - sentinel"]
    args: ["/etc/redis/sentinel.conf"]
    volumeMounts:
    - name: sentinel - config
      mountPath: /etc/redis
  volumes:
  - name: sentinel - config
    configMap:
      name: sentinel - config - map
  • 上述 Pod 定义中,通过 volumeMountsvolumes 将名为 sentinel - config - map 的 ConfigMap 挂载到容器内的 /etc/redis 路径,该 ConfigMap 包含了 sentinel.conf 配置文件。

  • 创建 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: sentinel - config - map
data:
  sentinel.conf: |
    port 26379
    sentinel monitor mymaster redis - master - service 6379 2
    sentinel down - after - milliseconds mymaster 5000
    sentinel failover - timeout mymaster 10000
  • 可以创建多个 Sentinel Pod 来提高 Sentinel 集群的可靠性。通过以上步骤,我们可以在 Kubernetes 集群中部署一个 Redis Sentinel 集群,实现 Redis 主从集群的高可用性。

六、Redis 在 Kubernetes 中的持久化

6.1 使用 EmptyDir 卷

  1. EmptyDir 卷简介:EmptyDir 卷是 Kubernetes 中一种最简单的卷类型,它在 Pod 创建时被创建,在 Pod 销毁时被删除。EmptyDir 卷的数据存储在宿主机的磁盘上,不同容器可以通过挂载同一个 EmptyDir 卷来共享数据。
  2. 为 Redis Pod 添加 EmptyDir 卷:以下是一个修改后的 Redis Pod YAML,添加了 EmptyDir 卷来实现持久化:
apiVersion: v1
kind: Pod
metadata:
  name: redis - pod - with - persistence
spec:
  containers:
  - name: redis - container
    image: redis:latest
    ports:
    - containerPort: 6379
    volumeMounts:
    - name: redis - data
      mountPath: /data
  volumes:
  - name: redis - data
    emptyDir: {}

上述 YAML 中,通过 volumeMounts 将名为 redis - data 的 EmptyDir 卷挂载到容器内的 /data 路径,Redis 默认会将持久化文件(如 AOF 或 RDB 文件)存储在 /data 目录下,从而实现数据在 Pod 生命周期内的持久化。但需要注意的是,如果 Pod 被重新调度到其他节点,数据不会跟随迁移。

6.2 使用 PersistentVolume 和 PersistentVolumeClaim

  1. PersistentVolume(PV)和 PersistentVolumeClaim(PVC)简介:PersistentVolume 是集群中由管理员预先配置的一段存储,它是独立于 Pod 存在的。PersistentVolumeClaim 则是用户对存储的请求,通过 PVC 可以动态绑定到合适的 PV 上。
  2. 创建 PV:以下是一个 NFS 类型 PV 的 YAML 示例:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: redis - pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: nfs - server - ip
    path: /exports/redis - data

上述 PV 定义了 1GB 的存储空间,访问模式为 ReadWriteOnce(表示可以被单个节点以读写模式挂载),回收策略为 Retain(表示当 PVC 被删除时,PV 不会被自动删除,数据会保留),并指定了 NFS 服务器的地址和共享路径。

  1. 创建 PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis - pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  1. 修改 Redis Pod 使用 PVC
apiVersion: v1
kind: Pod
metadata:
  name: redis - pod - with - pvc
spec:
  containers:
  - name: redis - container
    image: redis:latest
    ports:
    - containerPort: 6379
    volumeMounts:
    - name: redis - data
      mountPath: /data
  volumes:
  - name: redis - data
    persistentVolumeClaim:
      claimName: redis - pvc

通过以上步骤,Redis Pod 可以使用 PersistentVolume 和 PersistentVolumeClaim 来实现数据的持久化,并且数据可以在 Pod 重新调度时保持一致。

七、监控与维护 Redis 在容器化和 Kubernetes 环境中的运行

7.1 监控 Redis 指标

  1. Redis 内置指标:Redis 提供了一些内置的命令来获取运行时指标,例如 INFO 命令。可以通过 Redis 客户端连接到 Redis 服务并执行 INFO 命令,它会返回 Redis 的各种信息,包括服务器信息、内存使用、持久化状态、客户端连接等。
  2. 在 Kubernetes 中监控:可以使用 Prometheus 和 Grafana 来监控 Redis 在 Kubernetes 集群中的运行状态。首先,需要部署 Prometheus 的 Redis 监控 Exporter,例如 redis - exporter。以下是一个简单的 redis - exporter Deployment 的 YAML 示例:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis - exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis - exporter
  template:
    metadata:
      labels:
        app: redis - exporter
    spec:
      containers:
      - name: redis - exporter
        image: oliver006/redis - exporter:v1.33.0
        args:
          - --redis.addr=redis - service:6379
          - --redis.password=mypassword
        ports:
        - containerPort: 9121

上述 Deployment 部署了 redis - exporter,并指定了要监控的 Redis 服务地址和密码。然后,配置 Prometheus 来抓取 redis - exporter 暴露的指标,最后通过 Grafana 创建仪表盘来展示 Redis 的各项指标,如内存使用率、请求速率等。

7.2 维护 Redis 集群

  1. 节点健康检查:在 Kubernetes 中,可以通过 Kubernetes 的健康检查机制来确保 Redis Pod 的健康运行。在 Redis Pod 的 YAML 中,可以添加 livenessProbereadinessProbe。例如:
apiVersion: v1
kind: Pod
metadata:
  name: redis - pod - with - probes
spec:
  containers:
  - name: redis - container
    image: redis:latest
    ports:
    - containerPort: 6379
    livenessProbe:
      exec:
        command: ["redis - cli", "ping"]
      initialDelaySeconds: 5
      periodSeconds: 10
    readinessProbe:
      exec:
        command: ["redis - cli", "ping"]
      initialDelaySeconds: 5
      periodSeconds: 10

上述 YAML 中,livenessProbereadinessProbe 都通过执行 redis - cli ping 命令来检查 Redis 是否健康运行,initialDelaySeconds 表示在容器启动后等待 5 秒开始检查,periodSeconds 表示每隔 10 秒检查一次。如果 livenessProbe 检查失败,Kubernetes 会自动重启容器;如果 readinessProbe 检查失败,该 Pod 不会被加入到 Service 的端点中,从而避免将流量发送到不健康的 Pod。 2. 升级与回滚:在 Kubernetes 中,可以使用 kubectl 命令来进行 Redis 应用的升级和回滚。例如,要升级 Redis 镜像版本,可以修改 Deployment 的 YAML 中镜像的标签,然后执行 kubectl apply -f redis - deployment.yaml。如果升级过程中出现问题,可以通过 kubectl rollout undo deployment/redis - deployment 命令回滚到上一个版本。

通过以上监控和维护措施,可以确保 Redis 在容器化和 Kubernetes 环境中稳定、可靠地运行。在实际生产环境中,还需要根据具体的业务需求和性能要求进行进一步的优化和调整。例如,根据 Redis 的负载情况动态调整集群的节点数量,优化持久化策略以平衡性能和数据安全性等。同时,随着业务的发展和变化,不断关注 Redis 技术的更新和 Kubernetes 功能的增强,以提升整个系统的运行效率和可靠性。