【问题标题】:How best to run one-off migration tasks in a kubernetes cluster如何最好地在 Kubernetes 集群中运行一次性迁移任务
【发布时间】:2016-08-31 17:25:49
【问题描述】:

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

解决方案的要求:

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

我曾认为 Kubernetes 中的 Jobs 功能会让这一切变得简单,但似乎存在一些挑战:

使用“裸豆荚”会是更好的方法吗?如果是这样,它会如何工作?

【问题讨论】:

  • 你是怎么做到的?我自己也有同样的困境......

标签: docker kubernetes


【解决方案1】:

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

感谢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 描述了一个 kubernetes Job 资源,配置了restartPolicy: Never 和相当低的activeDeadlineSeconds

您也可以使用 spec.ttlSecondsAfterFinished attribute 而不是手动运行 kubectl delete,但这在撰写本文时仍处于 alpha 阶段,至少 Google Kubernetes Engine 不支持。

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      1. 初始化迁移
      2. 初始化装置
      3. init-createsuperUser

      这将做的是并行运行django pod 和postgres pod,但同时持续运行initContainers 直到postgres pod 出现,然后您的迁移应该运行。

      至于不断重启的 pod,也许他们现在已经修复了 restartPolicy。我目前对 kubernetes 还很陌生,但这是我发现的适合我的方法。

      【讨论】:

      • 如果您有同一个 pod 的多个副本怎么办......初始化容器是为每个副本运行还是只运行一次?你如何确保它只运行一次?
      • 这是一个很好的问题。检查可以发生在应用程序层,如果一切都是最新的,应用程序将能够迁移/固定/创建超级用户。可以做的另一种方法是创建一个作业,并根据规范使用带有后安装的注释: ``` annotations: # 这就是将此资源定义为钩子的原因。如果没有此行,# 作业将被视为发布的一部分。 “helm.sh/hook”:安装后,升级后 “helm.sh/hook-weight”:“0” “helm.sh/hook-delete-policy”:hook-succeeded ```
      • initContainers 确实为每个副本运行,因此 IMO 它们不是运行数据库迁移的可行方法。如果突然出现负载峰值,您不希望最终在 10 个并行容器中运行迁移!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-24
      • 2023-01-10
      • 2012-01-14
      • 1970-01-01
      • 2022-11-11
      • 1970-01-01
      • 2016-03-12
      相关资源
      最近更新 更多