- a deep dive into Docker
- a comparison of Docker with other container services
- a comparison of AWS with other PaaS and IaaS offerings
- basic familiarity with AWS
- basic familiarity with Docker
--- diagram goes here ---
- a tiered VPC with public and private subnets in the us-east-1 region
- a highly available, Fargate-backed ECS cluster deployed across two AZs
- 4 instances of a Rails 5 API fronted by an ALB
- an RDS-managed Postgres database
- a GitHub-integrated CI/CD server for zero-downtime deploys to ECS cluster
- an ECR repository for our application's Docker images
- centralized logging, with CloudWatch
- great, hold them until the end of the prez
- a lightweight container virtualization technology that does not require a hypervisor
- programs are executed in a container isolated from other processes
- helps us to package the application and its dependencies together
- a tool for defining and running multi-container Docker applications
- you use a Compose file to configure your application's services (app, postgres, redis, etc.)
- using a single command, you create and start all the services
- helps us to simulate our AWS environment locally and in CI/CD environment
- collection of IaaS and PaaS offerings from Amazon
- some services we'll use in this presentation include:
- CloudFormation
- RDS (Relational Database Service)
- ECR (Elastic Container Registry)
- ECS (Elastic Container Service)
- CodePipeline
- ALB (Application Load Balancer)
- VPC (Virtual Private Cloud)
- clone repo
- create GitHub personal acccess token, for CodePipeline
rails new
an applicationrails generate
scaffolding for aPost
model + routes- create application secret
- replace
database.yml
- use the Ruby 2.5.0 Alpine image as our base
- install system dependencies w/APK
- copy
Gemfile
andbundle install
before copying app sources, for caching COPY
application sources into image- define a very flexible entrypoint
docker build -t mysweetapp .
docker run mysweetapp "rails db:migrate && rails server -b 0.0.0.0"
- we need a database
- we don't want to rebuild the image every time we make a code change
- define a Postgres service, built from the offical Postgres image
- web service:
- gets a shared volume, which overrides the
COPY
instruction - gets some environment variables which tell it how to connect to DB
- runs Ruby script to ensure DB is up before starting Rails
- exposes web app port to the host OS
- gets a shared volume, which overrides the
docker-compose -f ./websvc/docker-compose.yml run --rm websvc "\
ruby ./wait-for-postgres.rb \
&& rails db:migrate \
&& rails db:test:prepare \
&& rails test"
Add Guard-related dependencies to Gemfile:
group :development do
gem 'guard'
gem 'guard-minitest'
end
Then, install dependencies and update the Gemfile.lock
:
docker-compose -f ./websvc/docker-compose.yml run --rm websvc "\
bundle install \
&& guard init minitest \
&& cp /opt/bundle/Gemfile.lock /opt/app/"
Commit changes. Then, run guard
:
docker-compose -f ./websvc/docker-compose.yml run --rm websvc "\
ruby ./wait-for-postgres.rb \
&& rails db:migrate \
&& rails db:test:prepare \
&& guard"
docker-compose -f ./websvc/docker-compose.yml up
The following command stops the running Docker containers and deletes anonymous volumes attached to containers:
docker-compose -f ./websvc/docker-compose.yml up --volumes
- a Amazon tool which provided a language for describing and provisioning AWS infrastructure
- artifacts under version control
- declarative
- stack (collection of resources)
- resource (VPC, ECS cluster, ALB, IAM user)
- parameter (inputs to template)
- output (outputs from stack)
- deploy --no-execute-changeset (declare the final state that we desire)
- describe-change-set (see what needs to happen in order for that to become a reality)
- deploy (do it)
# s3stuff.yml
Parameters:
BucketName:
Type: String
Resources:
S3Bucket:
Type: AWS::S3::Bucket
Properties:
AccessControl: PublicRead
BucketName: !Ref BucketName
Outputs:
BucketWebsiteURL:
Description: Returns the Amazon S3 website endpoint for the specified bucket.
Value: !GetAtt S3Bucket.WebsiteURL
$ aws cloudformation deploy \
--stack-name foobarbazblix \
--template-file ~/Desktop/s3stuff.yaml \
--parameter-overrides BucketName=foobarbazblix
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - foobarbazblix
$ aws cloudformation describe-stacks \
--stack-name foobarblix
{
"Stacks": [
{
"StackId": "arn:aws:cloudformation:us-east-1:166875342547:stack/foobarbazblix/37c71cd0-f008-11e7-9c6b-5044763dbb7b",
"LastUpdatedTime": "2018-01-02T22:04:27.801Z",
"Parameters": [
{
"ParameterValue": "foobletronica",
"ParameterKey": "BucketName"
}
],
"Tags": [],
"Outputs": [
{
"Description": "Returns the Amazon S3 website endpoint for the specified bucket.",
"OutputKey": "BucketWebsiteURL",
"OutputValue": "http://foobletronica.s3-website-us-east-1.amazonaws.com"
}
],
"EnableTerminationProtection": false,
"CreationTime": "2018-01-02T22:04:20.457Z",
"StackName": "foobarbazblix",
"NotificationARNs": [],
"StackStatus": "CREATE_COMPLETE",
"DisableRollback": false,
"ChangeSetId": "arn:aws:cloudformation:us-east-1:166875342547:changeSet/awscli-cloudformation-package-deploy-1514930659/9657151d-0e00-40f0-a8b2-1abcc9d8d307",
"RollbackConfiguration": {}
}
]
}
$ aws cloudformation describe-stacks \
--stack-name foobarbazblix \
--query 'Stacks[0].Outputs[0].OutputValue' \
| tr -d "\""
http://foobletronica.s3-website-us-east-1.amazonaws.com
Six parts, several-hundred lines:
- networking and security
- ECR
- RDS
- ECS and ALB
- CI/CD pipeline
- public and private subnets
- virtualized network equipment (NAT gateway, IGW) which permits stuff in VPC to talk to Internet (and vice-versa)
- security groups to control ingress to various parts of system
- holds our Docker images
- hosts Postgres for us
- cluster
- service
- task definition
- load balancer
- a collection of services with a name
- number of desired applications behind load balancer
- deployment strategy (blue/green deploy? outage?)
- ingress rules / security groups
- registration with load balancer
- resources (CPU units, memory) required for each app
- Docker command to run the app
- container port-mappings
- logging configuration
- healthcheck paths and ports
- forwarding rules
- applications log to stdout
- logs are sent to single CloudWatch group
- log streams are linked to the origin container
- polls GitHub using an OAuth token
- pulls changes when detected
- builds application using Docker Compose
- runs tests
- pushes image to ECR
- updates ECS service definition to use new image
- blue/green or outage depends on "minimum healthy percentage" and "maximum healthy percentage" and "desired count"-properties of ECS service
- blue/green ("zero-downtime") deploys require careful processes to ensure backwards compatibility!
- Rails has some tools which aim to prevent multiple apps from simultaneously running migrations
- not particularly difficult to package a Rails application as a Docker container
- use Docker Compose locally and in CI to simulate integrated environment
- deploy everything to a sophisticated AWS environment via version-controlled artifacts