“Move to cloud” là cụm từ được nhắc tới khá nhiều hiện nay. Hiện tại và tương lai các ứng dụng chúng ta dùng sẽ dưới dạng SaaS - Dạng mà chúng ta chả cần quan tâm nó nằm ở đâu, ta chỉ cần có một thiết bị có kết nối mạng và xài thôi (dĩ nhiên vẫn sẽ phải trả tiên bằng cách này hay cách kia vì không có bữa ăn nào miễn phí cả :d). Người cung cấp dịch vụ software thay bằng việc quen với cách làm truyền thống sẽ phải tìm cách đưa app của mình lên cloud. Câu hỏi đặt ra là muốn đưa app lên cloud thì cần chú ý gì khi build app để nó adopt với môi trường cloud. Một nhóm “học giả” cùng quê của cụ Tokuda nổi tiếng đề xuất 12 factors - một dạng “Design Patterns” cho SaaS app. Cá nhân tôi thấy cũng khá hợp lý. Đề xuất của họ có thể đúng, có thể sai nhưng cũng đáng để anh em tham khảo nếu mà bạn còn lạc lối, chưa biết làm thế nào.

I. Codebase

One codebase tracked in revision control, many deploys

Đại ý của nội dung này là source code của app cần phải được quản lý bằng các source control system. Mối quan hệ app - code base chỉ là môí qua hệ một - một.

Với nhiều môi trường run cùng 1 app chỉ nên sử dụng duy nhất 1 code base (repo). Các app chỉ coi là các instance của của một code base. Khi deploy thể hiện có thể giống/khác nhau được điều chỉnh dựa vào các tham số (vd branch).

Nguyên lý này hướng tới sự thống nhất trong quản lý mã nguồn. Hạn chế tối đa thời gian vô ích xử lý các vấn đề trong quản lý mã nguồn, thời gian đó tập trung vào việc phát triển/ tích hợp mã nguồn để release được sản phẩm nhanh và chất lượng.

II. Dependencies

Explicitly declare and isolate dependencies

Theo nguyên lý thứ 2.

  • Các dependencies (Ví dụ: lib) trong source code cần được khai báo tường minh - Dùng gì ghì ghi hẳn ra một file, kèm version. Áp dụng nguyên lý này một cách đơn giản là sử dụng các dependency management. Ví dụ: ruby có thể dùng Gem (file khai báo lib là Gemfile), php có thể dùng composer (file khai báo lib là composer.json).

  • Ngoài ra các dependencies cần phải tách biệt (isolate) ở mức tối đa. Dependencies không nên tạo thành “ring” khiến không thể kiểm soát. 

Mục tiêu của nguyên lý này là làm app portable, rút ngắn thời gian deploy nhanh nhất có thể.

III. Config

Store config in the environment

Một app thông thường có nhiều loại config và giá trị config khác nhau ở các môi trường khác nhau (dev, staging, production). Các loại config thường thấy.

  • Resource handle: Database, memcached, redis, …
  • Credential tới dịch vụ bên thứ 3 như Amazone S3, Twitter, token fb, …
  • Các cấu hình, secret môi trường deploy

Theo đề xuất của nguyên lý này các loại config cần sperate với source code. Có thể lựa chọn sử dụng eviroment variable để lưu config. Nếu có thể nên sử dụng các server centralize lưu trữ config cũng như các secret info (password, token, …).

Mục tiêu của đề xuất này là giảm thiểu tối đa việc phải thay đổi config khi deploy code. Dễ dàng scale app. Tránh “accident” liên quan tới lỗi config mỗi lần deploy code. Vì trong môi trường SaaS việc tích hợp, deploy sẽ là việc thường xuyên. Để đảm bảo bug sẽ được fix sớm nhất, các feature mới nhất liên tục được đưa tới người dùng.

PS: Ai đã từng làm sysadmin chắc chắn không dưới 1 lần gặp lỗi khi release trên product nguyên nhân là do lỗi trong việc thay thế/bổ sung cấu hình sẽ hiểu hơn ý nghĩa của nguyên lý này.

IV. Backing services

Treat backing services as attached resources

Trước hết cần hiểu backing services là các service access qua network cụ thể là các dạng như CSDL, Message queue, các loại service sử dụng ngoài như SMTP service, các loại API-access (Tweeter, google map), Storage như S3, … Attached resource là các resource nằm ngay tại local.

Nguyên lý này đưa ra đề xuất app phải thiết kế sao cho không có sự khác biệt khi app đang sử dụng attached resource chuyển qua xài backing service (xài service qua mạng). Nghĩa là chỉ cần thay đổi cấu hình thì đang dùng attached resource có thể chuyển qua dùng backing service mà không cần thay đổi gì trong code app . Ví dụ tôi đang dùng db mysql local có thể chuyên qua dùng Amazone RDS, đang dùng SMTP serivice local có thể chuyển qua xài SMTP service của Amazone/zoho, đang dùng S3 trên Ceph local có thể chuyển qua sài S3 trên Amazone Webservice một cách dễ dàng.

Nếu làm tốt các yêu cầu này app vừa có tính khả chuyển thích ứng với nhiều môi trường lại có khả năng scale dựa vào việc phân tải xử lý tại các môi trường chuyên biệt khác nhau.

V. Build, release, run

Strictly separate build and run stages

Codebase được deploy (non - development) trải qua qua 3 pha:

  • Build: Chuyển từ mã nguồn thành dạng có khả năng thực thi
  • Release: Sử dụng kết quả của Build kết hợp với config
  • Run: Chạy ứng dụng trong môi trường thực thi tại một Release cụ thể

Nguyên lý này yêu cầu phải tách biệt nghiêm ngặt giữa 3 pha build, release và run. 3 pha này phải thực hiện theo đúng thứ tự. Ví dụ không được thay đổi code ở Runtime (pha run) vì nếu thay đổi tại đó sẽ không có cách nào apply sự thay đổi đó trở lại code và build.

Các công cụ deploy phải có khả năng quản lý phiên bản của release và có khả năng rollback trở lại phiên bản cũ khi lỗi xảy ra. Release phải được đánh phiên bản unique (release ID). Có thể xem xét đánh theo thời gian release (Ví dụ: 2011-04-06-20:32:17) hoặc số verion (Ví dụ: v100).

VI. Processes

Execute the app as one or more stateless processes

Khái niệm stateless mô tả khi process xử lý một nhiệm vụ, xử lý xong thì nó trả lại kết quả luôn và kết thúc một chu trình. Không nhớ trạng thái của các process trước, sau, xung quanh nó.

Một app thông thường gồm nhiều hoặc một process. Theo nguyên lý thứ 6 này các process nên stateless và không nên chia sẻ gì với nhau (càng stateless càng tốt). Trường hợp phải sử các giữ liệu persist (lưu trữ bền vững) cần được lưu ở các statefull backing service, các database chuyên biệt (không nên lưu local).

Ví dụ cơ bản là một vài hệ thống web sử dụng “sticky session” dùng để cache user session trong memory hoặc file để các process khác của app trong tương lai nếu của cùng một user sẽ được đọc vùng nhớ/file chia sẻ chung này để route đến cùng một url cho phép. Điều này là vi phạm với nguyên tắc thứ 6 này vì các process đã phụ thuộc lẫn nhau ở mức local. Cách làm được đề xuất là sticky session cần được lưu trữ ở một backing service chuyên biệt như Redis, memcache kèm expire time.

VII. Port binding

Export services via port binding

Nguyên lý thứ 7 này quy ước các service cần được thiết kế theo hướng hoàn toàn độc lập và không phụ thuộc vào môi trường chạy bằng việc tạo ra các web-facing (các port) để cho các app khác giao tiếp với nó. Cụ thể với web app thì cần phải export HTTP port và lắng nghe các request đến từ port này.

Chú ý: Nguyên lý này chỉ áp dụng cho các web app sử dụng port-binding là backing service cho các app khác. Không áp dụng cho các dạng worker.

VIII. Concurrency

Scale out via the process model

Tham khảo: https://12factor.net