任务应用程序的持续部署

随着任务应用程序的演进,您需要将更新部署到生产环境。更改可以是修复错误的任务应用程序的新版本,也可以是设置与先前任务启动不同的部署属性。

在 SCDF 中注册任务应用程序时,通常会与之关联一个版本。一个任务应用程序可以关联多个版本,其中一个版本被选为默认版本。下图说明了一个关联了多个版本的应用程序(请参阅时间戳条目)。

Registering Task Applications with multiple Versions

在 SCDF 中,通过注册多个名称和坐标相同但版本不同的应用程序来管理应用程序的版本。例如,如果您要注册具有以下值的应用程序,则会获得一个注册了两个版本(2.0.0.RELEASE 和 2.1.0.RELEASE)的应用程序

  • 应用程序 1

    • 名称: 时间戳
    • 类型: 任务
    • URI:maven://io.spring:timestamp-task:2.0.1
  • 应用 2

    • 名称: 时间戳
    • 类型: 任务
    • URI:maven://io.spring:timestamp-task:2.0.2

除了有多个版本之外,Spring Cloud Data Flow 还需要知道在下一次启动时运行哪个版本。这可以通过将一个版本设置为默认版本来指示。配置为默认版本的任何任务应用程序版本都将在下一次启动请求时运行。您可以在 UI 中查看哪个版本是默认版本,如下所示

Task Application Default Version

任务启动生命周期

在 SCDF 中支持 Tasks 的 CD 之前,当收到启动任务的请求时,Spring Cloud Data Flow 会部署应用程序(如果需要)并运行它。如果应用程序正在不需要每次都部署应用程序的平台(例如 Cloud Foundry)上运行,则会使用先前部署的应用程序。从 2.3 版本开始,此流程已更改。下图显示了现在收到任务启动请求时会发生什么

Flow For Launching A Task

在上图中,需要考虑三个主要流程

  • 第一次启动或在没有更改的情况下启动是一种
  • 在有更改但任务未运行时启动
  • 在有更改但任务正在运行时启动

我们先来看看没有更改的流程。

启动没有更改的任务

  1. Data Flow 收到启动请求。Data Flow 确定不需要升级,因为没有任何更改(自上次执行以来,属性、部署属性或版本均未更改)。
  2. 在缓存已部署工件的平台(撰写本文时为 Cloud Foundry)上,Data Flow 会检查应用程序之前是否已部署。
  3. 如果需要部署应用程序,Data Flow 会部署任务应用程序。
  4. Data Flow 启动应用程序。

此流程是默认行为,如果没有更改,则每次收到请求时都会发生。请注意,这与 Data Flow 始终为启动任务执行的流程相同。

启动已更改但当前未运行的任务

启动任务时要考虑的第二个流程是任务应用程序版本、应用程序属性或部署属性是否发生了更改。在这种情况下,将执行以下流程

  1. Data Flow 收到启动请求。Data Flow 确定需要升级,因为任务应用程序版本、应用程序属性或部署属性发生了变化。
  2. Data Flow 检查当前是否正在运行另一个任务定义实例。
  3. 如果当前没有运行另一个任务定义实例,则删除旧部署。
  4. 在缓存已部署工件的平台上(在撰写本文时为 Cloud Foundry),Data Flow 会检查应用程序之前是否已部署(在此流程中,此检查的计算结果为 false,因为旧部署已删除)。
  5. Data Flow 使用更新后的值(新的应用程序版本、新的合并属性和新的合并部署属性)部署任务应用程序。
  6. Data Flow 启动应用程序。

此流程从根本上实现了 Spring Cloud Data Flow 的持续部署。

在另一个实例运行时启动带有更改的任务

最后一个主要流程是当启动请求到达 Spring Cloud Data Flow 进行升级,但任务定义当前正在运行时。在这种情况下,由于需要删除当前应用程序,因此启动将被阻止。在某些平台上(在撰写本文时为 Cloud Foundry),删除应用程序会导致所有当前运行的应用程序关闭。此功能可防止这种情况发生。以下过程描述了当任务在另一个实例运行时发生更改时会发生什么

  1. Data Flow 收到启动请求。Data Flow 确定需要升级,因为任务应用程序版本、应用程序属性或部署属性中的任何一项发生了变化。
  2. Data Flow 检查当前是否正在运行另一个任务定义实例。
  3. Data Flow 会阻止启动,因为任务定义的其他实例正在运行。

注意:任何需要升级在请求时正在运行的任务定义的启动都将被阻止执行,因为需要删除任何当前正在运行的任务。

持续部署示例

现在,我们在 应用程序注册表 中注册了 timestamp 应用程序,它有两个版本:2.0.12.0.2

dataflow:>app list --id task:timestamp
╔═══╤══════╤═════════╤════╤═══════════════════════════╗
║app│source│processor│sink│           task            ║
╠═══╪══════╪═════════╪════╪═══════════════════════════╣
║   │      │         │    │> timestamp-2.0.1 <        ║
║   │      │         │    │timestamp-2.0.2            ║
╚═══╧══════╧═════════╧════╧═══════════════════════════╝

任务应用程序 timestamp 现在在启动任务时使用版本 2.0.1 作为默认版本。

使用之前注册的 timestamp 应用程序创建一个名为 demo1 的任务

dataflow:>task create demo1 --definition "timestamp"
Created new task 'demo1'

启动设置了部署属性的任务 demo1

dataflow:>task launch demo1 --properties "app.timestamp.format=YYYY"
Launched task 'demo1' with execution id 1

任务启动后,您可以检查任务执行状态并验证是否使用了应用程序版本2.0.1

dataflow:>task execution status 1
╔══════════════════════╤═══════════════════════════════════════════════════════════════════════════════════╗
║         Key          │                                       Value                                       ║
╠══════════════════════╪═══════════════════════════════════════════════════════════════════════════════════╣
║Id                    │1                                                                                  ║
║Resource URL          │io.spring:timestamp-task:jar:2.0.1                                                 ║
║Name                  │demo1                                                                              ║
║CLI Arguments         │[--spring.cloud.data.flow.platformname=default, --spring.cloud.task.executionid=1] ║
║App Arguments         │                 timestamp.format = YYYY                                           ║
║                      │       spring.datasource.username = ******                                         ║
║                      │           spring.cloud.task.name = demo1                                          ║
║                      │            spring.datasource.url = ******                                         ║
║                      │spring.datasource.driverClassName = org.h2.Driver                                  ║
║Deployment Properties │app.timestamp.format = YYYY                                                        ║
║Job Execution Ids     │[]                                                                                 ║
║Start Time            │Wed May 20 20:50:40 IST 2020                                                       ║
║End Time              │Wed May 20 20:50:40 IST 2020                                                       ║
║Exit Code             │0                                                                                  ║
║Exit Message          │                                                                                   ║
║Error Message         │                                                                                   ║
║External Execution Id │demo1-87a6e434-33ce-4b09-9f14-6b1892b6c135                                         ║
╚══════════════════════╧═══════════════════════════════════════════════════════════════════════════════════╝

现在我们可以尝试将 timestamp 应用程序的默认版本更改为 2.0.2

dataflow:>app default --id task:timestamp --version 2.0.2
New default Application task:timestamp:2.0.2

您可以验证更改,如下所示

dataflow:>app list --id task:timestamp
╔═══╤══════╤═════════╤════╤═══════════════════════════╗
║app│source│processor│sink│           task            ║
╠═══╪══════╪═════════╪════╪═══════════════════════════╣
║   │      │         │    │timestamp-2.0.1            ║
║   │      │         │    │> timestamp-2.0.2         <║
╚═══╧══════╧═════════╧════╧═══════════════════════════╝

现在,timestamp 应用程序的默认版本设置为使用 2.0.2。这意味着任何后续启动的 timestamp 应用程序都将使用 2.0.2 而不是之前的默认版本 (2.0.1)。

dataflow:>task launch demo1
Launched task 'demo1' with execution id 2

您可以使用任务执行状态来验证这一点,如下所示

dataflow:>task execution status 2
╔══════════════════════╤═══════════════════════════════════════════════════════════════════════════════════╗
║         Key          │                                       Value                                       ║
╠══════════════════════╪═══════════════════════════════════════════════════════════════════════════════════╣
║Id                    │2                                                                                  ║
║Resource URL          │io.spring:timestamp-task:jar:2.0.2                                                 ║
║Name                  │demo1                                                                              ║
║CLI Arguments         │[--spring.cloud.data.flow.platformname=default, --spring.cloud.task.executionid=2 ]║
║App Arguments         │                 timestamp.format = YYYY                                           ║
║                      │       spring.datasource.username = ******                                         ║
║                      │           spring.cloud.task.name = demo1                                          ║
║                      │            spring.datasource.url = ******                                         ║
║                      │spring.datasource.driverClassName = org.h2.Driver                                  ║
║Deployment Properties │app.timestamp.format = YYYY                                                        ║
║Job Execution Ids     │[]                                                                                 ║
║Start Time            │Wed May 20 20:57:21 IST 2020                                                       ║
║End Time              │Wed May 20 20:57:21 IST 2020                                                       ║
║Exit Code             │0                                                                                  ║
║Exit Message          │                                                                                   ║
║Error Message         │                                                                                   ║
║External Execution Id │demo1-aac20c8b-9c80-40dc-ac7d-bb3f4155be41                                         ║
╚══════════════════════╧═══════════════════════════════════════════════════════════════════════════════════╝

请注意,现在使用的是 timestamp 应用程序的 2.0.2 版本,以及之前任务启动时的部署属性。您也可以在任务启动期间覆盖这些部署属性。

注意:虽然部署属性会在任务启动之间传播,但任务参数不会传播。其理念是仅为每次任务启动保留参数。

调度生命周期

Spring Cloud Data Flow 支持在两个平台上进行调度:Kubernetes 和 Cloud Foundry。在这两种情况下,Spring Cloud Data Flow 都与平台提供的调度系统交互以

  • 创建调度
  • 删除调度
  • 列出可用的调度 每个平台处理任务调度的方式都不同。在以下部分中,我们将讨论 Spring Cloud Data Flow 如何调度任务。

在 Cloud Foundry 上调度

  1. 调度请求进入 Spring Cloud Data Flow。Spring Cloud Data Flow 确定应用程序当前是否存在,如果不存在,则将应用程序部署到 Cloud Foundry 实例。然后将应用程序绑定到调度程序(以及所需的绑定)。
  2. 部署应用程序并将其绑定到调度程序后,调度程序将根据提供的调度启动应用程序。

调度应用程序后,应用程序的生命周期将由 Cloud Foundry 调度程序管理,不再由 Spring Cloud Data Flow 管理,除非删除调度或在删除任务定义时将其删除。

在 Kubernetes 上调度

  1. Spring Cloud Data Flow 收到一个调度请求。Spring Cloud Data Flow 会在平台指定的命名空间和集群中创建一个 CronJob。
  2. CronJob 创建完成后,会根据提供的调度计划启动应用程序。

应用程序调度完成后,其生命周期将由关联的 CronJob 管理。当任务定义被删除或调度被删除时,Spring Cloud Data Flow 将删除 CronJob。