Thú nhận. Môi trường development của tôi không thay đổi nhiều trong bốn năm tôi làm việc trên Honeybadger. Nhưng trong thời gian đó Honeybadger đã trở nên sophisticated hơn nhiều, phụ thuộc vào khoảng mười services để function.
Đó là lý do chúng ta đang chuyển về Docker cho local development. Thay vì mỗi developer phải setup Postgres, Cassandra, Memcached và phần còn lại, chúng ta có thể dùng docker-compose để spin up môi trường pre-made. Nó awesome.
Tự nhiên, tôi bắt đầu tò mò việc deploy ứng dụng Dockerized dễ đến đâu.
Deploy Với Docker
Docker đi kèm utilities như docker-machine và docker-swarm mà supposed to làm deployment painless. Cho đến nay chúng chưa deliver trên promise đó. Nếu bạn muốn đọc tất cả về deficiencies của chúng, xem bài hacker news gần đây này.
Đó là lý do tôi chọn focus trên ECS (EC2 Container Service) của Amazon.
ECS là gì?
ECS giống như một phiên bản grown-up, production-ready của docker-compose và docker-swarm.
Với ECS bạn có thể nói "Chạy ba bản sao của web app của tôi" và nó sẽ intelligently spin up các Docker containers phù hợp bên trong cluster EC2 instances của bạn.
Nó có thể load-balance requests across containers của bạn, và có thể scale cluster của bạn up hoặc down tùy thuộc vào load.
Tạo ứng dụng Sinatra Dockerized
Đây là một Sinatra app đơn giản. Nó in current time, để bạn biết nếu bạn thấy cached version. Nó cũng in tên máy tính chạy app. Sau này, chúng ta sẽ spin up nhiều server chạy app này và dùng load balancer để route requests. Bằng cách trả về hostname, chúng ta có thể biết server nào served request cụ thể.
Ứng dụng
Dockerized Sinatra app tôi sắp show bạn là phiên bản heavily rewritten của 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
Đây là Gemfile:
# Gemfile
source 'https://rubygems.org'
gem 'sinatra'
gem 'thin'
...và đây là file config.ru:
$:.unshift(File.dirname(__FILE__))
require 'app'
run App
Dockerfile
Chúng ta sẽ cần Dockerfile để tạo Docker image cho app này. Nó tạo thư mục cho app, copy file qua, và chạy web server trên 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 và chạy image
Đầu tiên, chúng ta sẽ bảo Docker build image từ Docker file trong thư mục hiện tại. Sau đó chúng ta sẽ chạy nó, map port 80 của container đến localhost:4000.
docker build -t docker-sinatra .
docker run -p 4000:80 docker-sinatra
Để check nếu nó worked, mở localhost:4000 trong web browser. Bạn nên thấy gì đó như sau:

Deploy lên ECS
Bây giờ hãy deploy lên ECS. Chúng ta sẽ dùng setup wizard của họ. Đó có phải cheating? Tôi không care. :) Vậy đi đến ECS control panel.

Click "Get Started." Sau đó click "Continue" trên màn hình tiếp theo."

Tạo Docker registry của bạn
Bạn typically không upload Docker images lên production server từ development environment. Thay vào đó, bạn gửi images đến Docker registry -- như dockerhub -- và server pull chúng khi deploy. Amazon cung cấp private Docker registry. Nó không phải requirement bạn dùng nó, nhưng chúng ta sẽ dùng cho bây giờ.
Tôi sẽ đặt tên registry "docker-sinatra":

Push image lên Registry
Sau đó, tôi được đưa ra danh sách lệnh để chạy để build image và push nó lên registry.
Lần đầu tôi thử, ad-blocker của browser prevented các lệnh được hiển thị đúng. Lạ - tôi biết.

Tạo Task Definition của bạn
AWS loves tạo ra terminology mới, confusing. "Task definition" đơn giản chỉ là list của containers nên chạy cùng nhau. Nó giống như Procfile, hoặc docker-compose configuration.
Vì vậy, nếu application của bạn có một container chạy Nginx, một chạy Unicorn, và một chạy Sidekiq thì cả ba có thể contained trong "task definition" của bạn.
App của chúng ta đơn giản hơn nhiều. Chúng ta chỉ có một container. Vì vậy configuration tối giản.
- Tôi sẽ chắc chắn image đúng pull từ registry của chúng ta
- Tôi sẽ map port 80 từ container đến port 80 trên EC2 instance chạy container.

Tạo Service của bạn
Terminology confusing hơn! Cấu hình "service" cho bạn specify bao nhiêu "tasks" (a.k.a. bản sao app) nên chạy, và chúng được load balanced như thế nào.
Ở đây, tôi muốn ba bản sao app chạy, với load balancing trên port 80.

Khởi động Cluster của bạn
Cluster là một đám EC2 instances điển hình đang chạy software ECS của Amazon. Bạn có thể làm bất cứ gì với chúng bạn có thể làm với bất kỳ EC2 instance nào. Trong case này, tôi specify tôi muốn ba t2.micro instances.
Sau vài bước xác nhận và chờ khoảng 5 phút, mọi thứ ready.
Một khi service functional, bạn sẽ thấy màn hình trông gì đó như sau:

Test ứng dụng
Bạn có thể click vào load balancer name để pull up chi tiết. Ở đó, bạn nên tìm thấy public domain name của nó. Đặt đó vào browser và bạn sẽ thấy sample app của chúng ta.

Nếu bạn refresh vài lần, bạn sẽ thấy hostname thay đổi. Đó là vì load balancer đang balance requests của bạn across all three hosts.
Dọn dẹp
ECS wizard đã tạo rất nhiều resources trong AWS account của bạn vừa rồi. Bạn có thể không muốn để chúng đó. Chúng sẽ làm rối, và có thể cost bạn tiền.
May mắn thay, ECS wizard dùng CloudFormation để tạo tất cả resources của nó. Nghĩa là bạn có thể xóa mọi thứ đơn giản bằng cách remove CloudFormation stack.
