Tìm hiểu về Docker trong kiến trúc Microservice

Giới thiệu về docker container trong kiến trúc microservice

Trong bài viết trước tôi đã đề cập tới 5 yếu tố quan trọng để phát triển phần mềm theo kiến trúc microservice.  

1.  Mỗi microservice nên có một database riêng biệt

2.  Giữ source code của microservice ở mức hợp lý

3. Tạo build script (Dockerfile) cho mỗi microservice

4. Triển khai microservice bên trong các docker container

5. Stateless server

Một kiến trúc microservice tốt cần đáp ứng tốt được các yếu tố trên. Và trong các yếu tố đã được đề cập, docker container đóng một vài trò rất quan trọng.

Docker container là gì?

Trong giới hạn bài viết này tôi sẽ không tập trung vào giải thích docker là gì, mà chỉ đưa ra các định nghĩa của container nói chung và docker container nói riêng. Trên thực tế có nhiều loại docker chứ không phải chỉ có docker container. Tôi đã có cơ hội làm việc với hai loại container là docker container và linux container. Theo định nghĩa từ trang chủ của docker thì một container là "A standardized unit of software", tạm dịch là "một đơn vị phần mềm được tiêu chuẩn hóa".

Từ container có nghĩa là thùng đựng, thùng chứa, và container trong bài viết này cũng có ý nghĩa tương tự như vậy.

Giả sử tôi có  một xưởng sản xuất các mặt hàng tiêu dùng như bánh kẹo, thạch hoa quả, mứt tết, kem đánh răng, bàn chải đánh răng, chỉ nha khoa... Các mặt hàng này khác nhau về mục đích sử dụng, là các sản phẩm riêng biệt mà tôi mong muốn cung cấp đến người mua hàng, do vậy tôi cần đóng gói chúng vào các túi đựng hay thùng chứa riêng biệt để làm các mục đích chính sau:

1. Cung cấp lớp bảo vệ

- Bảo vệ hàng hóa khỏi các điều kiện môi trường khác nhau như ánh sáng, độ ẩm và nhiệt độ.

- Bảo vệ khỏi sự phá hoại từ các loài vi sinh vật.

- Bảo vệ hàng hóa khỏi rơi vỡ, dập nát.

2. Phòng tránh mất mát

- Việc đóng gói hàng hóa ngăn chặn sự rơi vãi, hay bị đánh cắp trong quá trình vận chuyển.

Cũng như vậy, những nhà cung cấp, phát triển phần mềm cần có các cách thức để phân phối sản phẩm từ nơi này qua nơi khác. Họ cần:

1. Cung cấp lớp bảo vệ

- Bảo vệ ứng dụng khỏi tác động của các môi trường khác nhau như hệ điều hành hay các thiết lập trên máy chạy ứng dụng đó.

- Bảo vệ khỏi sự xung đột với các ứng dụng khác chạy trên cùng một máy chủ.

2. Phòng tránh mất mát

- Giải quyết một vấn đề nhức đầu của rất nhiều lập trình viên đó là ứng dụng chỉ chạy trên máy của dev mà không chạy trên môi trường thật hay trên máy của QA, bằng cách đóng gói ứng dụng bao gồm cả mã nguồn, các thiết lập và các gói thư viện, phần mềm phụ trợ của nó theo đúng phiên bản …

Container sinh ra để đáp ứng những điều trên.


Hình. Docker container

Trong hình 1, các ứng dụng chạy trong các container khác nhau, các container này chạy trên nền docker engine.

Và chúng có các đặc tính:

Tiêu chuẩn: Docker tao ra những tiêu chuẩn cho các container để chúng có thể mang đi và chạy ở mọi nơi (portable)

Lightweight: Các container dùng chung kernel với máy chủ do vậy các ứng dụng trong mỗi container không đòi hỏi một hệ điều hành riêng, qua đó tăng hiệu quả sử dụng server, tiêu tốn ít tài nguyên phần cứng hơn nên giảm được số lượng server và giảm giá thành của việc mua license cho các server.

Secure: Docker cung cấp khả năng cô lập mạnh mẽ giữa các ứng dụng chạy bên trong và ngoài docker container, do vậy giúp các ứng dụng an toàn hơn khi chạy bên trong các container.

Sự khác biệt giữa container và máy ảo

Đôi khi bạn cần sử dụng một phần mềm mã nguồn mở cho việc phát triển sản phẩm hay nghiên cứu, và mã nguồn đó chỉ làm việc trên centos nhưng bạn lại đang sử dụng ubuntu. Lúc này bạn có thể cài một máy ảo hoặc tạo một docker với hệ điều hành centos trên máy ubuntu của bạn.

Cả hai đều phục vụ được mục đích của bạn. Chúng đều cung cấp sự cô lập và sự phân chia tài nguyên một cách hiệu quả. Vậy đâu là sự khác nhau giữa chúng? Hãy cùng xem xét trường hợp sau.

Bạn phải phát triển một ứng dụng cho windows nhưng lại đang sử dụng ubuntu, lúc này bạn có thể cài lại hệ điều hành windows cho máy của mình hoặc cài một máy ảo windows, nhưng trong trường hợp này bạn không thể chạy một container windows trên máy đang chạy ubuntu. Và lý do căn bản được thể hiện trong hình sau:

Hình. Sự khác nhau giữa container và máy ảo

Sự khác biệt lớn nhất ở đây là đối với trường hợp của máy ảo có thêm tầng Hypervisor. Tầng này cho phép ảo hóa phần cứng. Một server vật lý có thể chạy cùng lúc nhiều máy ảo, mỗi máy ảo chạy một hệ điều hành khác nhau, phiên bản hệ điều hành được cài cho các máy ảo là một phiên bản đầy đủ mà cũng có thể dùng để cài đặt cho máy vật lý thật.

Còn container chỉ ảo hóa tầng ứng dụng của hệ điều hành. Một server vật lý có thể chạy được nhiều container một lúc, các container chia sẻ chung kernel với hệ điều hành của máy chủ chạy nó. Mỗi container được chạy như một tiến trình riêng biệt của hệ điều hành trong không gian người dùng (user space), do vậy mà các container chiếm dụng ít tài nguyên hơn và nhẹ hơn  các máy ảo.

Do các container chia sẻ kernel với hệ điều hành của máy chủ nên việc chạy container windows trên server linux là điều không thể. vì kernel của linux và windows là hoàn toàn khác nhau. Nhưng cũng chính do việc chia sẻ kernel với hệ điều hành của máy chủ (không cần có riêng kernel cho mỗi container như trong trường hợp của máy ảo) này mà các docker có thời gian khởi động nhanh hơn nhiều so với các máy ảo.

Container và ứng dụng trong kiến trúc microservice

Cùng xem mô hình kiến trúc microservice sau:

Hình: Mô hình kiến trúc microservice với docker

Các container đóng vai trò quan trọng trong việc triển khai hệ thống microservice vì công nghệ của chúng có khả năng hỗ trợ những việc sau:

1. Dễ tạo, dễ hủy

Các container dễ dàng tạo, dừng , hủy, tạo lại , hay triển khai lại với ít bước thiết lập và cài đặt nhất.

2. Khởi động nhanh

Các container có thời gian khởi động cực kì nhanh, tuy nhiên thời gian khởi động của container còn phụ thuộc vào những gì mà nó chứa, Cụ thể là khi container khởi động thì có thể các service bên trong nó cũng được khởi động cùng. Nếu tạo ra một container (đúng hơn là docker image - docker image là một file, nó lưu lại toàn bộ thiết lập, môi trường, trạng thái và toàn bộ các file trong container ) quá lớn thì thời gian khởi động của container đó cũng tăng theo. Do vậy cần xóa những gói phụ trợ không cần thiết, giữ kích cỡ của docker image ở mức vừa phải.

3. Container có khả năng dừng nhanh chóng

Khả năng dừng nhanh, kết hợp với khả năng khởi động nhanh của container  giúp khả năng phục hồi của hệ thống cũng nhanh.

4. Nhẹ (Lightweight)

Nếu với máy ảo bạn cần phải có một bộ cài nặng tới hàng GB, nhưng với docker container đôi khi bạn chỉ cần một bộ cài (base image) nặng 5MB như Alpine Linux.

Các image nhẹ làm giúp giảm không gian lưu trữ, giảm thời gian và dung lượng để tải image từ một repo về nơi mà bạn cần triển khai. Điều này cực kỳ quan trọng trong môi trường development và production, nó giúp làm giảm thời gian phát triển sản phẩm cũng như làm thời gian phục hồi hệ thống nhanh hơn.

5. Portable

Tất cả những gì cần để chạy ứng dụng đều nằm trong docker container và có thể lưu lại thành docker image. Các docker image có thể được đánh phiên bản để phân biệt lưu trên docker hub (docker hub là một nơi lưu trữ docker image, giống như github là nơi lưu trữ source code). Điều này rất tiện lợi cho việc chia sẻ và triển khai ứng dụng. Khi muốn chạy một phiên bản mã nguồn mới chỉ cần tải docker image về và chạy.

6. Đồng nhất

Các container được chạy từ một docker image là hoàn toàn giống nhau, do vậy  hệ thống microservice có thể được mở rộng bằng cách khởi chạy thêm các container từ docker image.

 Docker là gì?

Docker là một nền tảng miễn phí (open platform) dành cho việc phát triển, triển khai ứng dụng, cho phép người dùng có thể phát triển và triển khai phần mềm một cách nhanh chóng mà không phải quan tâm nhiều đến hạ tầng bên dưới.

Docker cung cấp khả năng đóng gói và triển khai ứng dụng trong một môi trường cô lập được gọi là container. Với tính cô lập và bảo mật, Docker cho phép người dùng có thể triển khai nhiều container đồng thời trên một server (máy chủ) nhất định. Các container sử dụng rất ít dung lượng bộ nhớ vì chúng không cần sử dụng hypervisor, thay vào đó các container sẽ tương tác trực tiếp với nhân (kernel) của server. Người dùng có thể khởi chạy nhiều container trên một tổ hợp phần cứng nhất định so với việc sử dụng máy ảo, và thậm chí có thể chạy các Docker container trên các máy ảo.

Docker Engine là gì?

Docker engine là một phần mền dạng  “client-server” bao gồm các thành phần chính sau:

  • Một tiến trình Docker daemon (dockerd) có nhiệm vụ khởi tạo và quản lý các container, image, volume, network.
  • REST API là nơi nhận các yêu cầu từ phía Docker client và giao tiếp với Docker daemon để yêu cầu Docker daemon thực thi các yêu cầu từ phía người dùng.
  • Docker CLI có vai trò là client, cung cấp giao diện tương tác với người dùng (command line) và gửi các request tương ứng đến Docker Daemon thông qua REST API.

Docker Engine. Nguồn ảnh: Docker

Kiến trúc của Docker

Docker sử dụng kiến trúc client – server. Docker client sử dụng một REST API (thông qua UNIX socket, hoặc cổng mạng) để có thể giao tiếp với Docker daemon, tiến trình này thực hiện công việc tạo, chạy và phân phối các Docker container. Docker client và daemon có thể chạy trên cùng một hệ thống hoặc có thể kết nối Docker client với Docker daemon từ xa. Kiến trúc của Docker sẽ bao gồm:

Kiến trúc của Docker. Nguồn ảnh: Docker

Docker daemon

Daemon Docker (dockerd) lắng nghe các yêu cầu của người dùng thông qua Docker API và quản lý các đối tượng Docker như image, container, network và volume. Một daemon cũng có thể giao tiếp với các daemon khác để quản lý các Docker service.

Docker client

Docker client (docker) là cách thức mà nhiều người dùng tương tác với Docker. Khi bạn sử dụng các câu lệnh như docker run, client thông qua Docker API sẽ gửi các lệnh này đến dockerd, nơi thực hiện chúng. Docker client có thể giao tiếp với nhiều hơn một Docker daemon.

Docker registry

Docker registry sẽ là nơi lưu trữ các Docker image. Docker Hub là nơi lưu trữ Docker image công khai (public registry) mà bất kỳ ai cũng có thể sử dụng và Docker được định cấu hình mặc định để tìm image trên Docker Hub. Ngoài ra người dùng có thể cấu hình các registry riêng tư khác để lưu trữ Docker image.

Khi người dùng sử dụng câu lệnh “docker pull” hoặc “docker run”, các image chỉ định sẽ được tải về dựa trên registry đã được cấu hình trước đó. Khi người dùng sử dụng câu lệnh “docker push”, image cũng sẽ được tải lên registry mà người dùng đã cấu hình từ trước đó.

Các đối tượng khác

Khi sử dụng Docker, bạn sẽ khởi tạo và sử dụng image, container, network, volume, plugin và các đối tượng khác. Sau đây sẽ là tổng quan về các đối tượng này.

Docker image

Docker Image là template read-only (chỉ cho phép đọc) với các hướng dẫn để tạo Docker container. Image sẽ được sử dụng để đóng gói các ứng dụng và các thành phần đi kèm của ứng dụng, được lưu trữ ở server hoặc trên registry. Ví dụ bạn có thể sử dụng Dockerfile để tạo ra một Docker image sử dụng hệ điều hành Ubuntu và cài đặt Apache server với những cài đặt, cấu hình tùy chỉnh của riêng mình.

Docker container

Container là 1 “runable instance” của image. Bạn có thể khởi tạo, dừng hoặc xóa container bằng cách sử dụng Docker API hoặc CLI. Bạn có thể kết nối container đến 1 hoặc nhiều network, thư mục lưu trữ, hoặc thậm chí tạo ra 1 image mới dựa trên tình trạng hiện tại của container. Mặc định 1 container được “cách ly” với các container và server nếu người dùng không có các cài đặt gì thêm.

Docker volume

Volume được thiết kể để làm nơi lưu trữ các dữ liệu độc lập với vòng đời của container.

Docker network

Cung cấp một private network mà chỉ tồn tại giữa container và server, giúp các container có thể giao tiếp được với nhau một cách dễ dàng.

Docker service

Service cho phép bạn mở rộng các contaner thông qua nhiều Docker daemon, chúng giao tiếp với nhau thông qua swarm cluster bao gồm nhiều manager và worker. Mỗi một node của swarm là 1 Docker daemon giao tiếp với nhau bằng cách sử dụng Docker API. Theo mặc định thì service được cân bằng tải trên các node.

Khi nào sử dụng Docker?

  • Triển khai kiến trúc Microservices.
  • Khi xây dựng ứng dụng và cần scale một cách linh hoạt.
  • Khi bạn muốn không tốn khá nhiều thời gian để config máy local và server cùng một môi trường để chạy được ứng dụng. Bạn chỉ cần build 1 lần chạy ở nhiều nơi mà thôi.
  • Sản phẩm của công ty bạn cần một cách tiếp cận mới về xây dựng, triển khai lên server, thực thi ứng dụng một cách nhanh chóng dễ dàng.


Post a Comment

Mới hơn Cũ hơn