Choosing a Deployment Strategy

A deployment strategy is a way to change or upgrade an application. The aim is to make the change without downtime in a way that the user barely notices the improvements.

Because the end user usually accesses the application through a route handled by a router, the deployment strategy can focus on DeploymentConfig object features or routing features. Strategies that focus on the deployment impact all routes that use the application. Strategies that use router features target individual routes.

Many deployment strategies are supported through the DeploymentConfig object, and some additional strategies are supported through router features. Deployment strategies are discussed in this section.

Choosing a deployment strategy

Consider the following when choosing a deployment strategy:

  • Long-running connections must be handled gracefully.
  • Database conversions can be complex and must be done and rolled back along with the application.
  • If the application is a hybrid of microservices and traditional components, downtime might be required to complete the transition.
  • You must have the infrastructure to do this.
  • If you have a non-isolated test environment, you can break both new and old versions.

A deployment strategy uses readiness checks to determine if a new pod is ready for use. If a readiness check fails, the DeploymentConfig object retries to run the pod until it times out. The default timeout is 10m, a value set in TimeoutSeconds in dc.spec.strategy.*params.

Rolling strategy

A rolling deployment slowly replaces instances of the previous version of an application with instances of the new version of the application. The rolling strategy is the default deployment strategy used if no strategy is specified on a DeploymentConfig object.

A rolling deployment typically waits for new pods to become ready via a readiness check before scaling down the old components. If a significant issue occurs, the rolling deployment can be aborted.

When to use a rolling deployment:

  • When you want to take no downtime during an application update.
  • When your application supports having old code and new code running at the same time.

A rolling deployment means you to have both old and new versions of your code running at the same time. This typically requires that your application handle N-1 compatibility.

The rolling strategy:

  • Executes any pre lifecycle hook.
  • Scales up the new replication controller based on the surge count.
  • Scales down the old replication controller based on the max unavailable count.
  • Repeats this scaling until the new replication controller has reached the desired replica count and the old replication controller has been scaled to zero.
  • Executes any post lifecycle hook.

The maxUnavailable parameter is the maximum number of pods that can be unavailable during the update. The maxSurge parameter is the maximum number of pods that can be scheduled above the original number of pods. Both parameters can be set to either a percentage (e.g., 10%) or an absolute value (e.g., 2). The default value for both is 25%.

These parameters allow the deployment to be tuned for availability and speed. For example:

  • maxUnavailable*=0 and maxSurge*=20% ensures full capacity is maintained during the update and rapid scale up.
  • maxUnavailable*=10% and maxSurge*=0 performs an update using no extra capacity (an in-place update).
  • maxUnavailable*=10% and maxSurge*=10% scales up and down quickly with some potential for capacity loss.

Generally, if you want fast rollouts, use maxSurge. If you have to take into account resource quota and can accept partial unavailability, use maxUnavailable.

Canary deployments

All rolling deployments in OKD are canary deployments; a new version (the canary) is tested before all of the old instances are replaced. If the readiness check never succeeds, the canary instance is removed and the DeploymentConfig object will be automatically rolled back.

The readiness check is part of the application code and can be as sophisticated as necessary to ensure the new instance is ready to be used. If you must implement more complex checks of the application (such as sending real user workloads to the new instance), consider implementing a custom deployment or using a blue-green deployment strategy.

Recreate strategy

The recreate strategy has basic rollout behavior and supports lifecycle hooks for injecting code into the deployment process. Example recreate strategy definition:

  type: Recreate
    pre: {} 
    mid: {}
    post: {}

The recreate strategy:

  • Executes any pre lifecycle hook.
  • Scales down the previous deployment to zero.
  • Executes any mid lifecycle hook.
  • Scales up the new deployment.
  • Executes any post lifecycle hook.

When to use a recreate deployment:

  • When you must run migrations or other data transformations before your new code starts.
  • When you do not support having new and old versions of your application code running at the same time.
  • When you want to use a RWO volume, which is not supported being shared between multiple replicas.

A recreate deployment incurs downtime because, for a brief period, no instances of your application are running. However, your old code and new code do not run at the same time.

Custom strategy

The custom strategy allows you to provide your own deployment behavior. Example custom strategy definition:

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

In the above example, the organization/strategy container image provides the deployment behavior. The optional command array overrides any CMD directive specified in the image’s Dockerfile. The optional environment variables provided are added to the execution environment of the strategy process.

Additionally, OKD provides the following environment variables to the deployment process:

Environment variable Description
OPENSHIFT_DEPLOYMENT_NAME The name of the new deployment, a replication controller.
OPENSHIFT_DEPLOYMENT_NAMESPACE The name space of the new deployment.

The replica count of the new deployment will initially be zero. The responsibility of the strategy is to make the new deployment active using the logic that best serves the needs of the user.

Alternatively, use the customParams object to inject the custom deployment logic into the existing deployment strategies. Provide a custom shell script logic and call the openshift-deploy binary. Users do not have to supply their custom deployer container image.

Lifecycle hooks

The rolling and recreate strategies support lifecycle hooks, or deployment hooks, which allow behavior to be injected into the deployment process at predefined points within the strategy:

Example pre lifecycle hook

  failurePolicy: Abort
  execNewPod: {} 

Every hook has a failure policy, which defines the action the strategy should take when a hook failure is encountered:

Policy Description
Abort The deployment process will be considered a failure if the hook fails.
Retry The hook execution should be retried until it succeeds.
Ignore Any hook failure should be ignored and the deployment should proceed.

Hooks have a type-specific field that describes how to execute the hook. Currently, pod-based hooks are the only supported hook type, specified by the execNewPod field.