4.3. 使用 DeploymentConfig 策略

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

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

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

选择部署策略

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

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

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

4.3.1. Rolling 策略

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

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

何时使用 Rolling 部署:

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

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

Rolling 策略定义示例

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。

Rolling 策略:

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

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

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

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

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

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

4.3.1.1. Canary 部署

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

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

4.3.1.2. 创建 Rolling 部署

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

流程

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

    $ oc new-app openshift/deployment-example
  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

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

如果 Pod 尚未就绪,该过程中止,并且 DeploymentConfig 回滚到之前的版本。

4.3.1.3. 使用 Developer 视角启动 Rolling 部署

先决条件

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

流程

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

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

    滚动更新

4.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。
重要

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

何时使用 Recreate 部署:

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

Recreate 部署会出现停机的情况,这是因为在短时间内会出现没有运行您的应用程序实例的情况。然而,旧代码和新代码不会被同时运行。

4.3.3. 使用 Developer 视角启动 Recreate 部署

您可以使用 web 控制台中的 Developer 视角将部署策略从默认的 Rolling 更新切换到 Recreate 更新。

先决条件

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

流程

切换到 Recreate 更新策略并升级应用程序:

  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。

    重新创建更新

4.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

新部署 (ReplicationController) 的名称。

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,执行该策略的容器可以使用容器中的服务帐户令牌进行身份验证。

4.3.5. 生命周期 hook

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

pre 生命周期 hook 示例

pre:
  failurePolicy: Abort
  execNewPod: {} 1

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

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

Abort

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

Retry

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

Ignore

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

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

基于 Pod 的生命周期 hook

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

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

kind: DeploymentConfig
apiVersion: 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 卷。

4.3.5.1. 设置生命周期 hook

您可以使用 CLI 为 DeploymentConfig 设置生命周期 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 \
        -v data --failure-policy=abort -- /usr/bin/command arg1 arg2