اعتراف: development environment ผมไม่เปลี่ยนมาก 4 ปีทำงาน Honeybadger แต่ Honeybadger sophisticated ขึ้น ขึ้นอยู่กับ ~10 services
นั่นคือเหตุเรา moving towards Docker สำหรับ local development แทนทุก developer setup Postgres, Cassandra, Memcached ใช้ docker-compose spin up pre-made environment สะดวก
นั่นทำผม wonder: deploy Dockerized application ง่ายแค่ไหน?
Deploy ด้วย Docker
Docker มาพร้อม utilities อย่าง docker-machine และ docker-swarm ควรทำ deployment painless จนตอนนี้ยังไม่ deliver on that promise อยากอ่าน deficiencies ดู hacker news post ใหม่
นั่นคือเหตุผม focus Amazon ECS (EC2 Container Service)
ECS คืออะไร?
ECS เหมือน grown-up, production-ready mashup ของ docker-compose และ docker-swarm
กับ ECS พูดได้ว่า "Run three copies of my web app" มันจะ spin up Docker containers ที่เหมาะสมใน cluster EC2 instances
Load-balance requests across containers และ scale cluster up/down ตาม load
สร้าง Dockerized Sinatra App
Sinatra app เรียบง่าย: พิมพ์เวลาปัจจุบัน (รู้ว่ายังไม่ cached) และพิมพ์ hostname ตอนหลัง spin up multiple servers รัน app นี้ และ load balancer route requests ด้วย hostname รู้ว่า request ไหน served by server ไหน
The App
Dockerized Sinatra app ที่จะโชว์ heavily rewritten จาก tcnksm-sample/docker-sinatra
require 'sinatra'
require 'sinatra/base'
class App < Sinatra::Base
get '/' do
"Hello from sinatra! The time is #{ Time.now.to_i } on #{ `hostname` }!"
end
end
Gemfile:
# Gemfile
source 'https://rubygems.org'
gem 'sinatra'
gem 'thin'
config.ru:
$:.unshift(File.dirname(__FILE__))
require 'app'
run App
The Dockerfile
ต้องการ Dockerfile สร้าง Docker image สร้าง directory app, copy files, run web server port 80
FROM ruby:2.3.1-slim
RUN apt-get update -qq && apt-get install -y build-essential
ENV APP_ROOT /var/www/docker-sinatra
RUN mkdir -p $APP_ROOT
WORKDIR $APP_ROOT
ADD Gemfile* $APP_ROOT/
RUN bundle install
ADD . $APP_ROOT
EXPOSE 80
CMD ["bundle", "exec", "rackup", "config.ru", "-p", "80", "-s", "thin", "-o", "0.0.0.0"]
Build และ Run Image
บอก Docker build image จาก Dockerfile ใน current directory แล้ว run map container port 80 ไป localhost:4000
docker build -t docker-sinatra .
docker run -p 4000:80 docker-sinatra
เช็คว่าได้ไหม เปิด localhost:4000 ใน browser ควรเห็นแบบนี้:

Deploy ไป ECS
ใช้ setup wizard ของพวกเขา cheating? ไม่แคร์ :) ไป ECS control panel

Click "Get Started" แล้ว "Continue" หน้าถัดไป

สร้าง Docker registry
ปกติไม่ upload Docker images ไป production server จาก dev environment ส่ง images ไป Docker registry — เช่น dockerhub — server pull on deploy Amazon มี private Docker registry ไม่บังคับใช้ แต่เราใช้ตอนนี้
ตั้งชื่อ registry "docker-sinatra":

Push Image ไป Registry
ได้คำสั่ง build image และ push ไป registry ครั้งแรกลอง ad-blocker บน browser ป้องกัน commands แสดงไม่ถูกต้อง แปลกไหม

สร้าง Task Definition
AWS ชอบสร้าง terminology ใหม่สับสน "Task definition" คือ list of containers ที่ควร run together เหมือน Procfile หรือ docker-compose config
ถ้า app มี container Nginx, Unicorn, Sidekiq ทั้งสามอาจอยู่ใน "task definition" เดียวกัน
App เราง่าย มีแค่ container เดียว config น้อย
- Ensure image ถูกต้อง pull จาก registry
- Map port 80 จาก container ไป port 80 บน EC2 instance ที่รัน container

สร้าง Service
Terminology สับสนอีก! "Service" config ให้ระบุกี่ "tasks" (copies of app) ควร run และ load balanced ยังไง
ที่นี่อยาก 3 copies app run load balancing port 80

Spin up Cluster
Cluster = ชุด EC2 instances ทั่วไปรัน ECS software ของ Amazon ทำอะไรก็ได้เหมือน EC2 instances อื่น ตอนนี้ระบุ 3 t2.micro instances
หลาย confirmation steps และรอ ~5 นาที ทุกอย่างพร้อม
Service functional จะเห็นหน้าประมาณนี้:

Test App
Click load balancer name ดู details จะมี public domain name ใส่ browser จะเห็น sample app

Refresh กี่ครั้ง จะเห็น hostname เปลี่ยน เพราะ load balancer balance requests ทุก hosts
Clean up
ECS wizard สร้าง resources เยอะใน AWS account ตอนนี้ ไม่อยากทิ้งไว้ จะ clutter และอาจ cost money
โชคดี ECS wizard ใช้ CloudFormation สร้าง resources ทั้งหมด ลบได้ง่ายด้วยการ remove CloudFormation stack
