Skip to content

Instantly share code, notes, and snippets.

@kennyhyun
Last active October 4, 2016 02:25
Show Gist options
  • Save kennyhyun/65e3d1bddd2d0777b9b28a31defdc606 to your computer and use it in GitHub Desktop.
Save kennyhyun/65e3d1bddd2d0777b9b28a31defdc606 to your computer and use it in GitHub Desktop.

a guide for deploying Meteor app to Elastic Beanstalk

these are scripts for deploying Meteor apps to AWS Elastic Beanstalk. it is tested in linux and mac. (might not working in Windows)

all files need to be copied relatively to the Meteor app root.

notice

  • AWS has released a new Application Load Balancer. so setting dual port in ELB may not be needed someday when ALB come to Elastic Beanstalk.
  • this is using ../build (from the Meteor app root) directory for building.
  • default-*-names in eb.config.yml and eb.packages.jsonneed to be customised.
  • domain_name in eb.app.config needs to be customised.
  • it generates and adds 512MB swap file in /var/swapfile.
  • in installs node-pre-gyp node package.
  • it copies settings*.json files into deployment package. if you don't want, edit scripts/cp-eb-scripts.sh and use METEOR_SETTING_FILE env variable to set the file location.

prerequisite

  • python
  • pip
  • aws-eb-cli

you can install pip and awsebcli by

$ curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | sudo python
$ sudo pip install awsebcli

AWS credentials needs to be installed. it automatically asks when you eb init for the first time.

script file to deploy

scripts/eb-deploy.sh

before deploying

for the first time since the EB env created, it needs some manual settings for environment variables and Elastic Load Balancer.

since nginx configuration patching is executed during deployment, manual settings for Elastic Beanstalk environment should be done before deployment. but you can deploy anytime later, again and again, if you change settings manually.

Environment variables

you can add it in Elastic Beanstalk console, environment name, Configuration, Software Configuration.

  • DDP_DEFAULT_CONNECTION_URL https://<domain_name>:8443/

  • MONGO_URL mongodb://<user>:<pw>@<ip_addr>:27017/<db_name>

  • PORT 8081

  • ROOT_URL https://<domain_name>/

  • METEOR_SETTING_FILE (if it is a development) ./settings.dev.json

ELB

I am using HTTPS only and redirect HTTP to HTTPS, so it use 80 and 443 port.

But Meteor needs sticky sessions for non websocket clients and websocket needs TCP settings rather than HTTP setting for load balancers. but AWS ELB does not support session stickness on TCP. so you need to setup another port for websocket connection. it will be port 8443 (ssl).

DDP connection will be set to :8443 by default by DDP_DEFAULT_CONNECTION_URL. and Clients should change their DDP connection port to normal (443) for session stickness when websocket is not available.

add a TCP(SSL) port to ELB

if you arlaedy have ssl certificates, you can use it in ELB. or you could create it for free.

in the Load balacers tab in EC2 console, select propriate Listeners tab. and add SSL, 8443, TCP, 80. and input SSL Certificate name and paste private key (.key) and public key(.crt). and Save.

aws-ec2-lb-2

add a rule for TCP port in Security Group

and then, go to Description tab and in the Security tab, click sg-0xxxx link to go to VPC console. there you need to add an Inbound Rules for 8443 port.

Edit, Add another rule, select or input like HTTPS* (8443), TCP (6), 8443, 0.0.0.0/0

aws-vpc-sg

turn on session stickness

in the Elastic Beanstalk console, environment name, Configuration, Load balancer. Turn on session stickiness at Sessions section with expiration period like 600 turn on HTTPS and select certificates input above.

aws-eb-stickness

option_settings:
- option_name: PORT
value: 8081
files:
"/home/ec2-user/addswap" :
mode: "000744"
owner: root
group: root
content: |
#!/bin/sh
if [ -f /var/swapfile ]; then
echo "Swapfile found, assuming already setup"
else
/bin/dd if=/dev/zero of=/var/swapfile bs=1M count=512
/bin/chmod 600 /var/swapfile
/sbin/mkswap /var/swapfile
/sbin/swapon /var/swapfile
fi
container_commands:
01_nginx_static:
command: |
sed -i '/\s*proxy_set_header\s*Connection/c \
proxy_set_header Upgrade $http_upgrade;\
proxy_set_header Connection "upgrade";\
if ($uri !~ "(^/$|^/meteor_runtime_config.js$)") {\
expires 30d;\
}\
if ($http_x_forwarded_proto = 'http') {\
return 301 https://domain_name$request_uri;\
}\
' /tmp/deployment/config/#etc#nginx#conf.d#00_elastic_beanstalk_proxy.conf
02setup_swap:
command: "/home/ec2-user/addswap"
03_global_node_packages:
command: |
`ls -td /opt/elasticbeanstalk/node-install/node-* | head -1`/bin/npm install -g node-pre-gyp
branch-defaults:
default:
environment: default-env-name
group_suffix: null
global:
application_name: default-app-name
default_ec2_keyname: default-key-pair-name
default_platform: 64bit Amazon Linux 2016.03 v2.1.3 running Node.js
default_region: ap-southeast-2
profile: eb-cli
sc: null
{
"name": "default-app-name",
"version": "0.0.1",
"scripts": {
"prestart": "cd programs/server && npm install",
"start": "node main.js"
}
}
8a
var settingfilename = './settings.json';
if (process.env.METEOR_SETTING_FILE)
settingfilename = process.env.METEOR_SETTING_FILE;
var settings = require(settingfilename);
if (settings) {
try {
process.env.METEOR_SETTINGS = JSON.stringify(settings);
} catch (e) {
console.error(e);
}
}
// console.log (JSON.stringify(process.env));
.
w
mkdir -p ../build/bundle/.elasticbeanstalk
mkdir -p ../build/bundle/.ebextensions
cp eb.config.yml ../build/bundle/.elasticbeanstalk/config.yml
cp eb.package.json ../build/bundle/package.json
cp eb.app.config ../build/bundle/.ebextensions/app.config
cp settings*.json ../build/bundle/
#!/bin/sh
# Log helper
log() {
echo "`date` :: $1" >&2
}
if [ -z $1 ]; then
currentBranch=`git rev-parse --abbrev-ref HEAD`
if [ "$currentBranch" != 'master' ]; then
log "Wrong branch. Only master may be tag and published"
exit 2
fi
DATE=`date +%Y-%m-%d-%H%M`
PREVIOUS_TAG=`git describe --tags --abbrev=0`
git tag "$DATE"
git push origin master --tags
log "git branch master tag set ($DATE) and pushed to origin"
fi
log 'start building'
meteor build ../build --architecture os.linux.x86_64 --directory
if [ $? -ne 0 ]; then
exit 1
fi
chmod +w ../build/bundle/main.js
ed - ../build/bundle/main.js < main.js.patch
if [ $? -ne 0 ]; then
exit 2
fi
dir='../build/bundle/programs/server/npm/node_modules'
unamestr=`uname`
if [ "$unamestr" = "Linux" ]; then
log 'touching files to 24 hours ago in Linux'
find $dir -exec touch -d '24 hours ago' {} \;
else
log 'touching files to 24 hours ago'
find $dir -exec touch -m -A-240000 {} \;
fi
if [ $? -ne 0 ]; then
exit 3
fi
cp settings*.json ../build/bundle/
if [ $? -ne 0 ]; then
exit 4
fi
./scripts/cp-eb-scripts.sh
if [ $? -ne 0 ]; then
exit 5
fi
cd ../build/bundle
eb deploy $1
log " *** DEPLOYMENT OVER $? ***"
@kennyhyun
Copy link
Author

just for adding images in md
aws-eb-stickness
aws-ec2-lb-2
aws-vpc-sg

@kennyhyun
Copy link
Author

AWS EB tools create zip file and upload it,
local time stamp (would be) archived.
and when it is uploaded and building node packages in the EC2 instance,
errors like followings

  ACTION Regenerating Makefile
make: Leaving directory `/var/app/current/programs/server/npm/node_modules/bcrypt/build'
make: Entering directory `/var/app/current/programs/server/npm/node_modules/bcrypt/build'
make: Warning: File `../binding.gyp' has modification time 2929 s in the future
  ACTION Regenerating Makefile
make: Leaving directory `/var/app/current/programs/server/npm/node_modules/bcrypt/build'
make: Entering directory `/var/app/current/programs/server/npm/node_modules/bcrypt/build'
make: Warning: File `../binding.gyp' has modification time 2928 s in the future

continuously occur.
probably because the time stamp is before time difference than UTC.

so I touched the timestamps by the build script and it is safe to set to before 24 hours because of summertime or so.

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