如何在Google Cloud上的Kubernetes中备份Postgres数据库?

21
以下是需要翻译的内容:

Google Cloud Container Engine上运行Postgres数据库的最佳备份实践是什么?

我的想法是将备份存储在Google Cloud Storage中,但我不确定如何将磁盘/ Pod 连接到存储桶。

我正在使用以下配置在Kubernetes集群中运行Postgres:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - image: postgres:9.6.2-alpine
          imagePullPolicy: IfNotPresent
          env:
            - name: PGDATA
              value: /var/lib/postgresql/data
            - name: POSTGRES_DB
              value: my-database-name
            - name: POSTGRES_PASSWORD
              value: my-password
            - name: POSTGRES_USER
              value: my-database-user
          name: postgres-container
          ports:
            - containerPort: 5432
          volumeMounts:
            - mountPath: /var/lib/postgresql
              name: my-postgres-volume
      volumes:
        - gcePersistentDisk:
            fsType: ext4
            pdName: my-postgres-disk
          name: my-postgres-volume

我尝试创建一个Job来运行备份:

apiVersion: batch/v1
kind: Job
metadata:
  name: postgres-dump-job
spec:
  template:
    metadata:
      labels:
        app: postgres-dump
    spec:
      containers:
        - command:
            - pg_dump
            - my-database-name
          # `env` value matches `env` from previous configuration.
          image: postgres:9.6.2-alpine
          imagePullPolicy: IfNotPresent
          name: my-postgres-dump-container
          volumeMounts:
            - mountPath: /var/lib/postgresql
              name: my-postgres-volume
              readOnly: true
      restartPolicy: Never
      volumes:
        - gcePersistentDisk:
            fsType: ext4
            pdName: my-postgres-disk
          name: my-postgres-volume

据我所知,这应该运行pg_dump命令并将备份数据输出到标准输出(应该出现在kubectl logs中)。
另外,当我检查Pods(使用kubectl get pods)时,它显示Pod永远无法跳出“挂起”状态,我认为这是由于没有足够的资源来启动Job。
作为一个旁注,以Job的形式运行此过程是否正确?如何将Job连接到Google Cloud Storage?还是我应该完全做其他事情?
我猜在数据库容器中运行pg_dump(使用kubectl exec)可能不明智,因为会影响性能,但在开发/暂存服务器上可能没问题?

这正是我的情况。你找到了一个可分享的工作解决方案吗? - BiAiB
6个回答

6

正如 @Marco Lamina 所说的那样,您可以在 postgres pod 上运行 pg_dump,例如:

DUMP
// pod-name         name of the postgres pod
// postgres-user    database user that is able to access the database
// database-name    name of the database
kubectl exec [pod-name] -- bash -c "pg_dump -U [postgres-user] [database-name]" > database.sql


RESTORE
// pod-name         name of the postgres pod
// postgres-user    database user that is able to access the database
// database-name    name of the database
cat database.sql | kubectl exec -i [pod-name] -- psql -U [postgres-user] -d [database-name]

你可以拥有一个工作Pod来运行此命令,并将其导出到文件存储系统,例如AWS S3。

pg_dump 进程很容易。困难在于将其复制到 GCS 存储桶,这就是为什么我保留了这个问题的原因。 - MattMS

3

我认为将pg_dump作为一个任务运行是个好主意,但直接连接到您的数据库持久磁盘则不是。尝试让pg_dump通过网络连接到您的数据库!然后,您可以有第二个磁盘用于存储pg_dump命令备份的数据。为了安全起见,您可以定期对这个第二个磁盘创建快照。


请问您为什么需要将备份存储在Google Cloud Storage中?我认为最简单的方法是编写一个小脚本,执行pg_dump并直接将数据推送到Google Cloud Storage。将脚本容器化,作为K8作业运行即可完成! - Marco Lamina
存储桶似乎更易扩展(无需大小管理)并提供本地挂载工具。磁盘出现在计算部分,因此它们似乎针对运行实例而非长期存储。整个过程需要自动化(无需手动创建磁盘或快照),所以帮助编写脚本(连接到适当的存储)正是我在这个问题中寻求的。 - MattMS
@MarcoLamina 你能详细说明一下“将脚本容器化,作为K8作业运行”吗? - void
@void 一个工作是一个K8资源,用于运行容器一次(或x次),直到完成为止:https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/ - Marco Lamina

2
Jobs POD一直停留在“待定”状态的原因是,它不断尝试附加/挂载GCE持久磁盘,但由于已经连接/挂载到另一个POD上而失败。
如果所有的POD以只读模式附加/挂载卷,则支持将持久磁盘附加到多个POD,但这显然对您来说不是可行的解决方案。
我从未使用过GCE,但应该可以轻松地在GCE中从PD创建快照。这将不能提供非常干净的备份,更像是“中途崩溃,但可以恢复”的状态,但这对您可能是可以接受的。
在数据库POD内运行pg_dump是可行的解决方案,但正如您已经注意到的那样,存在一些缺点,特别是性能问题。您还需要移出随后生成的备份文件,例如通过使用kubectl cp并使用另一个exec清理POD中的备份。

谢谢您的建议,但正如您所说,虽然磁盘快照是可能的,但它们远非理想的备份解决方案。我正在寻找一些稳定的可以在生产中使用的东西,因此我将保持这个问题开放以寻找其他解决方案。关于磁盘的有趣信息,我曾认为只读连接是可能的,但似乎不行。 - MattMS
正如所说,只有当所有POD以只读方式附加/挂载时,才能保证对只读挂载的一致性。 - Alexander Block

1
很多教程使用kubectl cp或在pod内部传输文件,但您也可以将pg_dump容器的输出直接管道传输到另一个进程。
kubectl run --env=PGPASSWORD=$PASSWORD --image=bitnami/postgresql postgresql -it --rm -- \
  bash -c "pg_dump -U $USER -h $HOST -d $DATABASE" |\
  gzip > backup.sql.gz

1
你可以使用 Minio客户端。首先,使用简单的Dockerfile创建一个包含Postgres和Minio客户端的Docker镜像(将其命名为 postgres_backup ):
FROM postgres

RUN apt-get update && apt-get install -y wget

RUN wget https://dl.min.io/client/mc/release/linux-amd64/mc

RUN chmod +x mc

RUN ./mc alias set gcs  https://storage.googleapis.com BKIKJAA5BMMU2RHO6IBB V8f1CwQqAcwo80UEIJEjc5gVQUSSx5ohQ9GSrr12

现在您可以在CronJob中使用< strong> postgres_backup 图像(我假设您在Google存储中创建了< em>备份桶):
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: backup-job
spec:
  # Backup the database every day at 2AM
  schedule: "0 2 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: postgres-backup
            image: postgres_backup
            env:
            - name: POSTGRES_HOST_AUTH_METHOD
              value: trust
            command: ["/bin/sh"]
            args: ["-c", 'pg_dump -Fc -U [Your Postgres Username] -W [Your Postgres Password] -h [Your Postgres Host] [Your Postgres Database] | ./mc pipe gcs/backups/$(date -Iseconds).dump']
          restartPolicy: Never

0

在不在您的Pod上存储任何其他副本的情况下卸载的最简单方法:

kubectl -n [namespace] exec -it [pod name] -- bash -c "export PGPASSWORD='[db password]'; pg_dump -U [db user] [db name]" > [database].sql

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接