Deploying with
Consul + Docker
http://docker.com
http://consul.io
Hello!
I am Lucas Fontes
Services Team Lead at Uken Studios
I take screenshots
Spirit Animal: Left Shark
internets: @lxfontes
Uken Studios
Rails shop
HTML5 and Unity3d
~ 150 servers (300 peak)
- ~ 40 Databases
- ~ 70 App servers
- SOA with nsq.io
Static server list
Lock-step commands on all servers
HAProxy config via Chef
Snowflake servers. (DB operations/scheduled
tasks)
~15 clusters
Shared HAProxy cluster
Bare Metal
DBs (cpu speed / memory / ssd)
Web (cpu count / nic bonding)
Tons of unused network transfer
Monthly billing upgrades
idle hardware (redundancy)
PowerUP ~ 2013
Build - Heroku buildpacks
lxfontes/slugbuilder
Orchestration - Redis / Rails (private)
Run - Docker/lxc hosts
lxfontes/slugrunner-rb
Dynamic LB - knuckles
uken/knuckles
Amazon
happened
~4 - 10 hours provisioning time
Virtual Servers meh
Softlayer -> AWS
Switch - 4 hours cut-over
Amazon. yey.
what now?
What if auto-scaling kicks in mid-deploy?
What if instance dies mid-deploy?
Trust chef nodes will register themselves!
Static server list
Lock-step commands on all servers
HAProxy config via Chef
Snowflake servers. (DB operations/scheduled
tasks)
HAProxy + Chef
Make Sensu remove dead nodes
move on.
PowerUP
much BuildPacks
such Scaling
wow Dynamic LB (knuckles)
Poor adoption
Manual Database migrations
No love for buildpacks
No more idle hardware
Ops Requirements
- Not tied to AWS
- Containers / packs
- Either straight LXC, docker, rkt
- Dynamic Load Balancing
- ELB only for SSL termination
- Easy to troubleshoot
- Heavy logging, unique-ids everywhere
- Configuration Decoupling
- Not tied to chef/ansible/puppet
- DB location, worker count
- Deploy anything
- Not just rails
Developers requirements
Dev Requirements
- Run pre/post deploy scripts
- slack notifications
- close jira tickets
- CDN friendly
- GitHub
- 'Can haz ephemeral shell?'
- run rake tasks manually
- ‘Can haz production shell?’
- troubleshooting
- One click deploy
Out there
or… “why you should not do it yourself”
Out there
- Clusters
- deis, kubernetes, shipbuilder, coreos, mesos
- Config management
- chef, ansible
- Deploy tools
- capistrano, mina, fabric, packer
- Services
- ECS, CodeDeploy, Elastic Beanstalk
- shippable, ezautoscaling (!?)
They all work!
Not the way we want!
Workflow
BUILD
RUN
RELEASE
BUILD
How? Dockerfile on each repo
docker build and done
Store? Docker Registry
Target Image? repo + prod|staging
registry.uken.int/uken/titans_prod
Target Version? Git revision
registry.uken.int/uken/titans_prod:cc3e68a
RUN
Sealed container only
docker --rm=true
Pre release
Database Migrations / Seeds
CDN Asset upload
Post release
Ephemeral shell sessions
RELEASE
Upload image to docker registry
Notify hosts
registry.uken.int/uken/titans_prod:cc3e68a
Go download this version!
Docker pull + restart on hosts
‘’
But Lucas… really...
How hosts reload ?
Load balancing ?
This looks complicated
Distributed Quorum
Agents on all hosts / load balancers
Key Value Pairs
titans_prod/version: registry.uken.int/uken/titans_prod:cc3e68a
titans_prod/env/DB_HOST: db1.uken.int
DNS + HTTP API
kinda important
Service Registration + Health Checks
web1.node.consul => 10.28.3.1
titans_prod.service.consul => 10.28.3.1 port 5001
Consul
consul-template
Host
Detect
change
Run
Template
Pull+Run
Image
Register
Service
docker
consul
consul-template
consul-template
‘’
But Lucas…
How hosts reload ?
Load balancing ?
This looks complicated
Use Consul DNS API
I said it was important
Lookup by repo + environment
titans_prod.service.consul
srv1.node.consul port 5100
srv2.node.consul port 4200
srv3.node.consul port 9000
proxy_pass http://$target;
gist
‘’
But Lucas…
How hosts reload ?
Load balancing ?
This looks complicated
Not really
Build
Dockerfile
docker build
Run / shells
docker pull
docker run
Release
docker push
consul set kv pair
Frontend Provisioning
ec2 snapshots
Load Balancers
ec2 snapshots
Samson
by Zendesk
Tricks
Consul + DNS
Run a local cache + consul chain (unbound)
stub-zone:
name: "consul"
stub-addr: 127.0.0.1@8600
CNAME databases / caches on alt domain
Docker
Filesystem Drivers
overlay / aufs / btrfs / devicemapper
STDOUT logging
Bad for long lived containers - fixed in 1.6!
Container linking
Meh. --net=host
Need volumes during build?
docker run && docker commit
Dockerfiles: Base Image
ubuntu
uken/base
uken/ruby uken/djangouken/go
shim
Dockerfiles: Passing parameters
# Inject SSH key
ADD http://127.0.0.1:9090/ssh_key /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa
# Revision + deploy vars
ADD http://127.0.0.1:9090/env /etc/profile.d/custom_env.sh
No ‘official’ way
HTTP trick
Dockerfiles: Caching
FROM uken/ruby_20:latest
ENV RAILS_ENV design
ENV WORKERS 4
ADD ./Gemfile /app/Gemfile
ADD ./Gemfile.lock /app/Gemfile.lock
RUN cd /app && bundle install --jobs 4 --deployment
ADD ./ /app
RUN cd /app && bundle exec rake assets:precompile
Procfiles
Foreman on desktop
ddollar/foreman
Forego on servers
ddollar/forego
web: bundle exec unicorn -c config/unicorn.rb -p ${PORT:-3000} -E ${RAILS_ENV:-
development}
realtime: ./realtime/realtime_server.linux -ws $PORT
sidekiq: bundle exec sidekiq -v -c 3
cron: cron -f
LB tricks
HTTP/1.1 200 OK
...
X-U-Fe: 10.1.0.248:5003
add_header X-U-Fe $target;
proxy_pass http://$target;
LB tricks
error_page 500 = /errors/internal-server-error;
location ~ ^/errors/(?<code>[a-z-])+ {
proxy_pass http://error.uken.com:80/titans/$code;
}
Reload away.
No more redirects!
Thanks!
@lxfontes
github.com/uken/autoscaling

Sheep it