如何最好地在kubernetes集群中运行一次性迁移任务

时间:2016-05-05 19:29:59

标签: docker kubernetes

在将新版本的应用部署到Kubernetes群集之前,我想要运行数据库迁移。我希望这些迁移作为Continuous Delivery管道的一部分自动运行。迁移将封装为容器映像。什么是实现这一目标的最佳机制?

解决方案的要求:

  • 能够确定迁移是否失败,以便我们随后尝试将新版本的应用部署到群集中。
  • 如果迁移失败则放弃 - 不要继续重试。
  • 能够访问日志以诊断失败的迁移。

我曾认为Kubernetes中的Jobs功能会让这很容易,但似乎有一些挑战:

使用"裸豆荚"是一个更好的方法?如果是这样,那该怎么办?

3 个答案:

答案 0 :(得分:9)

您可以尝试通过执行以下操作使迁移作业和应用程序彼此独立:

  • 即使迁移失败,也可以成功返回迁移作业。将机器可消耗的记录保存在迁移结果的某个位置。这可以显式地(通过,例如,将最新的模式版本写入某个数据库表字段)或隐式地(例如,假设必须已经沿着成功的迁移作业创建特定字段)来完成。如果由于技术原因失败,则迁移作业将仅返回错误代码(由于数据库不可用,应该应用迁移)。这样,您就可以通过Kubernetes Jobs进行迁移,并依靠其最终运行完成的能力。
  • 构建新的应用程序版本,以便它可以在迁移前和迁移后阶段使用数据库。这意味着什么取决于您的业务需求:应用程序可以在迁移成功完成之前转为空闲,或者根据当前阶段可能会向客户端返回不同的结果。这里的关键点是应用程序处理迁移作业之前生成的迁移结果,并相应地采取行动而不会错误地终止。

结合这两种设计方法,您应该能够彼此独立地开发和执行迁移作业和应用程序,而不必引入任何时间耦合。

这个想法实际上是否合理,取决于您的案例的更具体细节,例如数据库迁移工作的复杂性。正如您所提到的,另一种方法是将非托管pod部署到执行迁移的集群中。这需要更多的布线,因为您需要定期检查结果并区分成功和失败的结果。

答案 1 :(得分:5)

  

在等待排队作业的结果时阻塞似乎需要手动滚动脚本

借助kubectl wait命令,不再需要此操作。

这是我在CI中运行数据库迁移的方式:

kubectl apply -f migration-job.yml
kubectl wait --for=condition=complete --timeout=60s job/migration
kubectl delete job/migration

万一发生故障或超时,前两个CLI命令之一将返回错误的退出代码,然后强制其余CI管道终止。

migration-job.yml描述了配置了Job和相当低的restartPolicy: Never的kubernetes activeDeadlineSeconds资源。

您也可以使用spec.ttlSecondsAfterFinished attribute来代替手动运行kubectl delete,但这在撰写本文时仍处于Alpha状态,并且至少不受Google Kubernetes Engine支持。

答案 2 :(得分:2)

考虑到这个问题的年龄,我不确定当时是否有initContainers可用,但现在它们非常有用。

https://kubernetes.io/docs/concepts/workloads/pods/init-containers/

我最近设置的方式是让postgres pod和我们的django应用程序在同一名称空间中运行,但django pod有3 initContainers

  1. INIT-迁移
  2. INIT-夹具
  3. INIT-createsuperUser
  4. 这样做会同时运行django窗格和postgres窗格,但也会持续运行initContainers,直到postgres窗格出现,然后再迁移应该跑。

    至于pods不断重启,也许他们现在已经修复了restartPolicy。我目前对kubernetes很新,但我发现这对我有用。