管理Kubernetes集群上的数据库迁移

时间:2018-05-07 16:10:15

标签: postgresql docker kubernetes database-migration

我有一个基于Kubernetes的应用程序,包含使用头盔图管理的多个服务(和pod)。

Postgres用作所有服务的数据库。

当应用程序升级到较新版本时,我正在通过initContainers运行数据库迁移脚本。

当迁移脚本需要对DB的独占访问(所有其他连接应该终止)时,会出现问题,否则脚本将被阻止。

理想的解决方案是停止所有pod,运行迁移并重新创建它们。但我不确定如何使用Kubernetes正确实现它。

TNX

3 个答案:

答案 0 :(得分:6)

  

理想的解决方案是停止所有pod,运行迁移和   重新创造它们。但我不确定如何正确实现它   Kubernetes。

我从其中一条评论中看到你使用Helm,所以我想提出一个利用Helm钩子的解决方案:

  

Helm提供了一种钩子机制,允许图表开发人员进行干预   在发布的生命周期中的某些点。例如,您可以使用   挂钩:

     
      
  • 在安装过程中加载ConfigMap或Secret,然后再显示其他任何图表   加载。

  •   
  • 执行作业以在安装新数据库之前备份数据库   图表,然后在升级后执行第二个作业   恢复数据。

  •   
  • 在删除版本之前运行作业以优雅地获取   在移除之前服务不旋转。

  •   

https://github.com/kubernetes/helm/blob/master/docs/charts_hooks.md

您可以将迁移打包为k8s Job,并利用pre-installpre-upgrade挂钩来运行作业。这些钩子在渲染模板后运行,但在Kubernetes中创建任何新资源之前运行。因此,您的迁移将在部署Pod之前运行。

要在运行迁移之前删除部署,请创建第二个预安装/升级前挂钩,其中helm.sh/hook-weight更低,以删除目标部署:

apiVersion: batch/v1
kind: Job
metadata:
  name: "pre-upgrade-hook1"
  annotations:
    "helm.sh/hook": pre-upgrade
    "helm.sh/hook-weight": "-1"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    metadata:
      name: "pre-upgrade-hook1"
    spec:
      restartPolicy: Never
      serviceAccountName: "<an SA with delete RBAC permissions>"
      containers:
      - name: kubectl
        image: "lachlanevenson/k8s-kubectl:latest"
        command: ["delete","deployment","deploy1","deploy2"]

较低的钩子重量将确保此作业在迁移作业之前运行。这将确保以下一系列事件:

  1. 您运行helm upgrade
  2. 具有最低hook-weight的helm hook运行并删除相关部署
  3. 第二个钩子运行并运行您的迁移
  4. 您的图表将安装新的Deployments,Pods等
  5. 请确保将所有相关部署保留在同一个图表中。

答案 1 :(得分:1)

从自动化/编排的角度来看,我的感觉是,使用最近发布的运营商框架,运营商可以解决这样的问题:

https://github.com/operator-framework

我的想法是会有一个Postgres迁移运算符 - 据我所知还不存在 - 它会闲置等待自定义资源定义,描述迁移要发布到集群/命名空间。

操作员会醒来,了解预期迁移中涉及的内容,对群集进行一些分析以构建迁移计划,然后按照您的描述执行步骤 -

  • 将应用程序置于某种用户可见的维护模式
  • 取下现有广告连播
  • 运行迁移
  • 验证
  • 重新创建应用程序窗格
  • 测试
  • 使应用程序退出维护模式

但是现在这对你没有帮助。

答案 2 :(得分:0)

  

理想的解决方案是停止所有pod,运行迁移和   重新创造它们。但我不确定如何正确实现它   Kubernetes。

这在很大程度上取决于您的方法,特别是您的CI / CD工具。您可以应用几种策略,但是,作为一个例子,假设您有Gitlab管道(Jenkins可以这样做,术语不同等),这里是步骤:

  • 在gitlab-ci.yaml中进行以下阶段:
    • 构建(您可以在部署任何内容之前创建所有必要的图像并准备迁移)
    • 停止所有受影响的资产 - 部署,服务,状态设置(这可以通过相当简单的kubectl delete -f all_required_assets.yaml来完成,在单个清单中,您已经定义了要完全停止的所有资源。您也可以设置宽限期或强制终止,并且您不需要删除静态资产 - 仅与停止有关。请注意,要停止pod,您需要删除其顶级创建资源,即pod,部署,复制控制器或statefulset完全阻止它们,而不是简单地重新启动)
    • 迁移以Job或Pod的形式实现,可以处理与数据库的迁移(例如,kubectl create -f migrate_job.yaml)。完成工作后错误跟踪的优先工作。
    • 启动所有资产(与受影响的资源定义相同的清单文件与停止阶段相同,例如,kubectl create -f all_required_assets.yaml,所有启动/停止资源都通过单个文件处理。如果启动订单因任何原因都很重要,那么需要单独的文件,但仔细考虑一个文件应该足以满足大多数情况。)

同样的原则也可以在其他编排/部署工具中使用,你甚至可以制作一个简单的脚本,如果前一个成功,就可以一次性直接运行这些kubectl命令。