ElasticBeanstalk
Configure and deploy a rails app to Elastic Beanstalk via rake in 60 seconds. Maintain multiple environment DRY configurations and .ebextensions in one easy to use yaml configuration file.
This gem simplifies configuration, and passes the heavy lifting to the eb_deployer from ThoughtWorksStudios.
Installation
Add this line to your application's Gemfile:
gem 'elastic-beanstalk'
And then execute:
$ bundle
Or install it yourself as:
$ gem install elastic-beanstalk
Features
The elastic-beanstalk gem provides:
- Rake tasks to simplify all interactions
- Multi-environment configuration inheritance for DRY yaml configs
- Keep all configurations including .ebextensions in one yaml file (they are inheritable and can be overridden too)
- Full access to the range of configuration options provided by AWS Elastic Beanstalk
- Provide access to helpers such as the SmokeTester to simplify configurations
Plus
Since eb_deployer is doing the heavy lifting, by proxy you get access to great continuous delivery features such as:
-
blue-green
deployment strategy -
inplace-update
deployment strategy - Smoke Testing upon deployment before
blue-green
CNAME switching
Usage
Given an application named 'acme':
Step 1: Add ~/.aws/acme.yml
This should contain the access and secret keys generated from the selected IAM user. This is the only file that will need to reside outside the repository. Note that this location is configurable in the config/eb.yml
file.
access_key_id: XXXXXX
secret_access_key: XXXXXX
Step 2. Add a config/eb.yml to your rails project
Something like this should get you started
app: acme
region: us-east-1
solution_stack_name: 64bit Amazon Linux 2015.03 v2.0.0 running Ruby 2.2 (Passenger Standalone)
strategy: inplace-update
keep_latest: 10
development:
options:
aws:autoscaling:launchconfiguration:
InstanceType: t1.micro
production:
strategy: blue-green
options:
aws:autoscaling:launchconfiguration:
InstanceType: t1.small
Step 3. Package and deploy
The default is the 'development' environment, change this via command line arguments
$ rake eb:package eb:deploy
Step 4. Get some coffee
This will take a while. TODO: investigate methods to speed up deployment i.e. cache bundle. Feel free to post yours in the wiki.
Rake Tasks
EB
rake eb:clobber # Remove any generated package
rake eb:config[environment,version] # Setup AWS.config and merge/override environments into one resolved configuration
rake eb:deploy[environment,version] # Deploy to Elastic Beanstalk
rake eb:destroy[force] # ** Warning: Destroy Elastic Beanstalk application and *all* environments
rake eb:package[environment,version] # Package zip source bundle for Elastic Beanstalk
rake eb:show_config[environment,version] # Show resolved configuration without doing anything
EB:RDS Rake Tasks
The EB:RDS tasks are intended to make use of RDS tasks simple given existing configuration in the eb.yml.
i.e. create a snapshot before or after an eb:deploy
. The following rake tasks exist:
rake eb:rds:create_snapshot[instance_id,snapshot_id] # Creates an RDS snapshot
rake eb:rds:instances # List RDS instances
rake eb:rds:snapshots # List RDS snapshots
For example, this would create a snapshot prior to the deployment (and migration) to version 1.1.0:
rake eb:rds:create_snapshot[acme, pre-1.1.0] eb:deploy[1.1.0]
Using RAILS_ENV vs :environment:
Some people prefer to use RAILS_ENV
, others prefer to use the :environment
argument. Both are accepted. Depending on the use case, each one can be DRYer than the other.
Where the task specifies [:environment, :version]
, consider the :environment
optional if you want to use the default of development
or utilize the RAILS_ENV
instead.
NOTE: if using the argument :environment
, you must specify it for both the eb:package
and eb:deploy
, as eb:package
is responsible for injecting the RACK_ENV
and RAILS_ENV
in aws:elasticbeanstalk:application:environment
section of the .ebextensions
file.
:version
If not specified, version will be auto-generated via and MD5 hash of the package file. If specified to the eb:package
task, the version will be available as the APP_VERSION
environment variable, specified in the aws:elasticbeanstalk:application:environment
section of the .ebextensions
file.
A real-world example
Deploy version 1.1.3 of acme to production using the :environment
parameter
$ rake eb:package[production,1.1.3] eb:deploy[production,1.1.3]
Deploy version 1.1.3 of acme to production using RAILS_ENV
$ RAILS_ENV=production rake eb:package[1.1.3] eb:deploy[1.1.3]
Deploy an MD5 hashed version of acme to production using the :environment
parameter
$ rake eb:package[production] eb:deploy[production]
Deploy an MD5 hashed version of acme to production using RAILS_ENV
$ RAILS_ENV=production rake eb:package eb:deploy
Deploy an MD5 hashed version of acme to development
$ rake eb:package eb:deploy
config/eb.yml
# This is a sample that has not been executed so it may not be exactly 100%, but is intended to show
# that access to full options_settings and .ebextensions is intended.
#---
# http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options.html#command-options-ruby
#
# This is a sample that has not been executed so it may not be exactly 100%, but is intended to show
# that access to full options_settings and .ebextensions is intended.
#---
app: acme
region: us-east-1
# Choose a platform from http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts.platforms.html
solution_stack_name: 64bit Amazon Linux 2015.03 v2.0.0 running Ruby 2.2 (Passenger Standalone)
strategy: inplace-update # default to inplace-update to avoid starting new environments
keep_latest: 10
package:
verbose: true
includes: ['public/assets/.sprockets-manifest-*.json'] # ensure '.' manifest is added when using assets:precompile
exclude_dirs: [features, spec, target, coverage, vcr, flows] # additional dirs that merge with default excludes
exclude_files: [.ruby-*, rspec.xml, README*, db/*.sqlite3, bower.json]
smoke_test: |
lambda { |host|
EbSmokeTester.test_url("http://#{host}/health", 600, 5, 'All good! Everything is up and checks out.')
}
#--
ebextensions:
# General settings for the server environment
01-environment.config:
commands:
01timezone:
command: "ln -sf /usr/share/zoneinfo/America/Chicago /etc/localtime"
# These are things that make sense for any Ruby application
02-ruby.config:
# Install git in order to be able to bundle gems from git
packages:
yum:
git: []
patch: []
# Run rake tasks before an application deployment
03-rake.config:
container_commands:
01seed:
command: rake db:seed
leader_only: true
#---
options:
# Any environment variables - will be available in ENV
aws:elasticbeanstalk:application:environment:
FOO: 'bar'
RAILS_SKIP_ASSET_COMPILATION: true # Use if doing asset compilation before packaging (recommended)
aws:autoscaling:launchconfiguration:
EC2KeyName: eb-ssh
SecurityGroups: 'acme-production-control'
aws:autoscaling:asg:
MinSize: 1
MaxSize: 5
# Restrict to Reserved Instance zone: http://stackoverflow.com/a/33131364/2363935
'Custom Availability Zones': us-east-1c
'Availability Zones': Any 1
aws:elb:loadbalancer:
SSLCertificateId: 'arn:aws:iam::XXXXXXX:server-certificate/acme'
LoadBalancerHTTPSPort: 443
aws:elb:policies:
Stickiness Policy: true
aws:elasticbeanstalk:sns:topics:
Notification Endpoint: 'alerts@acme.com'
aws:elasticbeanstalk:application:
Application Healthcheck URL: '/health'
#---
# Set "inactive_settings" for saving cost on blue green deployment
# https://github.com/ThoughtWorksStudios/eb_deployer/wiki/Elastic-Beanstalk-Tips-and-Tricks#set-inactive_settings-for-saving-cost-on-blue-green-deployment
inactive:
aws:autoscaling:asg:
MinSize: 0
MaxSize: 0
Cooldown: 900
aws:autoscaling:updatepolicy:rollingupdate:
RollingUpdateEnabled: false
#---
development:
options:
aws:autoscaling:launchconfiguration:
InstanceType: t1.micro
aws:elasticbeanstalk:application:environment:
RAILS_SKIP_ASSET_COMPILATION: true
#---
production:
strategy: blue-green # always fire up a new environment and healthcheck before transitioning cname
options:
aws:autoscaling:launchconfiguration:
InstanceType: t1.small
ENV interpolation
ENV variable interpolation is provided by dry-config. Any of the values in the eb.yml
may contain interpolated values.
The following formats are acceptable:
- ~/foo
- $HOME/foo
- ${HOME}/foo
- #{HOME}/foo
Additional options
Most of the configurations are defaulted. The following are less obvious but may be useful:
secrets_dir: (default: '~/.aws')
package:
verbose: (default: false)
dir: (default: 'pkg')
eb_deployer additional options
The following are passed if not nil, otherwise eb_deployer assigns an appropriate default.
inactive_settings: (nil if unspecified)
package_bucket:
keep_latest: (if unspecified, it will keep all past versions in the S3 bucket)
version_prefix:
tier:
Still to come
- Speedier deployments - investigate caching of bundle and asset pre-compilation to see if there is a common setting to be found
Contributing
Please contribute! While this is working great, a greater scope of functionality is certainly easily attainable with this foundation in place.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
Copyright and License
Copyright (c) 2014-2015 AlienFast, LLC. MIT License, see LICENSE.txt for further details.