Skip to content

Instantly share code, notes, and snippets.

@kdunn926
Last active December 9, 2019 19:05
Show Gist options
  • Save kdunn926/be85897deca6d2df9078222fecfad284 to your computer and use it in GitHub Desktop.
Save kdunn926/be85897deca6d2df9078222fecfad284 to your computer and use it in GitHub Desktop.
CircleCI ElasticBeanstalk deployment with NodeJS application and Docker runtime
version: 2
jobs:
build-test:
docker:
- image: circleci/node:10.7.0
working_directory: ~/repo
steps:
- checkout
- run:
name: Update npm
command: 'sudo npm install -g npm@6'
- run:
name: Concatenate dependencies for cache restoration
# Aggressively key the caching based on ALL project dependencies
command: |
cat package-lock.json \
client/package-lock.json \
server/package-lock.json > all_deps
- restore_cache:
keys:
# use increasingly general patterns to restore cache
- node-v1-{{ .Branch }}-{{ checksum "all_deps" }}
- node-v1-{{ .Branch }}-
- node-v1-
- run:
name: Install dependencies
command: yarn setup
- save_cache:
paths:
- ~/repo/node_modules
- ~/repo/client/node_modules
- ~/repo/server/node_modules
key: node-v1-{{ .Branch }}-{{ checksum "all_deps" }}
- run:
name: Run server tests
command: cd server/ && yarn test
- run:
name: Run client tests
command: cd client/ && yarn test
- persist_to_workspace:
# Stage the application artifacts to a workspace for the deploy step
# This includes the raw application source from Git,
# a `Dockerfile`, and a `Dockerrun.aws.json` file
root: ~/repo
paths:
- ./*
deploy:
docker:
- image: circleci/node:10.7.0
working_directory: /tmp/
steps:
- attach_workspace:
at: /tmp/workspace
- run:
name: Install AWS CLI
command: |
sudo apt-get install python3-pip -y
sudo pip3 install awscli
- run:
# These environment variables need to be defined within the CCI UI
name: Persist application runtime environment
command: |
echo "MONGODB_URL_PROD = ${MONGODB_URL_PROD}" > /tmp/workspace/.env
echo "GITHUB_CLIENT_ID_PROD = ${GITHUB_CLIENT_ID_PROD}" >> /tmp/workspace/.env
echo "GITHUB_CLIENT_SECRET_PROD = ${GITHUB_CLIENT_SECRET_PROD}" >> /tmp/workspace/.env
- run:
name: Create application bundle
# Create a zip file for Elastic Beanstalk deployment using the artifacts
# persisted to the workspace during the build-test step
#
# Note: the production-optimized build is handled in the Dockerfile
command: |
cd workspace
zip -r deployment-${CIRCLE_SHA1}.zip . -x *.git*
- run:
name: Stage application bundle to S3
# Both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables
# need to be defined within the CCI UI - the associated IAM/account needs
# write access to this bucket and the subsequent Elastic Beanstalk application
command: |
cd workspace
aws s3 cp deployment-${CIRCLE_SHA1}.zip s3://mysweetapp.mycoolcompany.com/ \
--region us-west-1
- run:
name: Create new Elastic Beanstalk environment version
# Create a new version of the application using the bundle uploaded to S3
#
# The following two steps assume you have already created an
# Elastic Beanstalk application in the region specified
command: |
aws elasticbeanstalk create-application-version \
--application-name mysweetapp \
--version-label ${CIRCLE_SHA1} \
--source-bundle S3Bucket="mysweetapp.mycoolcompany.com",S3Key="deployment-${CIRCLE_SHA1}.zip" \
--region us-west-1
- run:
name: Wait for any pending deploys to complete before submitting a new one
# Wait until the environment status output no longer contains "Updating"
command: |
until aws elasticbeanstalk describe-environment-health \
--environment-name mysweetapp-prod \
--attribute-names "Status" \
--region us-west-1 | grep -v -m 1 "Updating" ; \
do \
echo "Waiting for a pending deploy to finish"; \
done ;
- run:
name: Apply new environment version to Elastic Beanstalk
# Deploy the new version of the application to the specified environment
command: |
aws elasticbeanstalk update-environment \
--application-name mysweetapp \
--environment-name mysweetapp-prod \
--version-label ${CIRCLE_SHA1} \
--region us-west-1
# All pushes on all branches will build-test, only master will deploy
workflows:
version: 2
build-deploy:
jobs:
- build-test
- deploy:
requires:
- build-test
filters:
branches:
only:
- master
node_modules
client/node_modules
###################################################################################################
#### Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
####
#### Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
#### except in compliance with the License. A copy of the License is located at
####
#### http://aws.amazon.com/apache2.0/
####
#### or in the "license" file accompanying this file. This file is distributed on an "AS IS"
#### BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#### License for the specific language governing permissions and limitations under the License.
###################################################################################################
###################################################################################################
#### This configuration file configures Nginx for Single Docker environments to redirect HTTP
#### requests on port 80 to HTTPS on port 443 after you have configured your environment to support
#### HTTPS connections:
####
#### Configuring Your Elastic Beanstalk Environment's Load Balancer to Terminate HTTPS:
#### http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https-elb.html
####
#### Terminating HTTPS on EC2 Instances Running Docker:
#### http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-singleinstance-docker.html
###################################################################################################
files:
"/etc/nginx/conf.d/proxy.conf":
mode: "000755"
owner: root
group: root
content: |
client_max_body_size 10M;
"/etc/nginx/sites-available/elasticbeanstalk-nginx-docker-proxy.conf":
owner: root
group: root
mode: "000644"
content: |
map $http_upgrade $connection_upgrade {
default "upgrade";
"" "";
}
server {
listen 80;
client_max_body_size 10M;
gzip on;
gzip_comp_level 4;
gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
}
access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd;
access_log /var/log/nginx/access.log;
location / {
set $redirect 0;
if ($http_x_forwarded_proto != "https") {
set $redirect 1;
}
if ($http_user_agent ~* "ELB-HealthChecker") {
set $redirect 0;
}
if ($redirect = 1) {
return 301 https://$host$request_uri;
}
proxy_pass http://docker;
proxy_http_version 1.1;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
FROM node:10
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
RUN npm run setup
RUN npm run build
# NODE_PORT might be more common
ENV PORT 80
EXPOSE 80
CMD [ "npm", "run", "prod" ]
{
"AWSEBDockerrunVersion": "1",
"Ports": [
{
"ContainerPort": "80"
}
],
"Logging": "/var/log"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment