Commit 6ca4631e authored by O'Reilly Media, Inc.'s avatar O'Reilly Media, Inc.
Browse files

Initial commit

parents
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\margl1440\margr1440\vieww9000\viewh8400\viewkind0
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
\f0\fs24 \cf0 No work files for this lesson...}
\ No newline at end of file
FROM node:0.12.1-slim
EXPOSE 8080
ADD package.json package.json
RUN npm install --save
ADD app.js app.js
CMD node app.js
/* A simple web service for O'Reilly's Docker on AWS video series
*
* This service exposes four endpoints:
* - GET / - Returns 200 with JSON body containing the current service
* count.
* - GET /version - Returns JSON describing the service version.
* - PUT /inc - Increment the service count. Returns 204.
* - PUT /dec - Decrement the service count. Returns 204.
*/
var express = require('express');
var morgan = require('morgan');
var PORT = process.env.PORT || 8080;
var count = 0;
var app = express();
app.use(morgan('[:date[iso]] :method :url\t:status'));
app.get('/', function (req, res) {
res.status(200).send({count: count});
});
app.put('/inc', function (req, res) {
count += 1;
res.status(204).end();
});
app.put('/dec', function (req, res) {
count -= 1;
res.status(204).end();
});
app.listen(PORT);
console.log('Running on http://localhost:' + PORT);
#!/usr/bin/env bash
docker build --tag rkneufeld/sample-service:simple .
{
"name": "sample-service",
"version": "1.0.0",
"private": true,
"description": "A sample service for O'Reilly's Docker on AWS video",
"author": "Ryan Neufeld <ryan@rkn.io>",
"license": "MIT",
"dependencies": {
"express": "4.12.3",
"morgan": "1.5.2"
},
"repository": {
"type": "git",
"url": "https://github.com/rkneufeld/docker-on-aws.git"
}
}
#!/usr/bin/env bash
echo "Launching Sample Service..."
echo "Press <ctrl-c> to exit."
docker run --tty \
--interactive \
--rm \
--publish 8080:8080 \
--name "sample-service" \
rkneufeld/sample-service:simple
{
"family": "sample-service",
"containerDefinitions": [
{
"name": "sample-service",
"image": "rkneufeld/sample-service:simple",
"cpu": 512,
"memory": 500,
"entryPoint": [],
"environment": [],
"command": [],
"portMappings": [
{
"hostPort": 8080,
"containerPort": 8080
}
],
"volumesFrom": [],
"links": [],
"mountPoints": [],
"essential": true
}
],
"volumes": []
}
FROM node:0.12.1-slim
EXPOSE 8080
ENV DB_HOST=redis
ENV DB_PORT=6379
ADD package.json package.json
RUN npm install --save
ADD app.js app.js
CMD node app.js
/* A simple web service for O'Reilly's Docker on AWS video series
*
* This service exposes four endpoints:
* - GET / - Returns 200 with JSON body containing the current service
* count.
* - GET /version - Returns JSON describing the service version.
* - PUT /inc - Increment the service count. Returns 204.
* - PUT /dec - Decrement the service count. Returns 204.
*/
// Express setup (incl. logging)
var express = require('express');
var morgan = require('morgan');
var PORT = process.env.PORT || 8080;
var app = express();
app.use(morgan('[:date[iso]] :method :url\t:status'));
// Redis Setup
var redis = require('redis'),
client = redis.createClient(process.env.DB_PORT, process.env.DB_HOST, {});
client.on('connect', function() {
console.log('Connected to Redis');
});
// Helper Functions
function getCount(callback) {
return client.get('count', callback);
}
// Routes
app.get('/', function (req, res) {
getCount(function (err, reply) {
var value = (reply == null ? 0 : parseInt(reply));
res.status(200).send({count: value});
});
});
app.put('/inc', function (req, res) {
client.incr('count');
res.status(204).end();
});
app.put('/dec', function (req, res) {
client.decr('count');
res.status(204).end();
});
// Launch server
app.listen(PORT);
console.log('Running on http://localhost:' + PORT);
#!/usr/bin/env bash
docker build --tag rkneufeld/sample-service:redis .
{
"containerDefinitions": [
{
"volumesFrom": [],
"portMappings": [
{
"hostPort": 30001,
"containerPort": 30001,
"protocol": "tcp"
}
],
"command": [
"syslog://<TODO: Papertrail endpoint:port (e.g. logsN.papertrailapp.com:NNNNN)>"
],
"environment": [],
"essential": true,
"entryPoint": [],
"links": [],
"mountPoints": [
{
"containerPath": "/tmp/docker.sock",
"sourceVolume": "docker-socket",
"readOnly": false
}
],
"memory": 50,
"name": "logspout",
"cpu": 50,
"image": "gliderlabs/logspout"
}
],
"volumes": [
{
"host": {
"sourcePath": "/var/run/docker.sock"
},
"name": "docker-socket"
}
],
"family": "logspout"
}
{
"name": "sample-service",
"version": "1.0.0",
"private": true,
"description": "A sample service for O'Reilly's Docker on AWS video",
"author": "Ryan Neufeld <ryan@rkn.io>",
"license": "MIT",
"dependencies": {
"express": "4.12.3",
"morgan": "1.5.2",
"redis": "0.12.1"
},
"repository": {
"type": "git",
"url": "https://github.com/rkneufeld/docker-on-aws.git"
}
}
{
"containerDefinitions": [
{
"volumesFrom": [],
"portMappings": [
{
"hostPort": 6379,
"containerPort": 6379,
"protocol": "tcp"
}
],
"command": [],
"environment": [],
"essential": true,
"entryPoint": [],
"links": [],
"mountPoints": [],
"memory": 250,
"name": "redis",
"cpu": 256,
"image": "redis"
}
],
"volumes": [],
"family": "redis"
}
#!/usr/bin/env bash
echo "Launching Redis..."
docker run --detach \
--publish 6379:6379 \
--name redis \
redis
#!/usr/bin/env bash
echo "Launching Sample Service..."
docker run --detach \
--link redis:redis \
--publish 8080:8080 \
--name "sample-service" \
rkneufeld/sample-service:redis
{
"family": "sample-service",
"containerDefinitions": [
{
"name": "sample-service",
"image": "rkneufeld/sample-service:redis",
"cpu": 256,
"memory": 250,
"entryPoint": [],
"environment": [],
"command": [],
"portMappings": [
{
"hostPort": 8080,
"containerPort": 8080
}
],
"volumesFrom": [],
"links": [
"redis:redis"
],
"mountPoints": [],
"essential": true
},
{
"name": "redis",
"image": "redis",
"cpu": 256,
"memory": 250,
"entryPoint": [],
"environment": [],
"command": [],
"portMappings": [
{
"hostPort": 6379,
"containerPort": 6379
}
],
"volumesFrom": [],
"links": [],
"mountPoints": [],
"essential": true
}
],
"volumes": []
}
{
"containerDefinitions": [
{
"volumesFrom": [],
"portMappings": [
{
"hostPort": 8080,
"containerPort": 8080,
"protocol": "tcp"
}
],
"command": [],
"environment": [
{
"name": "DB_HOST",
"value": "TODO - Replace with your own ELB DNS"
}
],
"essential": true,
"entryPoint": [],
"links": [],
"mountPoints": [],
"memory": 250,
"name": "sample-service",
"cpu": 256,
"image": "rkneufeld/sample-service:redis"
}
],
"volumes": [],
"family": "sample-service-elb"
}
web:
image: rkneufeld/sample-service:redis
ports:
- "8080:8080"
environment:
- DB_HOST=redis
links:
- redis:redis
redis:
image: redis
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Small ECS cluster with sample-service running on auto-scaling group.",
"Parameters": {
"ClusterSize": {
"Description": "Number of instances to run in the ECS cluster",
"Type": "Number",
"Default": "1",
"MinValue": "0",
"MaxValue": "10",
"ConstraintDescription": "must lower than 10 (or, raise the limits in template)."
},
"ClusterInstanceType": {
"Description": "ECS Cluster Instance Type",
"Type": "String",
"Default": "t2.micro",
"AllowedValues": ["t2.micro", "t2.small", "t2.medium", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "g2.2xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "d2.xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge"],
"ConstraintDescription": "must be a valid HVM instance type."
},
"KeyName": {
"Description": "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription": "must be the name of an existing EC2 KeyPair."
}
},
"Mappings": {
"RegionToECSOptimizedAMI": {
"us-east-1": {"AMI": "ami-8da458e6"},
"us-west-2": {"AMI": "ami-db0306eb"},
"eu-west-1": {"AMI": "ami-7948320e"},
"ap-northeast-1": {"AMI": "ami-fa12b7fa"},
"ap-southeast-2": {"AMI": "ami-014f353b"}
}
},
"Resources": {
"SampleServiceELB": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"AvailabilityZones": {"Fn::GetAZs" : ""},
"Listeners": [{
"LoadBalancerPort": "80",
"InstancePort": "8080",
"Protocol": "HTTP"
}],
"HealthCheck": {
"HealthyThreshold": "2",
"Interval": "10",
"Target": "HTTP:8080/",
"Timeout": "5",
"UnhealthyThreshold": "6"
}
}
},
"RedisELB": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"AvailabilityZones": {"Fn::GetAZs" : ""},
"SecurityGroups": [{"Fn::GetAtt": ["RedisELBSecurityGroup", "GroupId"]}],
"Listeners": [{
"LoadBalancerPort": "6379",
"InstancePort": "6379",
"Protocol": "TCP"
}],
"HealthCheck": {
"HealthyThreshold": "2",
"Interval": "10",
"Target": "TCP:6379",
"Timeout": "5",
"UnhealthyThreshold": "6"
}
}
},
"RedisELBSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow Cluster access to Redis (purposefully open for easier bootstrap-use internal scheme for production).",
"SecurityGroupIngress": [{
"IpProtocol": "tcp",
"FromPort": "6379",
"ToPort": "6379",
"CidrIp": "0.0.0.0/0"
}]
}
},
"RedisSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow Cluster access to Redis",
"SecurityGroupIngress": [{
"IpProtocol": "tcp",
"FromPort": "6379",
"ToPort": "6379",
"SourceSecurityGroupOwnerId": {"Fn::GetAtt": ["RedisELB", "SourceSecurityGroup.OwnerAlias"]},
"SourceSecurityGroupName": {"Fn::GetAtt" : ["RedisELB", "SourceSecurityGroup.GroupName"]}
}]
}
},
"ClusterSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "Allow inbound access to Cluster (8080, 22)",
"SecurityGroupIngress": [{
"IpProtocol": "tcp",
"FromPort": "8080",
"ToPort": "8080",
"SourceSecurityGroupOwnerId": {"Fn::GetAtt": ["SampleServiceELB", "SourceSecurityGroup.OwnerAlias"]},
"SourceSecurityGroupName": {"Fn::GetAtt" : ["SampleServiceELB", "SourceSecurityGroup.GroupName"]}
}, {
"IpProtocol": "tcp",
"FromPort": "22",
"ToPort": "22",
"CidrIp": "0.0.0.0/0"
}]
}
},
"ClusterAutoScalingGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {"AvailabilityZones": {"Fn::GetAZs": ""},
"LaunchConfigurationName": {"Ref": "ClusterLaunchConfig"},
"MinSize": "0",
"MaxSize": "10",
"DesiredCapacity": {"Ref": "ClusterSize"},
"Tags": [{
"Key": "Name",
"Value": {"Fn::Join": ["", ["ECS - ", {"Ref": "AWS::StackName"}]]},
"PropagateAtLaunch": true
}]
}
},
"ClusterLaunchConfig": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"ImageId": {"Fn::FindInMap": ["RegionToECSOptimizedAMI", {"Ref": "AWS::Region"}, "AMI"]},
"InstanceType": {"Ref": "ClusterInstanceType"},
"IamInstanceProfile": "ecsInstanceRole",
"KeyName": {"Ref": "KeyName"},
"SecurityGroups": [{"Ref": "ClusterSecurityGroup"}, {"Ref": "RedisSecurityGroup"}],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash\n",
"echo ECS_CLUSTER=", {"Ref": "Cluster"}, " >> /etc/ecs/ecs.config\n"
]
]
}
}
}
},