Mục tiêu
Mục tiêu của bài viết này là phát triển một ứng dụng trong môi trường gần nhất có thể với môi trường triển khai từ xa (remote deployment). Hãy làm điều này bằng Docker Machine và Compose để di chuyển ứng dụng từ phát triển cục bộ (local development) đến triển khai từ xa (remote deployment).
Docker Docker Docker
Hình ảnh minh họa
Đầu tiên chúng ta cần cài đặt Docker. Bài viết này sử dụng tất cả các thành phần Docker mới nhất tại thời điểm viết.
- Docker 1.7.0
- Docker Machine 0.3.0
- Docker Compose 1.3.0
Tôi giả định bạn đang chạy Docker trong VirtualBox cho phần còn lại của bài viết.
Ký sổ lưu bút (Guestbook) của chúng tôi
Ứng dụng chúng ta sẽ triển khai là một sổ lưu bút (guestbook) đơn giản. Nó đủ để chứng minh một ứng dụng 3-tier cơ bản. Chúng ta sẽ bắt đầu với môi trường phát triển cục bộ (dev env) nơi chúng ta sẽ phát triển một web app sử dụng các công nghệ sau:
- Nginx cho web server
- App server:
- Python cho ngôn ngữ lập trình
- Flask cho web framework
- Gunicorn cho WSGI server
- MySQL cho database
Chúng ta sẽ làm việc từ một repo trên GitHub, hãy bắt đầu bằng cách clone repo đó.
git clone https://github.com/rackerlabs/guestbook.git -b dmc guestbook
cd guestbook
Cũng khá dễ dàng để mất theo dõi Docker host bạn đang dùng. Tôi khuyên thiết lập alias này để giúp bạn dễ dàng tìm ra host bạn đang nói đến.
alias de='env | grep DOCKER_'
Bây giờ bạn chỉ cần gõ de để xem các biến môi trường Docker được thiết lập.
Đây là kết quả cuối cùng của việc di chuyển ứng dụng từ phát triển cục bộ đến triển khai từ xa.
Hình ảnh minh họa
Phát triển cục bộ (Local development)
Môi trường phát triển cục bộ (dev env) của chúng ta khá đơn giản vì chúng ta không phải thiết lập credentials (thông tin xác thực) hoặc lo lắng về bảo mật. Chúng ta sẽ thêm hậu tố "-dev" cho tất cả thứ dev env để giữ nó riêng biệt với triển khai từ xa.
Khởi tạo môi trường
Chúng ta sẽ dùng docker-machine để tạo một Docker host cho container của chúng ta. Sau đó cấu hình Docker để dùng host đó. Cuối cùng, docker-compose sẽ khởi động toàn bộ dev env của chúng ta.
docker-machine create --driver virtualbox guestbook-dev
docker-machine ip guestbook-dev # ghi nhớ Guestbook Dev IP Address
eval "$(docker-machine env guestbook-dev)"
docker-compose up
Trong khi đó chạy, hãy đọc qua docker-compose.yml để cảm nhận nó làm gì cho chúng ta. Nó được comment tốt nên nên tự giải thích. Lưu ý cách nó mở rộng docker-compose-common.yml làm cơ sở cho các thành phần chung. Bạn có thể tìm mô tả đầy đủ định dạng file Docker Compose trong tài liệu tham khảo docker-compose.yml.
Khi mọi thứ đã tải xong và chạy, chúng ta cần khởi tạo database. Chúng ta sẽ dùng một container one-off của app để chạy lệnh python tạo bảng trong database.
Mở terminal mới và chuyển đến thư mục guestbook.
eval "$(docker-machine env guestbook-dev)"
docker-compose run --rm --no-deps app python app.py create_db
Tại sao phải chạy container one-off cho việc này? Vì docker-compose tự động inject các biến môi trường chúng ta cần để kết nối database. Không cần cấu hình cho chúng ta.
Bây giờ mở trình duyệt và truy cập Guestbook Dev IP Address bạn đã ghi nhớ. Ký sổ lưu bút của chúng tôi xin mời.
Thay đổi (Make a change)
Hãy chắc chắn chúng ta có thể tiếp tục phát triển mã ứng dụng nhanh chóng. Có một vài tùy chọn cấu hình quan trọng trong docker-compose.yml cho phép chúng ta làm vậy. Đọc lại comment cho volumes và command trong service app.
Mở app/templates/index.html trong trình soạn thảo yêu thích. Thay đổi và lưu. Quay lại trình duyệt và reload. Voila!
Triển khai từ xa (Remote Deployment)
Phần này phức tạp hơn vì chúng ta phải thiết lập credentials và lo lắng về bảo mật. Nếu bạn không có tài khoản Rackspace, bạn có thể nhận credit miễn phí bằng cách đăng ký developer+. Khi tài khoản sẵn sàng, bạn cần tìm API key. Thiết lập các biến môi trường sau trong terminal.
export OS_USERNAME=your-rackspace-username
export OS_API_KEY=your-rackspace-api-key
export OS_REGION_NAME=IAD
Khởi tạo môi trường
Chúng ta sẽ dùng docker-machine để tạo Docker host cho container.
docker-machine create --driver rackspace guestbook
docker-machine ip guestbook # ghi nhớ Guestbook IP Address
Bảo mật môi trường
Miễn trừ trách nhiệm: Đây không phải cấu hình bảo mật nhất có thể. Script này chỉ nhằm mục đích an toàn hơn cấu hình mặc định. Không cam kết script này ngăn chặn server bị tấn công hoặc xe đạp bị đánh cắp. Kẻ xấu vẫn muốn hại bạn. Và chạy script này không miễn trừ bạn khỏi việc viết mã ứng dụng an toàn!
Cài đặt fail2ban để ngăn chặn brute force login attempts trên server và thiết lập firewall với ufw để chỉ cho phép các port chúng ta cần. Lưu ý không có output xuất hiện cho đến khi lệnh hoàn toàn xong nên cần kiên nhẫn.
docker-machine ssh guestbook "apt-get update"
docker-machine ssh guestbook "apt-get -y install fail2ban"
docker-machine ssh guestbook "ufw default deny"
docker-machine ssh guestbook "ufw allow ssh"
docker-machine ssh guestbook "ufw allow http"
docker-machine ssh guestbook "ufw allow 2376" # Docker
docker-machine ssh guestbook "ufw --force enable"
Tiếp tục khởi tạo môi trường
Trước khi Docker Compose xây dựng triển khai từ xa, chúng ta cần thiết lập một số biến môi trường cho database. Các biến này được dùng bởi file docker-compose-prod.yml. Chúng ta làm điều này để ngăn chặn việc commit dữ liệu nhạy cảm lên GitHub.
export MYSQL_USER=guestbook-admin
export MYSQL_PASSWORD=$(hexdump -v -e '1/1 "%.2x"' -n 32 /dev/random)
export MYSQL_ROOT_PASSWORD=$(hexdump -v -e '1/1 "%.2x"' -n 32 /dev/random)
echo "MYSQL_USER=$MYSQL_USER"
echo "MYSQL_PASSWORD=$MYSQL_PASSWORD"
echo "MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD"
Bây giờ cấu hình Docker để dùng host đó. Cuối cùng, docker-compose sẽ build và chạy container ở nền (background) nên chúng ta sẽ không thấy log màu sắc như phát triển cục bộ.
eval "$(docker-machine env guestbook)"
docker-compose --file docker-compose-prod.yml build
docker-compose --file docker-compose-prod.yml up -d
Trong khi đó chạy, hãy đọc qua docker-compose-prod.yml để cảm nhận nó làm gì. Lưu ý nó được đặt tên file mặc định docker-compose.yml nên không cần include tên file trong lệnh docker-compose. Nó được comment tốt nên tự giải thích. Nó cũng mở rộng docker-compose-common.yml làm cơ sở cho các thành phần chung.
Khi mọi thứ đã build xong và chạy, chúng ta cần khởi tạo database. Chúng ta sẽ dùng container one-off của app để chạy lệnh python tạo bảng trong database.
docker-compose --file docker-compose-prod.yml run --rm --no-deps app python app.py create_db
Bây giờ mở trình duyệt và truy cập Guestbook IP Address bạn đã ghi nhớ. Ký sổ lưu bút của chúng tôi xin mời.
Thay đổi (Make a change)
Chúng ta không muốn phát triển mã ứng dụng trong môi trường từ xa nhưng muốn triển khai thay đổi dễ dàng.
Mở app/templates/index.html trong trình soạn thảo yêu thích. Thay đổi và lưu. Quay lại trình duyệt tới Guestbook Dev IP Address và reload. Đảm bảo nó đã thay đổi như mong đợi trong môi trường phát triển cục bộ.
Bây giờ triển khai thay đổi đó đến môi trường từ xa bằng cách chạy vài lệnh quen thuộc.
docker-compose --file docker-compose-prod.yml build
docker-compose --file docker-compose-prod.yml up -d
Quay lại trình duyệt tới Guestbook IP Address và reload. Voila! Thay đổi của bạn đã xuất hiện và dữ liệu của bạn vẫn nguyên vẹn.
Tiếp theo là gì? (What's next?)
Bạn sẽ làm gì tiếp theo để đưa việc này xa hơn một bước?
Dữ liệu của bạn là phần quan trọng nhất của ứng dụng. Bạn cần chắc chắn nó an toàn. Bắt đầu với kế hoạch sao lưu (backup plan). Bạn có thể tự xây dựng giải pháp và có cron job lưu database dumps trong Cloud Files. Hoặc bạn có thể đi đường dễ dàng và dùng Cloud Backup. Cuối cùng, bạn có thể đi all-out và tạo Cloud Database sẵn sàng cao (highly available) và thay đổi docker-compose.yml để dùng nó thay thế.
Kết luận
Tôi hy vọng bạn đã học cách phát triển ứng dụng trong môi trường gần nhất có thể với môi trường triển khai từ xa. Nếu bạn gặp bất kỳ vấn đề nào, vui lòng cho chúng tôi biết trong phần bình luận bên dưới.