Cũng giống trong thập niên 80 của thế kỉ trước, lập trình hướng đối tượng đã cách mạng hóa cách phát triển phần mềm, khi đó một ứng dụng được tạo bởi rất nhiều thành phần module khác nhau. Hiện nay, chúng ta cũng chứng kiến sự thay đổi tương tự cho việc tạo dựng các hệ thống phân tán, kéo theo sự phổ biến của kiến trúc micro service được tạo bởi nhiều thành phần container khác nhau.
Cũng giống như design pattern của các ngôn ngữ lập trình, tạo dựng và sắp xếp các container cho hệ thống phân tán cũng có các pattern của riêng nó. Việc áp dụng các pattern giúp ta biết phải làm gì trong các trường hợp phổ biến, tiết kiệm thời gian và công sức vắt óc suy nghĩ nên sắp xếp và vận hành các container thế nào cho đúng.

Nội dung của blog này sẽ trình bày về single node pattern đầu tiên và đơn giản nhất là sidecar pattern.

uc?id=1KuQ-3oKgcpEoJxCors_pzikN4IdRNUk4&export=download

Lưu ý:

Để hiểu bài viết này bạn phải cần có kiến thức về docker.

1. Các single node pattern.

Tiêu đề của blog là "cho hệ thống phân tán" thì tại sao ta lại bàn về các single node pattern. Lý do như sau: container là khối xây dựng cơ sở cho các container design pattern, nhưng cuối cùng thì, nhóm các container cùng nằm trên một máy (node) sẽ tạo nên thành phần nguyên tử (thành phần đơn vị) của các pattern sử dụng trong hệ thống phân tán.

2. Sidecar pattern

Định nghĩa của sidecar pattern rất đơn giản. Đây là một single node pattern được tạo bởi hai container. Cái đầu tiên là application container chứa core
logic của ứng dụng. Cái thứ hai là sidecar container. Vai trò của container thêm này là để tăng cường và củng cố chức năng cho application container, mà không phải biết chi tiết về application container.


uc?id=1WK1EEWZjyWJ96a9X3cD9lXMXh3F_2PEF&export=download


Ở dạng đơn giản nhất, sidecar container có thể được dùng để thêm chức năng cho application container mà nó khó có thể cải thiện thêm (update code chẳng hạn).

Sidecar container được cùng schedule trên cùng một máy với application container có thể qua một nhóm container nguyên tử (automic container group) như pod API object trong Kubernetes.

Ngoài cùng được schedule trên cùng một máy, application container và sidecar container chia sẻ một số lượng các resource như là filesystem, hostname, network,…

3. Một số use-case phổ biến

Sau đây là một số use-case phổ biến mà theo đó bạn có thể áp dụng luôn hoặc biển thể trong các trường hợp xác định.

3.1. Thêm HTTPS cho một legacy service

Ví dụ công ty X có một web service cũ. Nhiều năm trước khi nó được tạo, vấn đề internal network security không được chú trọng, vì thế web service này chỉ phục vụ cho các request HTTP. Theo như các mối lo ngại security gần đây, công ty X bắt đầu bắt buộc dùng HTTPS cho tất cả website trong công ty. Ngặt nỗi khổ cho team devops là source code của web service này dùng phiên bản rất cũ trong hệ thống build của công ty, và nó đã dừng phát triển từ lâu.

Container hóa web service này rất dễ nhưng thêm phần chức năng HTTPS cho nó thì phải làm sao. Team devops đang cố gắng chọn giữa tiếp tục phát triển hệ thống build cũ hoặc port source app sang hệ thống build mới. Sau đó một thành viên đề nghị một giải pháp đơn giản hơn là dùng sidecar pattern.


uc?id=1mb0TP-4kTQrm5ULI3vjm20e0KFQb99Ga&export=download


Legacy web service đó sẽ được đóng gói thành một container và được config chỉ phục vụ cho request từ localhost, nghĩa là chỉ những service khác mà được chia sẻ local network của máy server mới truy cập được web service này. Ngoài ra, team devops chỉ việc tạo thêm nginx sidecar container. Container này nằm ở cùng network với legacy web service container nên có thể access được. Như thế, chỉ cần config nginx tiếp nhận HTTPS request và redirect sang HTTP request của Legacy web service thì vấn đề sẽ được giải quyết dễ dàng. Ở đây nginx sidecar container sẽ đóng vai trò như một SSL Proxy.

Vì những unencrypted traffic (HTTP) chỉ được gởi nội bộ trong local network qua các container, do đó team devops sẽ hài lòng rằng thế này là đủ security. Tương tự như vậy, bằng cách sử dụng sidecar pattern, team devops công ty X đã hiện đại hóa một legacy application mà không phải viết thêm một dòng code nào trong source code của ứng dụng.

3.2. Config động với Sidecar

Nhiều ứng dụng thường sử dụng các file config để truyền tham số cho ứng dụng. Trên môi trường cloud-native thì rất hữu ích khi dùng API để update config cho ứng dụng. Điều này cho phép linh hoạt trong việc push thông tin config thông qua API thay vì log vào từng server và update từng file config bằng tay.

Điều này cũng khiến tự động hóa các thao tác như rollback, reconfiguring an toàn và dễ dàng hơn.


uc?id=1V3RvB5rpWAbcSih2peNaExiMzkTEpOoJ&export=download


Áp dụng sidecar như sau: tạo 2 container, một là application container và container còn lại đóng vai trò là config manager. Hai container được nhóm lại thành một pod nơi mà chúng sẽ chia sẻ một thư mục chung. Thư mục này là nơi chưa config file.

Nguyên tắc hoạt động như sau: Khi legacy application khởi động, nó load config từ config file. Khi config manager khởi động, nó sẽ kiểm tra API config và kiểm tra xem có khác nhau không. Nếu có, sẽ download file config mới và bắn một tín hiệu cho legacy application để load lại config file. Loại tín hiệu thì tùy ứng dụng (có thể là restart, hoặc kill luôn application container).

4. Thiết kế sidecar cho việc module hóa và tái sử dụng

Ngoài dùng để cải thiện legacy application mà không đụng đến source code thì còn có vài lý do khác để áp dụng sidecar pattern. Trong đó, một trong những ưu điểm chính của việc sử dụng sidecar đó là việc module hóa và tái sử dụng thành phần sidecar.

Ở ví dụ 3.1 về thêm HTTPS, nếu nginx sidecar container được parameterized tốt (tức các tham số về ip, port,… được lấy từ biến) thì nginx sidecar container sẽ là một thành phần tách rời hoàn toàn với ứng dụng cụ thể và có thể được tái sử dụng cho các ứng dụng khác.


uc?id=18aXkebKaBxntIiVKuVcI0pHEUhwkJLOy&export=download


Việc thiết kế sidecar để đạt được khả năng module hóa và tái sử dụng, giống như để đạt được khả năng module tốt trong việc phát triển phần mềm chất lượng thì cũng cần có sự tập trung và kỷ luật trong team. Cụ thể, cần phải lưu ý và tập trung vào các yếu tố sau:

  • Parameter hóa các container.
  • Định nghĩa các API surface cho các container.
  • Viết Doc cho các hoạt động của container.
4.1. Parameter hóa các container

Đây là điều quan trọng nhất cần phải lưu ý để tạo nên các container có tính module và tái sử dụng bất kể là có áp dụng sidecar hay không.
Nói một cách ngắn gọn, parameter hóa container là những thông tin mà container đó sử dụng mà không cần thiết phải fix cứng thì nên được lấy từ biến (biến môi trường,…) hoặc từ file config,…

4.2. Định nghĩa API cho mỗi container

Khi thiết kế các container có tính module, tái sử dụng, điều quan trọng là phải nhận ra rằng mọi khía cạnh của container tương tác với bên ngoài là một phần của API được định nghĩa khi thiết kế. Như trong microservice, các micro container dựa trên API để đảm bảo rằng có sự tách biệt rõ ràng giữa container ứng dụng chính và sidecar container. Ngoài ra API tồn tại để đảm bảo tất cả đối tượng sử dụng sidecar (consumer) sẽ tiếp tục hoạt động đúng khi các phiên bản sau của sidecar được release. Tương tự như vậy, có API rõ ràng cho sidecar khiến sidecar developer phát triển nhanh hơn vì chúng có định nghĩa rõ ràng, dễ bảo trì và phát triển.

4.3. Viết Doc cho các hoạt động của container

Như các library, chìa khóa để tạo thứ gì đó thật sự có ích là giải thích làm thế nào để sử dụng chúng. Buồn thay là hiện tại có rất ít tool chuẩn để viết doc cho container image, tuy nhiên có một vài best practice có thể dùng để thực hiện.

Như là viết comment cho các lệnh trong dockerfile như expose và các biến môi trường


uc?id=1MuOr1_lCaUsuUiKXDS6UjxPiYjjWMTgk&export=download
uc?id=1X_CFO23_qJ0ZoWyyWI3UQ2IBMB9iKcWr&export=download


Và các các label


uc?id=1AtlMzTkr1_hra7Bq_TTXTjqdzlpQGXKX&export=download

5. Tổng kết

Qua blog này anh em devops chúng ta đã biết được định nghĩa, cách áp dụng sidecar cho các trường hợp phổ biến và cách thiết kế triển khai container sao cho module hóa và tái sử dụng tốt. Bài viết kỳ sau sẽ là pattern thứ hai trong chương mục Single Node Pattern: Ambassadors

6. Tham khảo

Sách Designing Destributed Systems của OREILLY
Blog Container Design Patterns for Distributed Systems