docker for ruby developers

95

Click here to load reader

Upload: aptible

Post on 19-Aug-2015

32 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Docker for Ruby Developers

Docker for Ruby DevelopersNYC.rb, August 2015

Frank Macreery CTO, Aptible @fancyremarker https://speakerdeck.com/fancyremarker

Page 2: Docker for Ruby Developers
Page 3: Docker for Ruby Developers

DockerWhat’s it all about?

Page 4: Docker for Ruby Developers
Page 5: Docker for Ruby Developers
Page 6: Docker for Ruby Developers

DockerContainers: The new virtual machines?

Page 7: Docker for Ruby Developers

https://www.docker.com/whatisdocker

Then: Virtual Machines

Page 8: Docker for Ruby Developers

https://www.docker.com/whatisdocker

Page 9: Docker for Ruby Developers

https://www.docker.com/whatisdocker

Now: Containers

Page 10: Docker for Ruby Developers

https://www.docker.com/whatisdocker

Page 11: Docker for Ruby Developers

Getting Started with Docker

Page 12: Docker for Ruby Developers

boot2docker

Page 13: Docker for Ruby Developers

Kitematic

Page 14: Docker for Ruby Developers

Getting Started with DockerInstall boot2docker viahttp://boot2docker.io/#installation

echo 'eval "$(boot2docker shellinit)"' >> ~/.bashrc

Page 15: Docker for Ruby Developers

Getting Started with DockerAlternatively (if you have Homebrew and VirtualBox installed)… brew install boot2docker brew install docker

Page 16: Docker for Ruby Developers

Getting Started with DockerImages and containers

Page 17: Docker for Ruby Developers

docker pull quay.io/aptible/nginx:latest

Page 18: Docker for Ruby Developers

docker pull quay.io/aptible/nginx:latest

Reference to a Docker image

Page 19: Docker for Ruby Developers

docker pull quay.io/aptible/nginx:latest

Image "repositories" can have many "tags"

Page 20: Docker for Ruby Developers

docker pull quay.io/aptible/nginx:latest

Pulls an image from a Docker "registry"

Page 21: Docker for Ruby Developers

A single Docker image consists of many "layers"

Page 22: Docker for Ruby Developers

docker images

Page 23: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ quay.io/aptible/nginx:latest

Page 24: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ quay.io/aptible/nginx:latest

Launches a new container from an existing image

Page 25: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ quay.io/aptible/nginx:latest

Forward container ports to the host (host port:container port)

Page 26: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ quay.io/aptible/nginx:latest

Run container in background

Page 27: Docker for Ruby Developers

docker ps

Page 28: Docker for Ruby Developers
Page 29: Docker for Ruby Developers
Page 30: Docker for Ruby Developers

Simplifying SOAService-oriented architectures without the complexity

Page 31: Docker for Ruby Developers

Dev/prod parity?

Page 32: Docker for Ruby Developers
Page 33: Docker for Ruby Developers

What makes dev/prod parity so hard?

Page 34: Docker for Ruby Developers

What makes dev/prod parity so hard?1 production deployment, many development/staging environments

Page 35: Docker for Ruby Developers

What makes dev/prod parity so hard?SOA simplifies each service’s responsibilities, but often at the cost of additional deployment complexity

Page 36: Docker for Ruby Developers

What makes dev/prod parity so hard?The more services you have, the harder it is to achieve dev/prod parity

Page 37: Docker for Ruby Developers

What makes dev/prod parity so hard?The more engineers you have, the harder it is to standardize dev parity

Page 38: Docker for Ruby Developers
Page 39: Docker for Ruby Developers
Page 40: Docker for Ruby Developers
Page 41: Docker for Ruby Developers

README != Automation

Page 42: Docker for Ruby Developers

Dev/prod parity via Docker

Page 43: Docker for Ruby Developers

Dev/prod parity via DockerDefine services in terms of Docker images

Page 44: Docker for Ruby Developers

# docker-compose.yml for Aptible Auth/API

auth: build: auth.aptible.com/ ports: "4000:4000" links: - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_auth_development

api: build: api.aptible.com/ ports: "4001:4001" links: - redis - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_api_development REDIS_URL: redis://redis APTIBLE_AUTH_ROOT_URL: http://docker:4000

redis: image: quay.io/aptible/redis:latest ports: "6379:6379"

postgresql: image: quay.io/aptible/postgresql:aptible-seeds ports: "5432:5432"

Page 45: Docker for Ruby Developers

# docker-compose.yml for Aptible Auth/API

auth: build: auth.aptible.com/ ports: "4000:4000" links: - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_auth_development

api: build: api.aptible.com/ ports: "4001:4001" links: - redis - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_api_development REDIS_URL: redis://redis APTIBLE_AUTH_ROOT_URL: http://docker:4000

redis: image: quay.io/aptible/redis:latest ports: "6379:6379"

postgresql: image: quay.io/aptible/postgresql:aptible-seeds ports: "5432:5432"

Page 46: Docker for Ruby Developers

# docker-compose.yml for Aptible Auth/API

auth: build: auth.aptible.com/ ports: "4000:4000" links: - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_auth_development

api: build: api.aptible.com/ ports: "4001:4001" links: - redis - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_api_development REDIS_URL: redis://redis APTIBLE_AUTH_ROOT_URL: http://docker:4000

redis: image: quay.io/aptible/redis:latest ports: "6379:6379"

postgresql: image: quay.io/aptible/postgresql:aptible-seeds ports: "5432:5432"

Page 47: Docker for Ruby Developers

# docker-compose.yml for Aptible Auth/API

auth: build: auth.aptible.com/ ports: "4000:4000" links: - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_auth_development

api: build: api.aptible.com/ ports: "4001:4001" links: - redis - postgresql environment: RAILS_ENV: development DATABASE_URL: postgresql://postgresql/aptible_api_development REDIS_URL: redis://redis APTIBLE_AUTH_ROOT_URL: http://docker:4000

redis: image: quay.io/aptible/redis:latest ports: "6379:6379"

postgresql: image: quay.io/aptible/postgresql:aptible-seeds ports: "5432:5432"

Page 48: Docker for Ruby Developers

Dev/prod parity via DockerUse the same service/image configuration in production as in development (Docker Compose, Swarm, Kubernetes…)

Page 49: Docker for Ruby Developers

Containerized SSLInfrastructure management made easy

Page 50: Docker for Ruby Developers

Elastic Load Balancer (ELB)

EC2 Instance EC2 Instance

NGiNX NGiNX

Page 51: Docker for Ruby Developers

TCP/HTTPSTCP/HTTPS

HTTP HTTP

Page 52: Docker for Ruby Developers

How to configure NGiNX with multiple dynamic upstreams?Chef? Salt? Ansible?

Page 53: Docker for Ruby Developers

ENV configuration$UPSTREAM_SERVERS

Page 54: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ -e UPSTREAM_SERVERS=docker:4000,docker:4001 \ quay.io/aptible/nginx:latest

Page 55: Docker for Ruby Developers

docker run -d -p 80:80 -p 443:443 \ -e UPSTREAM_SERVERS=docker:4000,docker:4001 \ quay.io/aptible/nginx:latest

Page 56: Docker for Ruby Developers

ENV configurationMakes testing easier

Page 57: Docker for Ruby Developers

https://github.com/sstephenson/bats

Page 58: Docker for Ruby Developers

# Dockerfile

# Install and configure NGiNX... # ...

ADD test /tmp/test RUN bats /tmp/test

https://github.com/aptible/docker-nginx Image: quay.io/aptible/nginx

Page 59: Docker for Ruby Developers

#!/usr/bin/env bats # /tmp/test/nginx.bats

@test "It should accept a list of UPSTREAM_SERVERS" { simulate_upstream UPSTREAM_SERVERS=localhost:4000 wait_for_nginx run curl localhost 2>/dev/null [[ "$output" =~ "Hello World!" ]] }

Page 60: Docker for Ruby Developers

#!/usr/bin/env bats # /tmp/test/nginx.bats

@test "It should accept a list of UPSTREAM_SERVERS" { simulate_upstream UPSTREAM_SERVERS=localhost:4000 wait_for_nginx run curl localhost 2>/dev/null [[ "$output" =~ "Hello World!" ]] }

Page 61: Docker for Ruby Developers

@test "It should accept a list of UPSTREAM_SERVERS" { simulate_upstream UPSTREAM_SERVERS=localhost:4000 wait_for_nginx run curl localhost 2>/dev/null [[ "$output" =~ "Hello World!" ]] }

simulate_upstream() { nc -l -p 4000 127.0.0.1 < upstream-response.txt }

Page 62: Docker for Ruby Developers

ENV configurationAbstracts implementation details: could be NGiNX, HAProxy, …

Page 63: Docker for Ruby Developers

ENV configurationSimplifies configuration management: central store doesn’t need to know parameters in advance

Page 64: Docker for Ruby Developers

ENV configuration$UPSTREAM_SERVERS $FORCE_SSL $DISABLE_WEAK_CIPHER_SUITES (…)

Page 65: Docker for Ruby Developers

Vulnerability ResponseFix, test, docker push, restart

Page 66: Docker for Ruby Developers

Heartbleed

Page 67: Docker for Ruby Developers

Heartbleed

POODLEbleed

Page 68: Docker for Ruby Developers

Heartbleed

POODLEbleed

xBleed???

Page 69: Docker for Ruby Developers

Integration TestsDocument and test every vulnerability response

Page 70: Docker for Ruby Developers

#!/usr/bin/env bats # /tmp/test/nginx.bats

@test "It should pass an external Heartbleed test" { install_heartbleed wait_for_nginx Heartbleed localhost:443 uninstall_heartbleed }

Page 71: Docker for Ruby Developers

@test "It should pass an external Heartbleed test" { install_heartbleed wait_for_nginx Heartbleed localhost:443 uninstall_heartbleed }

install_heartbleed() { export GOPATH=/tmp/gocode export PATH=${PATH}:/usr/local/go/bin:${GOPATH}/bin go get github.com/FiloSottile/Heartbleed go install github.com/FiloSottile/Heartbleed }

Page 72: Docker for Ruby Developers

Integration tests happen during each image build

Page 73: Docker for Ruby Developers

Integration tests happen during each image buildImages are built automatically via Quay Build Triggers

Page 74: Docker for Ruby Developers
Page 75: Docker for Ruby Developers

Integration tests happen during each image buildBuild status is easy to verify at a glance

Page 76: Docker for Ruby Developers
Page 77: Docker for Ruby Developers

Integration tests happen during each image buildQuay Time Machine lets us roll back an image to any previous state

Page 78: Docker for Ruby Developers
Page 79: Docker for Ruby Developers

Database DeploymentStandardizing an "API" across databases

Page 80: Docker for Ruby Developers
Page 81: Docker for Ruby Developers

New databases mean new dependencies

Page 82: Docker for Ruby Developers

New databases mean new dependenciesHow to document setup steps for engineers?

Page 83: Docker for Ruby Developers

New databases mean new dependenciesHow to deploy in production?

Page 84: Docker for Ruby Developers

New databases mean new dependenciesHow to perform common admin tasks? Backups? Replication? CLI access? Read-only mode?

Page 85: Docker for Ruby Developers

Wrap Databases in a Uniform APIStandardizing an "API" across databases

Page 86: Docker for Ruby Developers

#!/bin/bash # run-database.sh

command="/usr/lib/postgresql/$PG_VERSION/bin/postgres -D "$DATA_DIRECTORY" -c config_file=/etc/postgresql/$PG_VERSION/main/postgresql.conf"

if [[ "$1" == "--initialize" ]]; then chown -R postgres:postgres "$DATA_DIRECTORY"

su postgres <<COMMANDS /usr/lib/postgresql/$PG_VERSION/bin/initdb -D "$DATA_DIRECTORY" /etc/init.d/postgresql start psql --command "CREATE USER ${USERNAME:-aptible} WITH SUPERUSER PASSWORD '$PASSPHRASE'" psql --command "CREATE DATABASE ${DATABASE:-db}" /etc/init.d/postgresql stop COMMANDS

elif [[ "$1" == "--client" ]]; then [ -z "$2" ] && echo "docker run -it aptible/postgresql --client postgresql://..." && exit psql "$2"

elif [[ "$1" == "--dump" ]]; then [ -z "$2" ] && echo "docker run aptible/postgresql --dump postgresql://... > dump.psql" && exit pg_dump "$2"

elif [[ "$1" == "--restore" ]]; then [ -z "$2" ] && echo "docker run -i aptible/postgresql --restore postgresql://... < dump.psql" && exit psql "$2"

Page 87: Docker for Ruby Developers

#!/bin/bash # run-database.sh

command="/usr/lib/postgresql/$PG_VERSION/bin/postgres -D "$DATA_DIRECTORY" -c config_file=/etc/postgresql/$PG_VERSION/main/postgresql.conf"

if [[ "$1" == "--initialize" ]]; then chown -R postgres:postgres "$DATA_DIRECTORY"

su postgres <<COMMANDS /usr/lib/postgresql/$PG_VERSION/bin/initdb -D "$DATA_DIRECTORY" /etc/init.d/postgresql start psql --command "CREATE USER ${USERNAME:-aptible} WITH SUPERUSER PASSWORD '$PASSPHRASE'" psql --command "CREATE DATABASE ${DATABASE:-db}" /etc/init.d/postgresql stop COMMANDS

elif [[ "$1" == "--client" ]]; then [ -z "$2" ] && echo "docker run -it aptible/postgresql --client postgresql://..." && exit psql "$2"

elif [[ "$1" == "--dump" ]]; then [ -z "$2" ] && echo "docker run aptible/postgresql --dump postgresql://... > dump.psql" && exit pg_dump "$2"

elif [[ "$1" == "--restore" ]]; then [ -z "$2" ] && echo "docker run -i aptible/postgresql --restore postgresql://... < dump.psql" && exit psql "$2"

Page 88: Docker for Ruby Developers

--initialize: Initialize data directory --client: Start a CLI client --dump: Dump database to STDOUT --restore: Restore from dump --readonly: Start database in RO mode

Page 89: Docker for Ruby Developers

db-launch () { container=$(head -c 32 /dev/urandom | md5); passphrase=${PASSPHRASE:-foobar}; image="${@: -1}"; docker create --name $container $image docker run --volumes-from $container \ -e USERNAME=aptible -e PASSPHRASE=$passphrase \ -e DB=db $image --initialize docker run --volumes-from $container $@ }

http://bit.ly/aptible-dblaunch

Page 90: Docker for Ruby Developers

docker create --name $container $image

http://bit.ly/aptible-dblaunch

1. Create "volume container"

Page 91: Docker for Ruby Developers

docker run --volumes-from $container \ -e USERNAME=aptible -e PASSPHRASE=$passphrase \ -e DB=db $image --initialize

http://bit.ly/aptible-dblaunch

2. Initialize database data volume

Page 92: Docker for Ruby Developers

docker run --volumes-from $container $@

http://bit.ly/aptible-dblaunch

3. Run database

Page 93: Docker for Ruby Developers
Page 94: Docker for Ruby Developers

Thank you

Page 95: Docker for Ruby Developers

@fancyremarker [email protected]

https://speakerdeck.com/fancyremarker