AWS Elastic Beanstalk
Developer Guide (API Version 2010-12-01)
« PreviousNext »
View the PDF for this guide.Go to the AWS Discussion Forum for this product.Go to the Kindle Store to download this guide in Kindle format.Did this page help you?  Yes | No |  Tell us about it...

Deploying Versions with Zero Downtime

Since AWS Elastic Beanstalk performs an in-place update when you update your application versions, you will experience some downtime. However, it is possible to avoid this downtime by swapping the CNAMEs for your environments. This section walks you through how to perform a CNAME swap using the AWS Management Console, the command line interface, or APIs.

Note

If you have created an Alias record to map your root domain to your Elastic Load Balancer using Amazon Route 53, then after you have created you new environment, you will need to change your resource record set to map your root domain to the Elastic Load Balancer in your new environment. For instructions on how to change your existing resource record set, go to Using AWS Elastic Beanstalk with Amazon Route 53 to Map Your Domain to Your Load Balancer.

AWS Management Console

To deploy with zero downtime

  1. Check that your current environment is Green and Ready from the application's Environments list. For instructions, see Viewing Application Health and Environment Status.

  2. Verify that your new application version exists.

    1. Select the application from the drop-down list, and then click the Versions tab in the AWS Elastic Beanstalk console.

    2. Select the check box next to the version label of the application version you want to deploy.

  3. Create a configuration template for the current environment. For instructions, see Saving Environment Configuration Settings.

  4. Launch a new environment with your new application version and saved configuration template. For instructions, see Launching New Environments. In the Launch New Environment wizard, click your saved configuration template from the Load a Saved Configuration list.

  5. Make sure that your new environment is in the Green and Ready state. For instructions, see Viewing Application Health and Environment Status.

  6. Click the Actions drop-down list for your application environment and select Swap Environment URL.

  7. In the Swap Environment URL window, select the environment name you want to swap with from the Environment Name pull-down menu.

    Swap Environment URL Window
  8. Click Swap.

  9. Delete your old environment after you confirmed the swap operation has completed.

CLI

You can use the command line interface to deploy a new application with zero downtime. The following steps walk you through creating a configuration template, launching a new environment with the new application version using the configuration template, and swapping the environment CNAMEs. You can also use the following steps to perform configuration changes with zero downtime.

To deploy with zero downtime

  1. Check your current environment to make sure it is Green and Ready.

    PROMPT> elastic-beanstalk-describe-environments -E [Environment ID]

  2. Verify that your new application version exists.

    PROMPT> elastic-beanstalk-describe-application-versions -a [Application Name] -l [Version Label]

  3. Create a configuration template from the current environment.

    PROMPT> elastic-beanstalk-create-configuration-template -E [Environment ID] -a [Application Name] -t [Template Name]

  4. Launch a new environment for the new application version and template.

    PROMPT> elastic-beanstalk-create-environment -e [Environment Name] -t [Template Name] -a [Application Name] -l [Version Label]

    Note

    Environment names must be at least 4 characters, and less than or equal to 23 characters.

  5. Determine if the new environment is Green and Ready.

    PROMPT> elastic-beanstalk-describe-environments -E [Environment ID]

    If the new environment does not come up Green and Ready, you should decide if you want to retry the operation or leave the environment in its current state for investigation. Make sure to terminate the environment after you are finished, and clean up any unused resources.

    Note

    You can adjust the timeout period if the environment doesn't launch in a reasonable time.

  6. After the new environment is Green and Ready, swap the environment CNAMEs.

    PROMPT> elastic-beanstalk-swap-environment-cnames -S [Source Environment ID] -D [Destination Environment ID]

  7. After you have confirmed that the environment CNAME swap has completed, terminate the old environment.

    PROMPT> elastic-beanstalk-terminate-environment -E [Environment ID]

An example script

#! /usr/bin/env ruby
require 'optparse'
require 'json'
require 'timeout'

options = {}
optparse = OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename($0, ".rb")} [options] environment_id"

options[:verbose] = false
opts.on('-v', '--verbose', 'Output more information') do 
options[:verbose] = true;
end

options[:version_label] = nil
opts.on('-l LABEL', '--version-label', 'The application version to deploy to the new environment') do |label|
options[:version_label] = label
end

options[:application_name] = nil
opts.on('-a NAME', '--application-name', 'The name of the application associated with the version to deploy to the new environment.', 
      'Note if this is different from the application associated with the environment you are redeploying, the new environment will be associated with this application.') do |app|
options[:application_name] = app
end

opts.on('-h', '--help', 'Display this information') do 
puts opts
exit
end

end
optparse.parse!

verbose = options[:verbose]
puts "Verbose mode enabled" if verbose
environment_id = ARGV[0]
if (environment_id == nil)
puts optparse.to_s
exit
end

puts "Starting zero downtime deployment for environment: #{environment_id}" if verbose

## Verify Environment exists and has the right status
puts "Verifying environment exists and has correct status/health" if verbose

results = JSON.parse(%x[elastic-beanstalk-describe-environments -j -E #{environment_id}])
environment_info = results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'][0] if (results['DescribeEnvironmentsResponse'] &&
               results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult'] &&
               results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'])

if !environment_info
puts "No such environment found with environment_id: #{environment_id}"
exit
end

env_health = environment_info['Health']
env_status = environment_info['Status']
puts "Current Health: #{env_health}   Current Status: #{env_status}" if verbose
if (("Green" != env_health) || ("Ready" != env_status))
puts "Environment must be Ready and Green to perform a zero downtime deployment. Current Health: #{env_health}  Current Status: #{env_status}"
exit
end

## Verify version exists 
version_label = options[:version_label]
application_name = options[:application_name]

if (! application_name)
application_name = environment_info['ApplicationName']
end

if (! version_label)
version_label = environment_info['VersionLabel']
end

puts "Verifying version #{version_label} in application #{application_name} exists" if verbose
results = JSON.parse(%x[elastic-beanstalk-describe-application-versions -j -a #{application_name} -l #{version_label}])
version_info = results['DescribeApplicationVersionsResponse']['DescribeApplicationVersionsResult']['ApplicationVersions'][0] if (results['DescribeApplicationVersionsResponse'] &&
           results['DescribeApplicationVersionsResponse']['DescribeApplicationVersionsResult'] &&
           results['DescribeApplicationVersionsResponse']['DescribeApplicationVersionsResult']['ApplicationVersions'])

if (!version_info)
puts "No such version #{version_label} in application #{application_name} exists"
exit
end

environment_name = environment_info['EnvironmentName']

## New environment name will have 8 additional characters.  This is important since the environment
##  name is already limited to 25 characters in length (due to ELB usage).  
new_environment_name = environment_name.gsub(/_zdd_\d+$/, "_zdd_#{rand(10)}")

## Create a Configuration Template from the existing environment 
template_name = new_environment_name

puts "Creating ConfigurationTemplate named #{template_name}" if verbose
results = JSON.parse(%x[elastic-beanstalk-create-configuration-template -j -E #{environment_id} -a #{application_name} -t #{template_name}])
template_info = results['CreateConfigurationTemplateResponse']['CreateConfigurationTemplateResult'] if results['CreateConfigurationTemplateResponse']

if (! template_info)
puts "Error when creating configuration template: #{results}"
exit
end

## Launch a new environment with the desired version and template
puts "Creating new environment named #{new_environment_name}" if verbose
results = JSON.parse(%x[elastic-beanstalk-create-environment -j -a #{application_name} -l #{version_label} -e #{new_environment_name} -t #{template_name}} ])
new_environment_info = results['CreateEnvironmentResponse']['CreateEnvironmentResult'] if results['CreateEnvironmentResponse']

if (! new_environment_info)
puts "Error when launching new environment: #{results}"
exit
end

new_environment_id = new_environment_info['EnvironmentId']
puts "New environment: #{new_environment_info}" if verbose

## Wait for the new environment to go ready
## This wait can be customized for a given application to determine when it is really ready 

max_wait_time_sec = 5 * 60;  ## 5 minutes
begin
Timeout::timeout(max_wait_time_sec) do
done = false
while (! done) do 
  puts "Checking if new environment is ready/green" if verbose
  results = JSON.parse(%x[elastic-beanstalk-describe-environments -j -E #{new_environment_id}])
  new_environment_info = results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'][0] if (results['DescribeEnvironmentsResponse'] &&
                         results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult'] &&
                         results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'])

  puts "Current Health: #{new_environment_info['Health']}   Current Status: #{new_environment_info['Status']}" if verbose     
  done = (new_environment_info &&("Ready" == new_environment_info['Status']))
  if (! done)
    sleep 20  ## seconds
  end
end
end
rescue Timeout::Error
puts "Environment does not seem to be launching in a reasonable time.  Exiting after #{max_wait_time_sec} seconds"
exit
end

results = JSON.parse(%x[elastic-beanstalk-describe-environments -j -E #{new_environment_id}])
new_environment_info = results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'][0] if (results['DescribeEnvironmentsResponse'] &&
                   results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult'] &&
                   results['DescribeEnvironmentsResponse']['DescribeEnvironmentsResult']['Environments'])

if (! new_environment_info) 
puts "Error waiting for environment to launch: #{results}"
exit
end

if ("Green" != new_environment_info['Health'])
puts "New Environment is not healthy, aborting"
%x[elastic-beanstalk-terminate-environment -E #{new_environment_id}]
exit
end


## Execute CNAME swap
puts "Executing CNAME Swap between old environment #{environment_id} and new environment: #{new_environment_id}" if verbose
results = JSON.parse(%x[elastic-beanstalk-swap-environment-cnames j -S #{environment_id} -D #{new_environment_id}])

## Clean up resources

## Once comfortable that the environment swap has completed the old environment can be terminated
#results = JSON.parse(%x[elastic-beanstalk-terminate-environment -j -E #{environment_id}])

# Also delete the configuration template
#results = JSON.parse(%x[elastic-beanstalk-delete-configuration-template -j -a #{application_name} -t #{template_name}])

API

To deploy with zero downtime

  1. Check your current environment to make sure it is Green and Ready.

    Call DescribeEnvironments with the following parameter:

    • EnvironmentID = e-pyumupm7mph

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?EnvironmentID=e-pyumupm7mph
    &Operation=DescribeEnvironments
    &AuthParams        

  2. Verify that your new application version exists.

    Call DescribeApplicationVersions with the following parameters:

    • ApplicationName = SampleApp

    • VersionLabel = Version2

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?ApplicationName=SampleApp
    &VersionLabel=Version2
    &Operation=DescribeApplicationVersions
    &AuthParams        

  3. Create a configuration template from the current environment.

    Call CreateConfigurationTemplate with the following parameters:

    • EnvironmentID = e-pyumupm7mph

    • ApplicationName = SampleApp

    • TemplateName = MyConfigTemplate

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?ApplicationName=SampleApp
    &TemplateName=MyConfigTemplate
    &EnvironmentID=e-pyumupm7mph
    &Operation=CreateConfigurationTemplate
    &AuthParams          

  4. Launch a new environment for the new application version and template.

    Call CreateEnvironment with the following parameters:

    • ApplicationName = SampleApp

    • VersionLabel = Version2

    • EnvironmentName = SampleAppEnv2

      Note

      Environment names must be at least 4 characters, and less than or equal to 23 characters.

    • TemplateName = MyConfigTemplate

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?ApplicationName=SampleApp
    &VersionLabel=Version2
    &EnvironmentID=SampleAppEnv2
    &TemplateName=MyConfigTemplate
    &Operation=CreateEnvironment
    &AuthParams             

  5. Determine if the new environment is Green and Ready.

    Call DescribeEnvironments with the following parameters:

    • EnvironmentID = e-eup272zdrw

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?EnvironmentID=e-eup272zdrw
    &Operation=DescribeEnvironments
    &AuthParams        

    If the new environment does not come up Green and Ready, you should decide if you want to retry the operation or leave the environment in its current state for investigation. Make sure to terminate the environment after you are finished, and clean up any unused resources.

    Note

    You can adjust the timeout period if the environment doesn't launch in a reasonable time.

  6. After the new environment is Green and Ready, swap the environment CNAMEs.

    Call SwapEnvironmentCNAMEs with the following parameters:

    • SourceEnvironmentID = e-pyumupm7mph

    • DestinationEnvironmentID = e-eup272zdrw

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?SourceEnvironmentID=e-pyumupm7mph
    &DestinationEnvironmentIDe=e-eup272zdrw
    &Operation=SwapEnvironmentCNAMEs
    &AuthParams

  7. After you have confirmed that the environment CNAME swap has completed, terminate the old environment.

    Call TerminateEnvironment with the following parameters:

    • EnvironmentID = e-pyumupm7mph

    Example

    https://elasticbeanstalk.us-east-1.amazon.com/?EnvironmentId=e-pyumupm7mph
    &Operation=TerminateEnvironment
    &AuthParams