6.3. 使用部署策略

部署策略是更改或升级应用程序的一种方法。其目的是在无需停机的前提下进行修改,从而使用户几乎不会注意到这些变化。

因为最终用户通常通过由路由器控制的路由访问应用程序,所以部署策略侧重于 DeploymentConfig 对象功能或路由功能。注重部署的策略会影响所有使用该应用程序的路由。侧重于路由功能的策略则会影响到单个的路由。

许多部署策略通过 DeploymentConfig 对象支持,一些额外的策略则通过路由器功能支持。本节将讨论部署策略。

选择部署策略

选择部署策略时请考虑以下几点:

  • 长时间运行的连接必须被恰当处理。
  • 数据库转换可能比较复杂,且必须和应用程序一同执行并回滚。
  • 如果应用程序由微服务和传统组件构成,则可能需要停机才能完成转换。
  • 您必须拥有进行此操作的基础架构。
  • 如果您的测试环境没有被隔离,则可能会破坏到新版本和旧版本。

部署策略使用就绪度检查来确定新 pod 是否准备就绪。如果就绪度检查失败,DeploymentConfig 对象会重新尝试运行 pod,直到超时为止。默认超时为 10m,其值在 dc.spec.strategy.*paramsTimeoutSeconds 中设置。

6.3.1. Rolling 策略

滚动部署会逐渐将应用程序旧版本实例替换为应用程序的新版本实例。如果 DeploymentConfig 对象上没有指定任何策略,则滚动策略是默认的部署策略。

在缩减旧组件前,滚动部署通常会 等待新 pod 变为 ready。如果发生严重问题,可以中止 Rolling 部署。

使用滚动部署:

  • 希望在应用程序更新过程中不需要停机时。
  • 应用程序同时支持运行旧代码和新代码时。

滚动部署意味着您同时运行旧版和新版本的代码。这通常需要您的应用程序可以处理 N-1 兼容性。

滚动策略定义示例

strategy:
  type: Rolling
  rollingParams:
    updatePeriodSeconds: 1 1
    intervalSeconds: 1 2
    timeoutSeconds: 120 3
    maxSurge: "20%" 4
    maxUnavailable: "10%" 5
    pre: {} 6
    post: {}

1
各个 pod 更新之间等待的时间。如果未指定,则默认值为 1
2
更新后轮询部署状态之间等待的时间。如果未指定,则默认值为 1
3
放弃前等待扩展事件的时间。可选,默认值为 600。这里的放弃表示自动回滚到以前的完整部署。
4
maxSurge 是可选的;如果未指定,则默认为 25%。请参考以下流程中的信息。
5
maxUnavailable 是可选的;如果未指定,则默认为 25% 。请参考以下流程中的信息。
6
prepost 都是生命周期 hook。

滚动策略:

  1. 执行任何 pre 生命周期 hook。
  2. 根据数量扩展新的复制控制器。
  3. 根据最大不可用数,缩减旧的复制控制器。
  4. 重复这个扩展,直到新的复制控制器达到所需的副本数,并且旧的复制控制器已缩减为零。
  5. 执行任何 post 生命周期 hook。
重要

在缩减时,滚动策略会等待 pod 准备就绪,以便它能决定进一步缩放是否会影响到可用性。如果扩展 pod 永不就绪,部署过程将最终超时并导致部署失败。

maxUnavailable 参数是在更新过程中不可用的 pod 的最大数量。maxSurge 参数是原始 pod 数量之上最多可以调度的 pod 数量。这两个参数可以设定为百分比(如 10%)或绝对值(如 2)。两者的默认值都是 25%

这些参数允许对部署的可用性和速度进行调优。例如:

  • maxUnavailable*=0maxSurge*=20% 可确保在更新和快速扩展过程中保持全部容量。
  • maxUnavailable*=10%maxSurge*=0 在执行更新时不使用额外容量(原位更新)。
  • maxUnavailable*=10%maxSurge*=10% 可以快速缩放,可能会有一些容量损失。

一般而言,如果您想要快速推出部署,请使用 maxSurge。如果您需要考虑资源配额并可以接受资源部分不可用的情况,则可使用 maxUnavailable

6.3.1.1. Canary 部署

OpenShift Container Platform 中的所有滚动部署都属于 Canary 部署;在替换所有旧实例前测试新的版本(Canary)。如果就绪度检查永不成功,则移除 Canary 实例,并且自动回滚 DeploymentConfig 对象。

就绪度检查是应用程序代码的一部分,并且可以尽可能的精密,确保新实例就绪可用。如果您必须对应用程序进行更复杂的检查(比如向新实例发送真实用户负载),请考虑实施自定义部署或使用蓝绿部署策略。

6.3.1.2. 创建滚动部署

在 OpenShift Container Platform 中,Rolling 部署是默认类型。您可以使用 CLI 创建滚动部署。

流程

  1. 根据 Quay.io 中找到的示例部署镜像创建一个应用程序:

    $ oc new-app quay.io/openshifttest/deployment-example:latest
  2. 如果您安装了路由器,请通过路由(或直接使用服务 IP)提供应用程序。

    $ oc expose svc/deployment-example
  3. 通过 deployment-example.<project>.<router_domain> 访问应用程序,验证您能否看到 v1 镜像。
  4. DeploymentConfig 对象扩展至三个副本:

    $ oc scale dc/deployment-example --replicas=3
  5. 通过为示例的新版本标上 latest 标签(tag),自动触发新部署:

    $ oc tag deployment-example:v2 deployment-example:latest
  6. 在浏览器中刷新页面,直到您看到 v2 镜像。
  7. 在使用 CLI 时,以下命令显示版本 1 上的 pod 数以及版本 2 上的数量。在 Web 控制台中,pod 逐渐添加到 v2 中并从 v1 中移除:

    $ oc describe dc deployment-example

在部署过程中,新复制控制器以递增方式扩展。新 pod 标记为 ready(通过就绪度检查)后,部署过程将继续。

如果 pod 尚未就绪,该过程会中止,部署回滚到之前的版本。

6.3.1.3. 使用 Developer 视角启动滚动部署

先决条件

  • 确认您使用 web 控制台的 Developer 视角。
  • 确保您已使用 Add 视图创建了一个应用程序,并可以在 Topology 视图中查看它。

流程

要启动滚动部署来升级应用程序:

  1. Developer 视角的 Topology 视图中,点应用程序节点,查看侧面面板中的 Overview 选项卡。请注意,Update Strategy 被设置为默认的 Rolling 策略 。
  2. Actions 下拉菜单中,选择 Start Rollout 来启动滚动更新。滚动部署将应用程序更新到新版本,然后终止旧版本。

    图 6.1. 滚动更新

    odc 滚动更新

6.3.2. Recreate 策略

Recreate(重新创建)策略具有基本的推出部署行为,并支持使用生命周期 hook 将代码注入到部署过程中。

recreate 策略定义示例

strategy:
  type: Recreate
  recreateParams: 1
    pre: {} 2
    mid: {}
    post: {}

1
recreateParams 可选。
2
premidpost 是生命周期 hook。

recreate 策略:

  1. 执行任何 pre 生命周期 hook。
  2. 将上一部署缩减到零。
  3. 执行任何 mid 生命周期 hook。
  4. 向上扩展新的部署。
  5. 执行任何 post 生命周期 hook。
重要

在扩展过程中,如果部署副本数大于一,则先对部署的第一副本进行就绪状态验证,然后再全面扩展部署。如果第一副本验证失败,部署将被视为失败。

使用重新创建的部署:

  • 需要在新代码启动前进行迁移或进行其他数据转换时。
  • 不支持同时运行应用程序代码的新旧版本时。
  • 当使用 RWO 卷时,不支持在多个副本间共享该卷。

重新创建部署会导致停机,这是因为在短时间内没有运行应用程序实例。然而,旧代码和新代码不会被同时运行。

6.3.3. 使用 Developer 视角启动重新创建的部署

您可以使用 web 控制台中的 Developer 视角将部署策略从默认的滚动模式切换到重新创建模式。

先决条件

  • 确认您使用 web 控制台的 Developer 视角。
  • 确保您已使用 Add 视图创建了一个应用程序,并可以在 Topology 视图中查看它。

流程

切换到重新创建的更新策略并升级应用程序:

  1. Actions 下拉菜单中,选择 Edit Deployment Config 来查看应用程序的部署配置详情。
  2. 在 YAML 编辑器中,将 spec.strategy.type 更改为 Recreate ,然后点 Save
  3. Topology 视图中,选择节点即可看到侧面板中的 Overview 选项卡。Update Strategy 现在设为 Recreate
  4. 使用 Actions 下拉菜单选择 Start Rollout 以使用 recreate 策略启动更新。recreate 策略首先会终止旧版本应用程序的 pod,然后为新版本启动 pod。

    图 6.2. 重新创建更新

    odc 重新创建更新

6.3.4. Custom 策略

自定义(Custom)策略允许您提供自己的部署行为。

Custom 策略定义示例

strategy:
  type: Custom
  customParams:
    image: organization/strategy
    command: [ "command", "arg1" ]
    environment:
      - name: ENV_1
        value: VALUE_1

在上例中,organization/strategy 容器镜像提供部署行为。可选的 command 数组覆盖镜像的 Dockerfile 中指定的任何 CMD 指令。提供的可选环境变量添加到策略过程的执行环境中。

另外,OpenShift Container Platform 为部署过程提供以下环境变量:

环境变量描述

OPENSHIFT_DEPLOYMENT_NAME

新部署的名称,即复制控制器。

OPENSHIFT_DEPLOYMENT_NAMESPACE

新部署的命名空间。

新部署的副本数最初为零。该策略负责使新部署积极使用最能满足用户需求的逻辑。

另外,也可使用 customParams 对象将自定义部署逻辑注入现有的部署策略中。提供自定义 shell 脚本逻辑并调用 openshift-deploy 二进制文件。用户不必提供自定义的部署器容器镜像;本例中使用默认的 OpenShift Container Platform 部署器镜像:

strategy:
  type: Rolling
  customParams:
    command:
    - /bin/sh
    - -c
    - |
      set -e
      openshift-deploy --until=50%
      echo Halfway there
      openshift-deploy
      echo Complete

这会产生以下部署:

Started deployment #2
--> Scaling up custom-deployment-2 from 0 to 2, scaling down custom-deployment-1 from 2 to 0 (keep 2 pods available, don't exceed 3 pods)
    Scaling custom-deployment-2 up to 1
--> Reached 50% (currently 50%)
Halfway there
--> Scaling up custom-deployment-2 from 1 to 2, scaling down custom-deployment-1 from 2 to 0 (keep 2 pods available, don't exceed 3 pods)
    Scaling custom-deployment-1 down to 1
    Scaling custom-deployment-2 up to 2
    Scaling custom-deployment-1 down to 0
--> Success
Complete

如果自定义部署策略过程需要访问 OpenShift Container Platform API 或 Kubernetes API,执行该策略的容器可以使用容器中的服务帐户令牌进行身份验证。

6.3.5. 生命周期 hook

滚动和重新创建策略支持 生命周期 hook 或部署 hook,它允许在策略的预定义点将行为注入到部署过程中:

pre 生命周期 hook 示例

pre:
  failurePolicy: Abort
  execNewPod: {} 1

1
execNewPod 是基于 pod 的生命周期 hook。

每个 hook 都有一个 失败策略,定义在遇到 hook 失败时策略应执行的操作:

Abort

如果 hook 失败,部署过程将被视为失败。

Retry

应重试 hook 执行过程,直到成功为止。

Ignore

所有 hook 失败都应忽略,部署应继续进行。

Hook 具有特定类型的字段,用于描述如何执行 Hook。目前,基于 pod 的 hook 是唯一受支持的 hook 类型,通过 execNewPod 字段指定。

基于 Pod 的生命周期 hook

基于 Pod 的生命周期 hook 在来自 DeploymentConfig 对象模板的新 pod 中执行 hook 代码。

以下简化的部署示例使用了滚动策略。为简明起见,省略了触发器和其他一些次要的细节:

kind: DeploymentConfig
apiVersion: apps.openshift.io/v1
metadata:
  name: frontend
spec:
  template:
    metadata:
      labels:
        name: frontend
    spec:
      containers:
        - name: helloworld
          image: openshift/origin-ruby-sample
  replicas: 5
  selector:
    name: frontend
  strategy:
    type: Rolling
    rollingParams:
      pre:
        failurePolicy: Abort
        execNewPod:
          containerName: helloworld 1
          command: [ "/usr/bin/command", "arg1", "arg2" ] 2
          env: 3
            - name: CUSTOM_VAR1
              value: custom_value1
          volumes:
            - data 4
1
helloworld 名称指代 spec.template.spec.containers[0].name
2
command 覆盖 openshift/origin-ruby-sample 镜像中定义的任何 ENTRYPOINT
3
env 是 hook 容器的一组可选环境变量。
4
volumes 是 hook 容器的一组可选的卷引用。

在本例中,将使用 helloworld 容器中的 openshift/origin-ruby-sample 镜像在新 pod 中执行 pre hook。hook pod 具有以下属性:

  • hook 命令是 /usr/bin/command arg1 arg2
  • hook 容器包含 CUSTOM_VAR1=custom_value1 环境变量。
  • hook 失败策略是 Abort;即 hook 失败时部署过程也会失败。
  • hook pod 从 DeploymentConfig 对象 pod 继承 data 卷。

6.3.5.1. 设置生命周期 hook

您可以使用 CLI 为部署设置生命周期 hook 或部署 hook。

流程

  1. 使用 oc set deployment-hook 命令设定您想要的 hook 类型:--pre--mid--post。例如,设置部署前 hook:

    $ oc set deployment-hook dc/frontend \
        --pre -c helloworld -e CUSTOM_VAR1=custom_value1 \
        --volumes data --failure-policy=abort -- /usr/bin/command arg1 arg2