Phát triển ứng dụng thuần mây với nền tảng Dapr

Dapr là gì?
Việc xây dựng hệ thống ứng dụng phân tán ngày nay được xem là một trong những vấn đề rất phức tạp, nhất là với các dự án vừa và lớn. Trong quá trình vận hành, ứng dụng sẽ được bỏ vào Docker container để đóng gói, chạy và cũng cần các hệ thống để vận hành theo hướng cloud-native. Một trong những nền tảng hỗ trợ tốt vấn đề này là Kubernetes trên nền tảng Dapr.

nền tảng dapr
Dapr hỗ trợ đắc lực trong việc đơn giản hóa quy trình làm việc với các dự án

Tại sao lại cần đến nền tảng Dapr?

Dapr là viết tắt của Distributed Application Runtime. Thông qua buổi nói chuyện hôm nay, mỗi khái niệm sẽ được làm sáng tỏ và giải thích cặn kẽ các vấn đề liên quan đến hệ thống phân tán, các vấn đề của nó và cách Dapr giúp đơn giản hóa các vấn đề khó khăn này.

Distributed

Như đã biết, các ứng dụng ngày nay đều mang tính Resiliency và Scalability. Đây là những vấn đề rất khó vậy mình phải làm như thế nào để giải quyết vấn đề này? Việc scale một ứng dụng ổn định, phân tán và scale-out các ứng dụng khi vận hành là một quá trình rất phức tạp.

Khi phát triển ứng dụng, nhất là với các ứng dụng phân tán, hệ thống sẽ kết hợp rất nhiều các bộ phận với nhau (văn hóa DevOps), các Developer, IT và DevOps phải phối hợp làm việc với nhau để phân phối được ứng dụng một cách thành công. Và khi phát triển ứng dụng mới như hiện giờ với Docker và Kubernetes thì các yêu cầu này càng khó và đòi hỏi cao sự chính xác hơn.

  Dịch vụ Thị trường Điện toán đám mây và lưu trữ web Landscape 2020
  Chuyện mấy con Consumer

Nếu lúc trước có Docker đã khá khó thì giờ có Kubernetes còn khó và đa dạng hơn nên nó đòi hỏi phải có nhiều kiến thức ở các lĩnh vực như IT, networking, lập trình ứng dụng (kết hợp lại). Service Mesh còn gây bối rối hơn nữa vì một ứng dụng vừa có Kubernetes vừa có Service Mesh thì tính phức tạp sẽ còn tăng cao hơn nhiều.

Khi thiết kế ứng dụng chúng ta còn phải nghĩ đến việc chia các subnet cho network của ứng dụng như thế nào? Những câu hỏi đặt ra cần giải quyết là chúng ta phải chia subnet, vnet cho từng môi trường như thế nào, để làm sao hệ thống có thể chạy được trên nhiều nền tảng khác nhau và phân hoạch để đảm bảo tính bảo mật cho toàn hệ thống?

Application

Hiện nay khi xây dựng hệ thống doanh nghiệp, mọi người đều nghĩ về việc làm sao để một hệ thống “nói chuyện” với một hệ thống khác thông qua cơ chế event. Rồi đến việc phải sử dụng Actor-Model như thế nào, vì xây dựng ứng dụng doanh nghiệp thì một ứng dụng cần có và lưu trữ trạng thái (như thiết kế một hệ thống về payment chẳng hạn, theo dõi các đơn hàng đã checkout…), phải nghĩ đến các long running task để chạy tự động khi không có tương tác trực tiếp từ người dùng chẳng hạn. Và để tiết kiệm chi phí thì serverless cũng đang được nhiều doanh nghiệp cân nhắc.

Tất cả mọi vấn đề vừa đặt ra ngăn cản rất nhiều mô hình phát triển enterprise application vì chưa được hệ thống hóa một cách triệt để. Một điểm khác nữa là dù chúng ta làm việc trên hệ thống mới thì cũng không nên bỏ quên hệ thống cũ, vì việc làm sao đưa một hệ thống cũ (vẫn đang chạy tốt và tạo ra doanh thu cho doanh nghiệp) vào hệ thống mới cũng là yếu tố vô cùng quan trọng và mang tính sống còn.

Trong buổi nói chuyện này, Phương và Thắng cũng muốn khai thác và chia sẻ thêm các kinh nghiệm thực tế khi làm các dự án ở Nashtech để người đọc dễ dàng hiểu rõ hơn. Đó là khi tích hợp hệ thống cũ vào hệ thống mới sẽ rất khó, đòi hỏi nhiều kinh nghiệm trên nền yêu cầu chức năng và kiến thức của hệ thống cũ để hoàn thiện quy trình tích hợp. Vì những công nghệ hiện giờ chưa được build-in sẵn để hỗ trợ việc intercommunication, state management, pub/sub, event bindings,… Và sau khi xây dựng và tích hợp hệ thống xong, điều quan trọng là phải vận hành được nó. Bên cạnh đó, bảo mật cũng là một vấn đề quan trọng. Khi làm việc với các hệ thống của châu Âu thì có thêm loại bảo mật rất nổi trội chính là GDPR.

Xem thêm 20 trường hợp sử dụng lệnh Docker cho developer

Runtime

Đa phần khi làm việc với các ứng dụng ngày nay, các developer sẽ nghĩ đến việc tìm một package để sử dụng cho ngôn ngữ đang làm việc, chẳng hạn như 1 node package để gửi email chẳng hạn. Sau đó cài vào ứng dụng của mình để viết code và cấu hình thêm những yếu tố cần thiết khác để tạo nên một chức năng có thể chạy được.

Vấn đề lúc này là một ứng dụng thực tế sẽ không chỉ xài một thư viện mà sẽ cần rất nhiều thư viện và cũng có rất nhiều providers trên thị trường, ví dụ như SendGrid, local mail server… Và thực tế ta phải rẽ nhánh trong code ứng dụng để thỏa mãn việc sử dụng nhiều loại provider cho nhiều môi trường triển khai. Trong khi lẽ ra mình nên tập trung vào việc giải quyết vấn đề của business thì bây giờ, nếu sản phẩm bị bug sẽ phải giải quyết thêm vấn đề của các thư viện kết nối với các dịch vụ từ xa. Trong phát triển phần mềm gọi là vấn đề vendor-locking.

Một vấn đề khác nữa là quản lý versioning, đôi khi chúng ta muốn upgrade version nhưng lại bị ảnh hưởng lên các thư viện khiến việc upgrade trở nên khó khăn hơn. Lại nói tiếp về Portability trong việc xây dựng ứng dụng, hiện nay có 2 vấn đề cần phải giải quyết:

Khi làm việc với môi trường phân tán và đám mây thì làm sao để chạy được trên local có Docker hay không có Docker và làm sao để hệ thống chạy được trên Kubernetes trên local và trên đám mây? Rõ ràng rằng việc được cái này phải chấp nhận mất cái kia là điều không tránh được. Sẽ phải thỏa mãn rất nhiều thứ phức tạp khiến các developer gặp khó khăn trong việc xây dựng ứng dụng hiện nay. Vậy giải pháp cho những vấn đề này như thế nào? Dapr sẽ giải quyết vấn đề này.

Nền tảng Dapr giúp gì trong quá trình làm việc?

Dapr là tập hợp có thể giải quyết các vấn đề khó khăn mà chúng ta vừa kể trên, cô đọng lại vào các khối nền dùng chung (building blocks) có sẵn và chỉ cần đưa vào ứng dụng rồi sử dụng nó mà thôi. Có thể hiểu building blocks như một platform ở dưới làm nền tảng để phát triển các ứng dụng phía trên theo hướng cloud-native. Khi muốn build một hệ thống có nhiều ngôn ngữ (polyglot languages) như .NET, Java, Nodejs, Go… thì độ phức tạp do việc phải bảo trì cùng lúc nhiều ngôn ngữ lập trình và các stack ngôn ngữ của nhóm phát triển dự án sẽ tăng lên. Nghĩa là trong nhóm phải có một người có thể làm nhiều ngôn ngữ hay một người có thể làm nhiều framework khác nhau (fullstack và cross-stack).

Tuy nhiên vấn đề khó khăn ở đây là, chúng ta không thể dùng ngôn ngữ đó để giải quyết vấn đề kinh doanh vì phải tập trung quá nhiều vấn đề kỹ thuật và đơn thuần chỉ là kỹ thuật. May mắn Dapr khắc phục được vấn đề đó qua các khối building-blocks, mô hình độc lập nền tảng và các stack ngôn ngữ (agnostic platform và programming languages). Khi làm việc với Dapr, chúng ta chỉ phải tập trung giải quyết code business của ứng dụng, còn những phần khác Dapr sẽ giúp chúng ta. Vậy nên khi phát triển một ứng dụng với Dapr thì việc có thể tận dụng nhiều ngôn ngữ khác nhau, nhiều framework khác nhau là chuyện hoàn toàn có thể làm được.

Sự hỗ trợ nhiều từ cộng đồng cũng là một điểm mạnh của Dapr. Ý tưởng này được phát triển đầu tiên bởi CTO và các thành viên chủ chốt của Microsoft, sau đó trở thành open-source. Đến bây giờ thì không chỉ có Microsoft mà các cộng đồng ở những công ty khác cũng có thể đóng góp thêm nhiều ý tưởng và xây dựng cộng đồng rộng lớn không chỉ chạy trên Azure cloud mà còn các dịch vụ của Google Cloud, AWS hay Alibaba cloud. Cộng đồng này rất biết cách lắng nghe, khi có ý tưởng hay bạn có thể đệ trình lên nơi lưu trữ của Dapr trên Github hoặc cũng có thể tạo các pull-request để đóng góp ngược lại vào Dapr cho các phiên bản release tiếp theo.

nền tảng dapr
Dapr hỗ trợ đa ngôn ngữ và framework

Để mọi thứ hoạt động trơn tru hơn trên nhiều nền tảng hay nhà cung cấp đám mây khác nhau, thì Dapr phải tuân theo và yêu cầu các Developer tuân thủ các chuẩn của công nghệ phần mềm cho các phần như communication, Rest API,… Về Open APIs, Dapr xây dựng trên nền có sẵn của Kubernetes, và bản thân Kubernetes có bộ API cho riêng nó phía trên và cho phép thao tác từ bên ngoài vào thông qua các CLI hoặc Rest API để thao tác trực tiếp vào những thành phần (Dapr gọi nó là Component) hiện sẵn có trong nền tảng Dapr.

Điểm hay nhất ở đây là có thể chạy ở bất kỳ nền tảng nào (on-prem hoặc on-cloud và thậm chí trong các thiết bị IoT). Vì Dapr có thể mở rộng (extensible) và và có thể gắn thêm (plugable) nên chúng ta có thể sử dụng rất nhiều Component từ phía nhà phát triển Dapr hoặc cộng đồng phát triển. Hiện nay, 3 công ty điện toán đám mây lớn trên thế giới (AWS, Azure, Google Cloud) đều đang đóng góp cho Dapr và họ đã viết những Component mềm dẻo cho các dịch vụ đám mây của họ để có thể gắn kết vào Dapr.

Việc của các Developer là tải về, cấu hình và thay đổi các thông tin cấu hình theo các thông tin các nhân của từng người sử dụng đám mây cho các service đó là có thể sử dụng ngay lập tức.

Micro Service Building Blocks

Dapr sinh ra để giải quyết vấn đề mà hiện tại đang khiến mọi người rất đau đầu trong việc giải quyết bài toán hệ thống phân tán: Đó là với Microservice, nếu không có Kubernetes và Dapr, chúng ta phải có 1 cơ chế Service Discovery để trừu tượng hóa các địa chỉ IP và Port của các service (Dapr gọi là app); Còn với Kubernetes và Dapr thì đơn giản hơn rất nhiều, bạn chỉ cần biết tên của service (app), giống như một khi tìm một nhà nào đó thì mình chỉ cần biết được địa chỉ của nhà đó rồi đến mà thôi chứ không quan tâm đến các chi tiết bên trong ngôi nhà.

Kubernetes Service chỉ quan tâm đến traffic từ bên ngoài vào và đó là lý do nó chỉ quan tâm đến service name. Dapr thừa hưởng các đặc tính này Kubernetes.

  Kubernetes là gì? Cùng tìm hiểu cách hoạt động

1. State Management

Với Dapr, chúng ta được tiếp cận với một khái niệm gọi là state-management. Cho đến nay khi xây dựng 1 ứng dụng, chúng ta thường có 2 dạng là stateless và stateful. Chúng khá nhập nhằng khiến các Developer không phân biệt được rõ ràng. Dapr thống nhất 2 khái niệm này với nhau, việc khi nào ứng dụng có trạng thái hoặc khi nào không có trạng thái, mình sẽ đọc tài liệu và code dựa trên 1 public API thống nhất cho phần state management rồi cấu hình để nó hoạt động mà thôi. Dapr không bị vendor-locking nên nó cho phép mình thay đổi dựa trên các môi trường.

Khi chúng ta làm việc với hệ thống phân tán, nếu muốn 1 hệ thống có high throughput và low latency thì nên cân nhắc sử dụng các cơ chế event-based. Dapr có các building-blocks sẵn có cho việc giúp chúng ta dễ tiếp cận với các kiểu publish/subscribe, send/receive message. Các message tuân thủ chuẩn cloud-event nên có thể được consume dễ dàng trên các nền tảng đám mây khác nhau hoặc on-prem (nếu có), và vì được chuẩn hóa nên nó đa dạng cho nhiều lại message brokers và các hệ thống message khác nhau điển hình như Kafka.

2. Resource binding và trigger

Resource binding và trigger là một vấn đề khá hay. Trong hệ thống phần mềm phức tạp, ta luôn có rất nhiều thành phần cần tính theo thời gian (trigger). Lấy ví dụ, Dapr trừu tượng hóa cả việc làm sao một cái tệp tin được bỏ vào Blob Storage, và bắt các sự kiện để trigger ra ngoài để các hệ thống/function khác nhận lấy và thực thi các hoạt động mở rộng trên cơ thế tệp tin. Chẳng hạn như sẽ gửi mail cho những người liên quan khi có các thao tác cập nhật nội dung tệp tin.

Dapr giải quyết chuyện này bằng khái niệm input và output. Input là event đi tới và output là trigger các sự kiện cho các hệ thống khác xử lý tiếp theo. Hiện tại được sử dụng khá nhiều cho các cơ chế của các thiết bị IoT, việc phân tích dữ liệu nâng cao,… Và đó là là resource bindings.

3. Actors Model

Actors Model với từng ngôn ngữ lập trình sẽ có các thư viện và cách sử dụng khác nhau, chẳng hạn như Akka, Orleans, Actix,… Sẽ có rất nhiều dạng ứng dụng trong thực tế sử dụng mô hình actors, nhóm phát triển Dapr cũng nghĩ thế và trừu tượng hóa nó thành 1 cách sử dụng dễ dàng nhưng cũng vô cùng mạnh mẽ. Việc sử dụng Actors Model trên Dapr giúp việc scale ứng dụng trên mô hình phân tán đơn giản hơn.

nền tảng dapr
Micro Service Building Blocks là hệ thống của Dapr với nhiều thế mạnh

4. Security với nền tảng Dapr

Quản lý những thông tin bí mật như password của database, các secret keys cũng là thế mạnh của Dapr. Với bài toán thường, sẽ phải sử dụng những file cấu hình hoặc biến môi trường để mô tả theo từng môi trường riêng rẽ. Dapr đưa ra một chuẩn riêng với các key value, sử dụng với sản phẩm và cấu hình phù hợp. Điểm hay là tất cả các cấu hình này có thể chạy được trên các môi trường độc lập khác nhau và không cần phải kiểm thử lại.

5. Extensible

Dapr hỗ trợ mở rộng trong trường hợp mình muốn có thêm các Components và các behavior mới trong ứng dụng. Dapr hỗ trợ phát triển ứng dụng rất tốt nhưng nó lại độc lập với ứng dụng đang làm việc nên câu hỏi đặt ra là khi sử dụng với các ngôn ngữ .NET, Java, Nodejs, Python, Go, và Rust thì có cần cài đặt Dapr vào trong ứng dụng hay không?

Câu trả lời là thật sự chúng ta không cần cài đặt bất cứ Dapr nào vào ứng dụng của mình hết.

Vậy nền tảng Dapr sẽ giải quyết vấn đề như thế nào?

Sidecar và Component Architecture

Với quá trình làm việc này, service productcatalog lấy thông tin của product và service shoppingcartapp là thông tin trên giỏ hàng, bài toán cần giải quyết là khi thêm các items vào giỏ hàng, Dapr hoạt động trên mô hình này như thế nào?

Nếu làm theo cách cũ, catalogproductapp service sẽ call API của shoppingcartapp service, tuy nhiên với Dapr nó không cần call trực tiếp mà sẽ thông qua một Dapr Sidecar. Mỗi service sẽ có Dapr Sidecar đứng kế bên. Trong trường hợp này, Dapr Sidecar của productcatalogapp sẽ call đến Dapr Sidecar của shoppingcartapp để lấy dữ liệu, khi đó Dapr Sidecar của shoppingcartapp sẽ gọi vô internal API của shoppingcartapp để lấy và trả dữ liệu về cho Dapr Sidecar của productcatalogapp.

Sau đó Dapr Sidecar của productcatalogapp sẽ trả dữ liệu này vào service bên trong. Mô hình này làm việc như một dạng thông dịch và chạy độc lập không phụ thuộc các ngôn ngữ lập trình, miễn là bạn có Sidecar cho từng service.

Xem thêm Share data giữa Docker Container bằng Docker Volume

Nhờ mô hình làm việc này nên Dapr sẽ có rất nhiều thông tin về logs, metrics để chuyển về trung tâm. Đó là lý do chúng ta không cần cài đặt Dapr cho ứng dụng vì ứng dụng chỉ biết rằng Dapr đang cung cấp một chuẩn API và call chuẩn API đó mà thôi. Đây là được xem là “nét đẹp” của Dapr.

Và kể cả nếu chạy trên Kubernetes cũng không cần thay đổi mô hình hoạt động này. Vì thật ra nó chỉ là những cấu hình nên khi chúng ta muốn thay bằng các Component khác thì chỉ phải đổi Component trong thư mục Components của Dapr mà thôi, nhờ về việc tránh vendor-locking như đề cập ở trên.

Để Kubernetes hiểu được các cấu hình, thông số thì chắc chắn phải sử dụng Helm chart. Trong Dapr sẽ có các components, core components là thành phần chính để Dapr đọc, nạp và vận hành được. Đối với tất cả các ứng dụng sẽ có ít nhất 2 container, 1 container là ứng dụng application code và 1 container nữa là Dapr Sidecar. Ngoài ra, các components chính là những service bên ngoài. Chúng ta có thể dùng Dapr thông qua các file cấu hình như thế.

Bài viết được trích dẫn từ phần trình bày của anh Phương Lê và Thắng Chung tại sự kiện Vietnam Web Summit 2020 LIVE do TopDev tổ chức


Có thể bạn quan tâm:

Xem thêm các việc làm Developer hấp dẫn tại TopDev