- vừa được xem lúc

Từ server truyền thống tới Docker và scaling cùng K8s

0 0 26

Người đăng: Kiên Đinh

Theo Viblo Asia

Mở đầu

Bạn đã bao giờ thắc mắc là các máy chủ web hoạt động như thế nào, có khác với lúc mình chạy ở local, cài các phần mềm database vào máy chủ ra sao?

Rồi người ta triển khai (deploy) và quản lý các hệ thống từ nhỏ đến lớn như thế nào? Tại sao các website lớn lại có thể xử lý hàng triệu tới hàng tỷ request mỗi giây trong khi cấu hình vật lý của máy tính là có hạn?

Hãy cùng mình đi qua hành trình từ webserver, tới scaling horizontal và containerization, orchestration để có một cái nhìn tổng quan về cách các hệ thống hoạt động, cũng như tự tìm câu trả lời cho bản thân nhé.

⚠️ Cảnh báo: bài viết rất dài. Vui lòng ngồi xuống, uống ly bánh, ăn miếng nước và thong thả đọc.

First thing first

Again, mình là Kiên Đinh (mà shipper vẫn hay gọi lộn thành Kiên Định 😦), một chàng developer thích viết, thích chia sẻ để có động lực học và nghiên cứu.

Hôm trước mình đã đề cập việc sử dụng docker để tạo nhanh 1 database postgres sử dụng cho việc test hiệu năng của connection pooling. Hôm nay mình sẽ giữ lời hứa viết 1 bài để cho những anh em còn chưa rõ về docker có thể có một cái nhìn tổng quan hơn.

Nếu đây là lần đầu bạn đọc bài viết của mình, thì xin giới thiệu đây là bài viết thuộc series backend nâng cao, chuỗi bài viết có hàm lượng kiến thức cao mà mình muốn chia sẻ cho mọi backend developer để có thể tiến sâu hơn về mặt technical.

Mô hình client-server

Giới thiệu

Từ lâu, khoảng những năm 80 của thế kỷ trước, một mô hình thiết kế phần mềm mang tên client-server bắt đầu xuất hiện, và nó còn phổ biến đến tận ngày nay. Không nói đâu xa, khi bạn đang lướt web để đọc bài viết này, thì trình duyệt của bạn cũng là một thành phần trong mô hình này.

Mình nhớ đâu đó năm lớp 10 hay lớp 11, trong môn tin học chúng ta đã được học về nó rồi, tuy nhiên chắc không còn ai nhớ, trả chữ cho thầy hết 💔.

Thành phần

Đúng như tên gọi, mô hình client-server có 2 thành phần:

  • Client-side: Hay còn gọi là phía khách, là một ứng dụng chạy ở máy tính của người dùng cuối (end-users). Ứng dụng này cung cấp giao diện để user tương tác, cũng có thể lưu trữ và xử lý một vài thông tin tạm thời (local-storage, cookies …). Giao tiếp với server bằng cách gửi yêu cầu, và nhận lại phản hồi.
  • Server-side: Phía máy chủ, hay ta quen gọi là server. Là phía xử lý yêu cầu từ client gửi lên, thực hiện các tác vụ logic và gửi lại phản hồi cho client. Phía server còn chứa thêm cả database, giúp lưu trữ thông tin của người dùng một cách lâu dài hơn.

Việc phân chia mô hình thành 2 phía này giúp cho việc xây dựng giao diện phía người dùng được dễ dàng hơn [1], client có thể là laptop, iphone, hoặc có thể là điện thoại android hay smart TV.

💡 Có thể bạn đã biết: Điện thoại (trừ cục gạch) và smart TV, thậm chí máy đọc sách cũng là một chiếc máy tính, vì nó có dầy đủ thành phần chính cấu tạo nên máy tính: Main Board; CPU; RAM; ROM; Ổ cứng;

Kiến trúc client-server không chỉ xuất hiện khi chúng ta duyệt web, mà trong máy tính của các bạn cũng có thể đang có vài phần mềm sử dụng nó ví dụ như:

  • X11 window system trên Linux
  • Language server, Gopls chạy trên VSCode
  • SSH, Git…

Web server

Đã đi qua định nghĩa về kiến trúc client-server rồi, hãy tiếp tục đi sâu vào web server, ta cần làm rõ nó trước khi đi tới các định nghĩa như containerization, orchestration mà mình đã đề cập.

Định nghĩa, giải ảo

Khi nhắc tới máy chủ, chúng ta thường lẫn lộn giữa server vật lý và server phần mềm, thực tế thì nói thế nào cũng đúng vì thực tế là nó như vậy 🤦.

Server có thể là:

  • Một ứng dụng có nhiệm vụ tiếp nhận requestgửi về response cho client (phần mềm server - application server).
  • Một máy tính có chạy phần mềm server.

Các phần mềm server nổi tiếng chúng ta có là: Apache, Tomcat, Nginx, IIS… Những phần mềm này hỗ trợ môi trường chạy cho các ngôn ngữ lập trình như PHP, ASP.NET, Python… Ở đây các ngôn ngữ như PHP đảm nhận nhiệm vụ xử lý logic.

Vậy có một câu hỏi: Không cần các phần mềm như IIS hay Nginx thì có thể khởi chạy 1 máy chủ hay không?

Với đa phần ngôn ngữ hiện nay, ta có thể chạy luôn mà không cần application server nhưng có thể cần thêm runtime engine, điển hình như Nodejs, .NET [2] hoặc là Go v.v. Còn với vài ngôn ngữ thông dịch như PHP thì không được (làm được nhưng cồng kềnh, không ai làm).

Điều kiện là code của chương trình phải lắng nghe 1 port nào đó (port mặc định là 80), lúc này đây chương trình đó giữ luôn vai trò application server.

Xem hình ví dụ sau để biết sự khác biệt giữa application server và server vật lý cũng như chạy trực tiếp app:

Với hình trên, máy chủ vật lý của kiendinh.space được cài PHP và phải chạy thông qua Nginx. Còn máy chủ của stackoverflow.com thì không cần, mà chạy trực tiếp process Golang. (Giống như bạn chạy yarn start -H 0.0.0.0).

Nay các server không chỉ đơn thuần là webserver nữa, mà có thể là server cho nhiều dịch vụ khác.

Một webserver hoạt động thế nào?

Chúng ta biết rằng mỗi một máy tính trên mạng internet đều có một địa chỉ IP. Do đó theo lý thuyết tất cả mọi người trên thế giới đều có thể gửi request tới router wifi nhà bạn, hay thậm chí chiếc máy tính cá nhân của bạn.

Chúng ta hãy xem IP như địa chỉ nhà riêng vậy.

Bây giờ, ta có thể đưa chiếc máy tính bình thường trở thành một server web với những bước sau:

  • Có một địa chỉ IP tĩnh (gói cước đắt hơn của nhà mạng có cung cấp). Chứ nếu không sẽ giống như việc bạn đổi địa chỉ nhà mỗi tuần 1 lần, sẽ nhiều người tìm không ra nhà bạn.
  • Tắt tường lửa cho các truy cập từ bên ngoài.
  • Export cổng của server đang lắng nghe (thường là 80 cho HTTP và 443 cho HTTPS).

Client có thể truy cập trực tiếp tới IP của máy chủ, hoặc thông qua tên miền (domain name). Để biết domain nào trỏ vào IP nào, thì client phải truy cập vào DNS (Domain Name Server) để tìm (DNS xem như danh bạ điện thoại, không cần nhớ số chỉ cần nhớ tên).

Hãy giả định như ta đang có tên miền kiendinh.space, thì trình duyệt (client) sẽ có flow từng bước như sau:

Việc deploy truyền thống

Tới đây thì ta đã rõ ràng server cũng chỉ là một chiếc máy tính như bao máy tính khác (nhưng cấu hình mạnh hơn). Thì việc deploy ứng dụng trước đây diễn ra thế nào?

Ta có thể dễ dàng đoán được, việc này cũng giống như cài các công cụ cần thiết cho việc code ở phía local vậy:

  • Setup một máy chủ vật lý hoặc VPS (máy chủ ảo), mua luôn về nhà hoặc đa phần thuê ở đâu đó.
  • Cài hệ điều hành cho máy (Windows server hoặc Linux).
  • Truy cập vào server bằng SSH hoặc RDP nếu là windows server (nếu server do mình quản lý thì mình mở ra chạy luôn như bình thường).
  • Cài đặt các phần mềm cần thiết: Git, PHP, Nginx, Java, .NET framework, Database (nếu có) v.v.
  • Cập nhật bản code / app mới nhất và chạy command.

Thực là lắm rắc rối và phiền hà. Các công ty lớn chắc là người ta sẽ tối ưu những công việc trên bằng các shellscript, nhưng vẫn rất là bất tiện.

💡 Các ngôn ngữ như PHP có thể không cần chạy thẳng trên VPS mà đa phần chỉ chạy trên hosting, sẽ đỡ phức tạp và tiết kiệm hơn nhiều. Hosting chứa phần mềm quản lý đã được cài đặt sẵn, giúp tối ưu cho việc deploy.

Bởi vì việc deploy phức tạp và tốn thời gian như vậy, mà đặc thù của môi trường development thì thay đổi liên tục, nên chúng ta cần vài một biện pháp tối ưu hơn, và thế là người ta dùng ảo hóa và containerization.

Ảo hóa và Container hóa

Docker đúng thực là một công cụ giúp ích rất nhiều trong việc thiết lập môi trường cho hệ thống. Như bài trước mình chỉ cần vài bước đơn giản đã có thể chạy postgres ở local. Lúc trước khi còn đi học, mỗi lần cài lại win là mình tốn hơn 30p tới 1 tiếng để cài MSSQL Server 🥲.

Nhưng trước khi nói tới Docker và cơ chế containerization (container hóa, dung khí hóa), thì ta nên tìm hiểu về cơ chế ảo hóa trước, để hiểu tường tận lý do nó ra đời và lợi ích containerization mang lại.

Cơ chế ảo hóa - virtualization

Nếu từng là sinh viên IT thì bạn đã cài máy ảo không chỉ 1 lần rồi đúng không? Hoặc cài bluestack để chơi game android trên PC thì cũng là một dạng máy ảo.

Xem hình mô tả cơ chế ảo hóa [3]:

Khi deploy ứng dụng web với cơ chế ảo hóa, chúng ta có vài lợi ích sau:

  • Tận dụng tối đa sức mạnh phần cứng.
  • Cô lập các ứng dụng khác nhau trên các VM khác nhau, ví dụ database chạy riêng, web app chạy riêng.
  • Chạy máy ảo vẫn sẽ nhanh hơn là cài OS thủ công và cài phần mềm ứng dụng vào đó.

Vậy điểm yếu của cơ chế này là gì?

  • Thứ nhất, tốn thời gian để khởi chạy một VM.
  • Ảo hóa tốn resource (RAM, Mem), hiệu năng app chạy trên VM không tốt như chạy trực tiếp.
  • Vì kích thước của các máy ảo lớn (hàng GB), nên việc backup và nhân bản (clone) khá bất tiện.

Tại sao cơ chế ảo hóa lại có những điểm yếu trên? Đáp án là bởi vì bản thân mỗi một VM đều phải chứa luôn 1 hệ điều hành (OS), là windows hoặc họ Linux, mà đã vậy thì số lượng công việc và tài nguyên nó chiếm dụng sẽ là một số lượng lớn.

Vì vậy, cơ chế containerization tối ưu hơn ra đời đã khắc phục được 2 nhược điểm trên.

Cơ chế containerization

Mặc dù cơ chế container hóa đã có từ lâu, nhưng phải tới lúc Docker xuất hiện thì nó mới phổ biến.

Năm 2010, 1 startup mang tên Docker Inc ra đời, và sản phẩm của họ chính là một công cụ hỗ trợ container hóa - Docker, điều đặc biệt là Docker là một phần mềm open-source, và được viết bằng Go 😎.

Và đây là hình minh họa so sánh conainerization và virtualization [4]:

Nhìn vào hình mô tả trên, ta có thể dễ dàng nhận ra kiến trúc của Docker / container đã được bớt đi 1 layer, chính là layer VM OS. Bởi vì Docker Engine sử dụng chung luôn Kernel của máy chủ vật lý. Điều này khiến cho lượng tài nguyên mà cơ chế container hóa sử dụng ít tài nguyên hơn.

Docker

Hiện nay mình không biết có bao nhiêu công cụ hỗ trợ container hóa, nhưng các công cụ mà opensource thì chỉ có 2 cái phổ biến nhất: Docker và Podman.

Ưu điểm của Docker

Bên cạnh việc sở hữu điểm mạnh của cơ chế container hóa là tiết kiệm tài nguyên hơn ảo hóa nhờ dùng chung kernel với Host OS, Docker còn có một điểm mạnh ăn tiền chính là các image có thể được sử dụng lại (vẫn nhẹ hơn các file VM ảo hóa), và chúng ta có thể dùng dockerfile để quyết định image của application chạy có những phần mềm nào.

Ví dụ, nếu bạn muốn deploy một ứng dụng web PHP trên Ubuntu, thông thường bạn sẽ phải cài Nginx hoặc Apache lên ubuntu (1), sau đó cài đặt PHP composer (2), MySQL trên máy chủ (3), chưa kể đôi lúc phải chạy vài script để chmod, cấp quyền cho user (4) vân vân mây mây… Khá tốn thời gian.

Với Docker, việc này đơn giản hơn vì bạn có thể sử dụng lại các Docker image đã cài đặt sẵn PHP, Nginx, bạn chỉ cần cài Docker (1) và config lại file dockerfile (2) để copy lại code PHP vào image và chạy thôi.

💡 Đây chỉ là một ví dụ, thực tế sẽ không nên cài chung DB cùng 1 container với web app.

Câu hỏi: Nếu sử dụng chung kernel, thì làm sao các máy tính windows có thể chạy được các image linux?

Trả lời: Với Docker ở các máy tính windows, bạn có thể chạy được cả 2 loại image Linux cũng như image Windows, lý do là bởi vì Windows các phiên bản mới có tính năng WSL. Tức là docker vẫn sử dụng kernel linux.

Ngược lại, bạn không thể chạy được image windows trên docker ở các máy chạy Linux, vì không có kernel Windows NT để share cho docker engine dùng [5].

Docker xử lý được vấn đề gì?

Docker xử lý được 2 điểm quan trọng:

  • Đảm bảo app của bạn chạy đúng như mong đợi trên các môi trường khác nhau (dev, UAT, PROD…). Bởi vì các package cài thêm, các script chạy đã được đóng gói sẵn vào image rồi.
  • Tối ưu quá trình, tiết kiệm thời gian thiết lập môi trường. Như các bạn thấy việc mình chạy một container postgresql hoặc MSSQL rất nhanh chỉ với vài thao tác, nhanh hơn nhiều việc cài bằng tay.

Thực tế cả 2 phương pháp containerization và virtualization vẫn được dùng song song hiện nay.

Cơ chế ảo hóa vẫn được dùng để bán các gói VPS cho bạn dùng (như AWS EC2), nhưng với deployment, người ta hầu hết sử dụng Docker hoặc tool containerization khác (Podman chẳng hạn).

💡 Các nhà cung cấp server thường có 2 lựa chọn cho máy chủ riêng: VPS và Dedicated server. VPS chính là máy ảo, dùng chung cùng một máy vật lý với các VPS khác, còn Dedicated server là một máy vật lý riêng biệt. Thông thường, các máy chủ vật lý được thiết lập cấu hình siêu mạnh, vậy nên người ta bán nhiều máy ảo (VM - Virtual Machine) trên cùng một server vật lý để tối ưu doanh thu.

Scaling và Kubernetes

Ở đầu bài mình có đề cập tới câu hỏi: “Tại sao các hệ thống lớn lại có thể xử lý được số lượng request lớn như vậy?”, trong khi ví dụ điển hình nhất là các server đăng ký học phần ở các trường ĐH chỉ có phục vụ mấy nghìn tới mấy chục nghìn sinh viên đã tèo rồi?

Đây là do các hệ thống lớn áp dụng scaling horizontal.

Scaling up và Scaling out

Một máy chủ vật lý thì có sức mạnh hữu hạn, khi một server chịu tải đến một mức độ nào đó người ta sẽ có 2 lựa chọn để có thể xử lý được nhiều request hơn:

  • Nâng cấp cấu hình: CPU, RAM (scaling up hoặc vertical scale)
  • Gắn thêm một server nữa, sử dụng load balancer để 2 em cùng gánh lượng request lớn hơn (scaling out hay horizontal scaling).

Nhưng với docker thì chúng ta chỉ cần tạo thêm các container khác ở một máy tính khác là xong đúng không? Vậy làm sao chúng ta quản lý chuyện đó, quy định số lượng container là bao nhiêu vân vân…?

Chúng ta cần một orchestration tool để làm việc này. Phổ biến nhất chính là Kubernetes, được viết tắt K8s. (Nếu dịch containerization là dung khí hóa, thì orchestration có thể dịch là phối khí 🤣).

Orchestration tool - Kubernetes

Hình dưới đây minh họa kiến trúc của kubernetes [6]:

K8s sẽ quản lý các worker, trong đó có các pod có thể được coi như là một server thu nhỏ. Khi một pod nào đó bị crash do lỗi, thì có thể dễ dàng điều phối request qua pod khác.

K8s cũng hỗ trợ tính năng auto-scale, tức là lượng request càng lớn, thì ta có thể tạo thêm nhiều pod để xử lý.

Trong khi docker đảm bảo vấn đề chạy đúng trên các môi trường, thì K8s có vai trò đảm bảo các ứng dụng luôn chạy (tính có sẵn - Availability). Khi mỗi "server" trong K8s không còn đơn lẻ nữa là mà 1 cụm các pod.

Để có thể chạy k8s ở local, chúng ta có thể sử dụng kind. (Kinh nghiệm của mình thì RAM dưới 32GB chạy rất đuối khoản này 😄).

Thường thì việc setup và quản lý K8s sẽ là của devops, nhưng developer thì cũng nên hiểu cách nó hoạt động để có thể design được một hệ thống hoạt động trơn tru, và tất nhiên, lên trình, tăng lương, cưới vợ, mua nhà, mua xe 😆.

⚠️ Các database trên hệ thống không nên đưa vào container mà thông thường sẽ được setup bằng tay.

Wrapping up

Chắc là bạn đã ăn xong ly nước, uống xong miếng bánh trước khi đọc hết bài này rồi. Mục đích bài này là để giới thiệu một cách tổng quan, để mọi người có cái nhìn overview hơn về backend, để không gặp phải những câu hỏi như scale up là gì? docker là gì? bla bla.

Hi vọng sẽ giúp ích được các bạn, nhớ để lại bình luận nếu bạn có thắc mắc, feel free to ask!

Bài viết gốc: Từ server truyền thống tới Docker và scaling cùng K8s

Footnotes:

  1. https://madooei.github.io/cs421_sp20_homepage/client-server-app/
  2. https://learn.microsoft.com/en-us/aspnet/web-api/overview/older-versions/self-host-a-web-api
  3. https://documentation.suse.com/smart/virtualization-cloud/html/concept-virtualization/index.html
  4. https://www.netapp.com/blog/containers-vs-vms/
  5. https://stackoverflow.com/questions/42158596/can-windows-containers-be-hosted-on-linux
  6. https://www.cncf.io/blog/2019/08/19/how-kubernetes-works/

Bình luận

Bài viết tương tự

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 397

- vừa được xem lúc

Phần 1: Giới thiệu về Kubernetes

Kubernetes là gì. Trang chủ: https://kubernetes.io/. Ai cần Kubernetes.

0 0 100

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 1- Lịch sử)

1. Vì sao nên sử dụng. . .

0 0 104

- vừa được xem lúc

Docker - những kiến thức cơ bản phần 1

Giới thiệu. Nếu bạn đang làm ở một công ty công nghệ thông tin, chắc rằng bạn đã được nghe nói về Docker.

0 0 78

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 2 - Dockerfile)

1. Mở đầu.

0 0 67

- vừa được xem lúc

Docker: Chưa biết gì đến biết dùng (Phần 3: Docker-compose)

1. Mở đầu. . .

0 0 121