2

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

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

当前设置

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

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

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

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

在容器内部,一个小 api 环绕pgBackRest,可以通过向POSTapi 发送请求来触发,目前这个触发是使用 CronJobs 完成的。

缺点

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

建议的设置

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

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

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

什么有效,但不是很好:

  • 使用调度作业的 CronJob
  • 这个 Job 查询 k8s api 并调度另一个Job

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

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__

以上可能最好由操作员提供,而不仅仅是使用 CronJob,但我想知道是否有人对上述问题有解决方案。

缺点

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

概括

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

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

1 回答 1

3

好吧,简单而简短的答案是:您通常不能。

但是,让我们暂时发挥创意:)

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

我可能会坚持你原来的方法,并进行一些调整(比如确保你永远不会因为备份/配置更改而关闭主服务器)。

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

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

于 2020-01-02T13:37:11.667 回答