kubernetes - 使用与 StatefulSet 中其他 1 个 Pod 相同的 PVC 来安排作业

标签 kubernetes kubernetes-statefulset kubernetes-cronjob

在 Kubernetes 集群中,我希望能够安排一个作业(使用 CronJob),该作业将挂载与给定 StatefulSet 的 1 个 Pod 相同的卷。哪个 Pod 是运行时决定的,具体取决于调度作业时 Pod 上设置的标签。

我想很多人会想知道为什么,因此描述一下我们正在做的事情和尝试做的事情:

当前设置

我们有一个 StatefulSet,它为 PostgreSQL 数据库提供服务。 (一个主库,多个副本) 我们希望能够从 StatefulSet 的 Pod 之一创建备份。

对于 PostgreSQL,我们已经可以使用 pg_basebackup 通过网络进行备份,但是我们正在运行多 TB PostgreSQL 数据库,这意味着完全流式备份(使用 pg_basebackup)不可行。

我们目前使用 pgBackRest 来备份数据库,它允许增量备份。

由于pgBackRest的增量备份需要访问数据卷和WAL卷,因此我们需要在与PostgreSQL实例相同的Kubernetes节点上运行备份容器,目前我们甚至在内部运行它同一 Pod 位于单独的 Container 中。

在容器内部,一个小型 api 包裹着 pgBackRest,并且可以通过向该 api 发送 POST 请求来触发,此触发目前是使用 CronJobs 完成的。

缺点

  • 每个 PostgreSQL 实例在 Pod 中都有多个容器,1 个用于服务 Postgres,1 个用于服务 pgBackRest 的小型包装器
  • 作业日志仅显示成功的备份触发器,实际的备份日志是备份容器的一部分
  • 将运行备份的 Pod 可能会在相对较旧的配置上运行,更改备份配置需要重新安排 Pod,这可能意味着 PostgreSQL 主节点的故障转移。

建议的设置

让 CronJob 调度一个与 StatefulSet 的 1 个 Pod 具有相同卷的 Pod。这将允许备份使用这些卷。

但是,它需要哪些卷是运行时决定的:我们可能希望在连接到主卷的卷上运行备份,或者我们可能希望使用副本的卷进行备份。主/副本可能随时发生变化,因为 PostgreSQL 主的自动故障转移是解决方案的一部分。

目前,这是不可能的,因为我无法在 CronJob 规范中找到任何方法来使用 k8s api 中的信息。

什么有效,但不是很好:

  • 使用 CronJob 来安排作业
  • 此作业查询 k8s API 并调度另一个作业

例如,我们可以这样做,让一个作业使用此运行时信息创建另一个作业:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: schedule-backup
spec:
  schedule: "13 03 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup-trigger
            image: bitnami/kubectl
            command:
            - sh
            - -c
            - |
              PRIMARYPOD=$(kubectl get pods -l cluster-name=<NAME>,role=master -o custom-columns=":metadata.name" --no-headers)
              kubectl apply -f - <<__JOB__
                apiVersion: batch/v1
                kind: Job
                metadata:
                  name: test
                spec:
                  volumes:
                    name: storage-volume
                    persistentVolumeClaim:
                      claimName:
                        data-volume-${PRIMARYPOD}
                  [...]
              __JOB__

上述内容可能最好由 Operator 来提供,而不是仅使用 CronJob,但我想知道是否有人有上述问题的解决方案。

缺点

  • 作业日志仅显示成功的备份触发器,实际备份日志是另一个作业的一部分
  • 该作业需要调度 Pod 的权限,需要另一个角色/角色绑定(bind)
  • 在 Bash 中使用heredocs会使事情更难阅读/解析/理解

摘要

说来话长,但这些是我们想要满足的约束:

  • 运行 PostgreSQL 数据库的备份
  • 这些是多 TB 数据库
  • 因此需要增量备份
  • 因此,我们需要挂载已运行 Pod 的相同 PV
  • 因此,我们需要在与 PV 相同的 K8s 节点上运行 Pod(或容器)
  • 我们希望能够在 CronJob 规范中表达这一点,而不必执行运行时 kubernetes api 调用

最佳答案

嗯,简单而简短的答案是:你通常不能。

但是让我们发挥一下创意:)

支持 RWX(读写多次)访问的存储后端数量非常有限,并且在大多数情况下,这些都是较慢的存储后端,在用于数据库时您要避免这种情况。这意味着,除非您将备份包装器作为 sidecar 运行(您现在就这样做),否则您无法真正访问不同 POD 中的 PV。

我可能会坚持您原来的方法,并进行一些调整(例如确保您永远不会因备份/配置更改而关闭主数据库)。

在最新的 K8S 集群和支持的基础设施提供商上,您可能可以查看 VolumeSnapshots用于基于快照的备份,并可能使用快照作为源来启动增量备份作业。虽然听起来有点复杂。

您还可以运行资源有限(无实时流量)的备份专用 postgres 副本 Pod,并仅在该 Pod 中嵌入备份逻辑。

关于kubernetes - 使用与 StatefulSet 中其他 1 个 Pod 相同的 PVC 来安排作业,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59562718/

相关文章:

nginx - ingress-nginx 永久重定向 301 不工作

kubernetes - StatefulSet 重新创建 pod,为什么?

mysql - 无法在 GCP 存储中创建 MySQL 数据库备份

kubernetes - 如何验证 Kubernetes 中的 cronjob 成功完成

kubernetes - 为什么 istio-ingressgateway 会暴露端口 31400?

node.js - 使用 Kubernetes 进行微服务设计 - API 网关、通信、服务发现和数据库问题

kubernetes - 公开一个 redis 集群 - 使用 kubernetes statefulset 到互联网

kubernetes - status.lastScheduleTime 何时更改?

ubuntu - 在 ubuntu 上运行的 Kubernetes POD 中 DNS 解析失败

Kubernetes 有状态集 : Restart all pods concurrently (instead of in sequence)