Skip to content

Instantly share code, notes, and snippets.

@ryanlabouve
Last active January 27, 2017 09:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ryanlabouve/536e48bf7c76efc4b6ec to your computer and use it in GitHub Desktop.
Save ryanlabouve/536e48bf7c76efc4b6ec to your computer and use it in GitHub Desktop.
Ember Deploy Notes (s3 and redis)
// Notes from our previous deploy strategy

CI for Ember-CLI App using

Using ember-cli-deploy we will deploy our Ember(-cli) app to S3 (and cloudfront), Redis via github and codeship.

Since skill-set's may vary, set's start by breaking this down at a high level:

This is a CI (continuous deployment setup. Every time we push certain branches to github, this will trigger a deployment

What happens in deployment

  • Codeship detects that we pushed to github and sets up our build environment
  • First, it builds our ember app for production (or whatever environment we pass in)
  • Next, it pushes dist/index.html to our RedisToGo
    • This is served from an app we'll setup on Heroku as the main page to our site
  • Every other asset will be served from Cloudfront (a CDN front for our AWS S3 bucket)

Our App Heroku— will have a simple Sinatra app (there are node alternatives if you are in to that) running that grabs our most recently deployed index.html from Redis.

RedisToGo— This is our hosted redis database that's attached to our sinatra app and where our deployment launches index.html.

Cloudfront (via S3)— Cloudfront will act as our CDN for a AWS S3 bucket that contains all of our application assets.

Working together— Users will hit our Heroku app, which will serve up our index.html from Redis. Inside of that index.html, all of the assets will point to Cloudfront.

Getting started

Run our ember app locally

I've thrown together a demo project that have a few features to help us make sure our setup works:

  • Different routes, so we can test visiting more than just the root /
  • Stylesheets, so we can make sure our assets are pulling in properly as well
  • A few tests so we can make sure they run when we push

You can grab a copy of the project here without and of the deploy steps done.

Deploy Setup

Now we'll setup our otherwise generic Ember App for deployment.

Install ember-cli-deploy and the redis and s3 plugins:

# https://www.npmjs.com/package/ember-cli-deploy
npm install ember-cli-deploy --save-dev
npm install ember-deploy-redis ember-deploy-s3 --save-dev

Now, we'll try to dumbly deploy.

  • Run ember deploy, error, no config/deploy.js
  • Run ember deploy again, and credential issues (because we haven't put in any Redis or other info)

Redis

Redis is a "key-value cache and store". Give it a try if you've never messed with it: http://try.redis.io/

Install Redis (bonus)

Before we get started, it can help to install redis locally to do some basic trouble shooting here.

  • Install homebrew if you haven't already
  • brew install redis

Given our redis to go link, let's try to connect. First, make sure you have redis installed locally so you have access to the redis-cli tool.

Heroku and RedisToGo

easy troubleshooting

Now refernce the long link we got from redis to go to grap host, port, and password.

At this point it's critical to realize how this link needs to be treated very securly.

Given the concepts, let's make something happen here.

http://stackoverflow.com/questions/17846371/how-to-connect-to-redistogo-how-to-see-the-data

# redis://redistogo:9999999999999999999@bearfish.redistogo.com:0000/
redis-cli -h bearfish.redistogo.com -p 0000 -a 9999999999999999999

Sinatra and Redis

  • Clone the reader (Sinatra app)
    • Bundle
  • Change environment variables
  • connect to redis and add

All Togeter Now, Heroku, Sinatra, and Redis

Get something out of Reids on the localhost

  • add to your local repo heroku git:remote -a orgname-reponame -r orgname-reponame
  • push
  • Add config varaibles heroku config:add REDISTOGO_URL=redis://redistogo:9999999999999999999@bearfish.redistogo.com:0000/ PROJECT_NAME=projectname --app reponame
  • Visit the http, and there you see your sample text from the last section!

Now it's time to hook it up to our ember deploy.

Back to Ember: Redis

Deploy redis from Ember

  • Update config/deploy.js

  • install node dotenv, and add the loader npm install dotenv --save

  • make your dot env file require('dotenv').load();

  • deploy

  • log in to redistogo to look at the list of keys

  • show that you get the index.html page from redis to go

  • also heroku open to show you get the correct index.html

AWS

Now that we have our index page deploying correctly, the next big issue is getting AWS setup right. This is a painful process, so hang in there.

AWS: Setting up the Bucket(s)

Sign into your AWS account, log into the AWS console, and then go to S3.

We'll create a bucket to hold everything except index.html.

For a lot of the steps here I followe a great article: http://kerrygallagher.co.uk/deploying-an-ember-cli-application-to-amazon-s3/

  • Create new bucket Console -> S3 -> Create bucket -> [name bucket]

  • Create special user for bucket, as to keep permissions well scoped services -> IAM. Users -> Create new users

    I'll call mine ember-deploy. Make sure to save the acces key id and secret access key.

  • Next, assign IAM policy to user ember-deploy

{
  "Statement": [
    {
      "Action": "s3:*",
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::<ASSETS BUCKET NAME>",
        "arn:aws:s3:::<ASSETS BUCKET NAME>/*",
      ]
    }
  ]
}
  • Next, assign bucket properties to allow world-writability

    S3 panel -> "Right click bucket" -> properties -> permissions -> Add bucket policy

{
    "Statement": [
        {
            "Sid": "AllowPublicRead",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<BUCKET NAME>/*"
        }
    ]
}

Sanity check

Ok, so let's plug in our keys into our deploy.js.

Access Key ID: 000000000000000000 Secret Access Key: 0000000000000000000000000000000000

S3_ACCESS_KEY_ID=000000000000000000
S3_SECRET_ADDESS_KEY=0000000000000000000000000000000000

IRL: I use transmit instead of the S3 interface. If you use transmit at all, do it.

Error I was getting: Unable to sync: PermanentRedirect: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.

Use "region": "us-west-2", or whatever that is, to indicate. Here's where you can find all the things: http://docs.aws.amazon.com/general/latest/gr/rande.html

ember deploy:assets

sanity check one: Look at data on S3 to make sure it's coming through

sanity check #2 access stuff from web.

Bucket Cleanup

Now let's cleanup our buckets by specifying which prefix bucket name we are using: "prefix": "production"

wipe out all uploaded files, and upload again

ember deploy:assets --environment=development ember deploy:assets --environment=production ember deploy:assets --environment=staging

CloudFront: Bucket -> CDN

AWS -> Cloudfront

Setp1: Select Deliver Method web

Setp 2: Create a distribution Origin Domain Name: www.domain.com.s3.amazonaws.com Origin Path: /staging Oriding ID: (I just leave it) (I also didn't restrict bucket access)

Which Gives Us Domain: .cloudfront.net

Fingerprint

Currently, our assets (from our sinatra app) point to the ether. We need to fingerprint them for use with cloudfront

in brocfile,

var app = new EmberApp({
  fingerprint: {
    prepend: '<cloudfront-id-thingy>.cloudfront.net'
  }
});

All is well, right? Nope.

Setting up staging as a production like environment

From the ember cli docs, here's my solution.

/* global require, module */
require('dotenv').load();
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

// This is all to set the correct CDN per environment
var env = EmberApp.env() || 'development';
var isProductionLikeBuild = ['production', 'staging'].indexOf(env) > -1;
var asset_arg = 'ASSETS_PREPEND_PATH_' + env.toUpperCase();
var prepend_path = env ? process.env[asset_arg] + '/' : '';

var app = new EmberApp({
  fingerprint: {
    enabled: isProductionLikeBuild,
    prepend: prepend_path
  },
  sourcemaps: {
    enabled: !isProductionLikeBuild
  },
  minifyCSS: { enabled: isProductionLikeBuild },
  minifyJS: { enabled: isProductionLikeBuild },
  tests: process.env.EMBER_CLI_TEST_COMMAND || !isProductionLikeBuild,
  hinting: process.env.EMBER_CLI_TEST_COMMAND || !isProductionLikeBuild,
});

module.exports = app.toTree();

Codeship:

http://treyhunner.com/2015/03/deploying-an-ember-cli-application-via-ssh/

From trey's blog $ export tag="example:$(git rev-parse --short HEAD)" $ ember deploy:activate --revision $tag --environment production

Test

[setup commands]

npm install -g codeclimate-test-reporter
npm install -g ember-cli bower phantomjs
bower install --quiet
npm install
touch .env

[Configure Test Pipelines]

# This is blowing up on staging and working find on local
# Troubleshooting (4/2)
ember test
# use the magic of sed to replace "dashboard/" with ""
# yey! blanket fixed this... sed -i.bak 's/SF:dashboard/SF:./g' lcov.info
#if [ "$CI_BRANCH" == "develop" ]; then CODECLIMATE_REPO_TOKEN=0000000000000000 codeclimate < lcov.info; fi

Deployment

#ember deploy --environment=production
#export tag="dashboard:$(git rev-parse --short HEAD)"
#ember deploy:activate --revision=$tag --environment=production
#ember deploy:list --environment=production

Environment

All the .env variables

Notification

Post slack webhook

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment