Kubernetes: Giải pháp tối ưu chi phí lưu trữ hiệu quả
Trong vài năm qua, ngành công nghiệp phần mềm đã có sự chuyển dịch rõ rệt sang phát triển các ứng dụng nhỏ gọn và tập trung vào chức năng cụ thể. Ngày càng nhiều công ty đang "phá vỡ" các ứng dụng nguyên khối (monoliths) đồ sộ và tĩnh của họ thành một tập hợp các thành phần độc lập, hoạt động riêng biệt.
Xu hướng này hoàn toàn dễ hiểu bởi các dịch vụ có kích thước nhỏ gọn mang lại nhiều lợi ích:
- Triển khai nhanh chóng hơn - do được tạo và phát hành theo từng phần nhỏ.
- Dễ dàng lặp lại - vì việc thêm các tính năng diễn ra độc lập.
- Khả năng phục hồi cao - dịch vụ tổng thể vẫn có thể hoạt động bình thường ngay cả khi một trong các thành phần không khả dụng.
Rõ ràng, các dịch vụ nhỏ gọn rất phù hợp với góc độ phát triển và sản phẩm.
Vậy, sự thay đổi mang tính văn hóa này tác động như thế nào đến cơ sở hạ tầng?
Thách thức trong việc quản lý cơ sở hạ tầng ở quy mô lớn
Mọi thứ sẽ khá đơn giản khi bạn xử lý một vài ứng dụng rời rạc. Bạn có thể tự tay quản lý và có nhiều thời gian để hỗ trợ và phát hành chúng.
Trong một tổ chức lớn, việc quản lý hàng trăm ứng dụng là một yêu cầu cao, nhưng vẫn khả thi. Bởi vì, bạn có thể phân chia thành nhiều nhóm chuyên trách cho việc phát triển, đóng gói và phát hành ứng dụng.
Tuy nhiên, việc phát triển dịch vụ từ các thành phần nhỏ hơn lại đặt ra một thách thức hoàn toàn khác.
Khi bạn có thể tái cấu trúc (refactor) một ứng dụng thành một tập hợp bốn thành phần, bạn sẽ có ít nhất gấp bốn lần số ứng dụng cần phát triển, đóng gói và phát hành.
Một dịch vụ nhỏ có thể được tạo thành từ hàng tá thành phần như ứng dụng giao diện người dùng (frontend), API backend, máy chủ xác thực (authorization server), ứng dụng quản trị (admin application), v.v. Khi bạn phát triển các dịch vụ tương tác với nhau, số lượng thành phần được triển khai trên cơ sở hạ tầng của bạn sẽ tăng lên nhanh chóng.
Lãng phí tài nguyên tính toán
Hầu hết các dịch vụ được triển khai trên các máy ảo như Amazon EC2, Digital Ocean Droplets hoặc Azure Virtual Machines.
Mỗi máy ảo đều đi kèm với một hệ điều hành, tiêu tốn một phần tài nguyên bộ nhớ và CPU được cấp phát cho nó.
Khi bạn tạo một Droplet có dung lượng 1GB bộ nhớ và 1 vCPU trên Digital Ocean, bạn sẽ chỉ sử dụng được 700MB bộ nhớ và 0.8 vCPU sau khi trừ đi phần tài nguyên mà hệ điều hành sử dụng.
Nói cách khác, cứ 5 máy ảo, bạn sẽ phải trả tiền cho 5 nhưng chỉ sử dụng được 4.
Bạn không thể thoát khỏi tình trạng này, ngay cả khi bạn đang sử dụng máy chủ vật lý (bare metal). Bạn vẫn cần phải chạy các dịch vụ của mình từ một hệ điều hành cơ sở.
"Không sao cả, ai cũng cần phải chạy hệ điều hành!" - Bạn có thể nói như vậy.
Tuy nhiên, số tiền lãng phí cho hệ điều hành chỉ là phần nổi của tảng băng chìm.
Lãng phí tài nguyên do sử dụng không hiệu quả
Bạn có thể nhận ra rằng khi chia nhỏ dịch vụ thành các thành phần nhỏ hơn, mỗi thành phần sẽ có yêu cầu về tài nguyên khác nhau.
Một số thành phần như xử lý dữ liệu và khai thác dữ liệu (data mining) sẽ cần nhiều CPU. Trong khi đó, các thành phần khác như máy chủ cho các ứng dụng thời gian thực có thể sử dụng nhiều bộ nhớ hơn CPU.
Amazon Web Services và các nhà cung cấp dịch vụ đám mây khác cung cấp nhiều loại tài nguyên tính toán phù hợp với mọi nhu cầu: mục đích chung, tối ưu hóa CPU, tối ưu hóa bộ nhớ, tối ưu hóa dung lượng lưu trữ và tính toán GPU.
Bạn nên cố gắng sử dụng đúng loại máy ảo cho thành phần của mình. Lý tưởng nhất là nó phù hợp với mức tiêu thụ bộ nhớ và mức sử dụng CPU.
Bạn đang làm việc trên một thành phần web quan trọng được viết bằng Java?
Có lẽ bạn nên sử dụng c5.4xlarge được tối ưu hóa cho khối lượng công việc cần nhiều tài nguyên tính toán.
Bạn càng khớp với các yêu cầu, bạn càng sử dụng tốt tài nguyên của mình.
Tuy nhiên, trên thực tế, điều này hiếm khi xảy ra.
Bạn nên sử dụng c5.2xlarge hay c5.4xlarge?
Liệu việc nâng cấp lên gói tiếp theo (8 vCPU và 16GB bộ nhớ) có tạo ra sự khác biệt?
Sẽ dễ dàng hơn nhiều khi chọn một vài cấu hình máy tính đủ tốt trong 80% trường hợp và sử dụng chúng cho tất cả các thành phần.
Thực tế, việc sử dụng hầu hết cùng một loại máy ảo cho mọi khối lượng công việc có vấn đề gì không?
Hoàn toàn không, nếu bạn hài lòng với việc gói gọn mọi thành phần trong dung lượng tính toán 2GB bộ nhớ và 1 vCPU. Ngay cả khi thành phần của bạn có thể chạy chỉ với 1GB bộ nhớ.
Đúng vậy, bạn có thể tối ưu hóa trong tương lai.
Nhưng hãy thành thật: điều đó giống như thay lốp xe khi đang lái xe.
Bạn đã nỗ lực rất nhiều để tinh chỉnh hệ thống chỉ để nhận ra rằng ứng dụng lại thay đổi và bạn phải bắt đầu lại từ đầu.
Vì vậy, bạn kết thúc bằng cách đưa ra lựa chọn hợp lý duy nhất: chọn cấu hình nhỏ, vừa và lớn cho máy ảo và sử dụng chúng cho tất cả các khối lượng công việc.
Bạn biết rằng bạn phải chấp nhận việc lãng phí hàng trăm megabyte RAM và rất nhiều chu kỳ CPU.
Nếu điều đó khiến bạn cảm thấy an ủi hơn, thì có rất nhiều công ty đang phải chịu đựng những sự kém hiệu quả tương tự.
Một số công ty chỉ sử dụng 10% tài nguyên được phân bổ.
Bạn trả 1000 USD cho các phiên bản EC2 trên Amazon, nhưng bạn chỉ thực sự sử dụng 100 USD.
Nghe có vẻ như đó không phải là cách chi tiêu ngân sách tốt nhất.
Bạn nên được hoàn lại tiền cho các tài nguyên mà bạn không sử dụng.
Nhưng tại sao những yêu cầu đó lại khác nhau như vậy?!
Sự đa dạng của công cụ và ngôn ngữ lập trình
Khi các nhà phát triển có quyền tự do sử dụng công cụ phù hợp cho công việc, họ thường "bung lụa". Node.js cho frontend, Spring Boot cho API backend, Flask và Celery cho xử lý tác vụ nền, React.js cho phía client, vân vân.
Cơ sở hạ tầng trở thành một công viên giải trí, với hàng trăm ứng dụng chạy trên các nền tảng hoàn toàn khác nhau.
Việc sử dụng công nghệ phù hợp cho từng công việc cho phép tăng tốc độ lặp lại, nhưng thường đi kèm với gánh nặng quản lý thêm một ngôn ngữ lập trình.
Mặc dù bạn có thể hạn chế sự gia tăng của các công cụ và ngôn ngữ lập trình, nhưng trên thực tế, điều đó phức tạp hơn nhiều.
Hai ứng dụng cùng chia sẻ một thời gian chạy JVM (Java Virtual Machine) có thể dựa trên các tập hợp thư viện và phần phụ thuộc khác nhau.
Có thể một ứng dụng dựa vào ImageMagick để thay đổi kích thước hình ảnh.
Ứng dụng còn lại dựa vào một tệp nhị phân như PhantomJS hoặc ZeroMQ để có sẵn trong đường dẫn của nó.
Bạn nên đóng gói các phần phụ thuộc đó cùng với ứng dụng của mình.
Và kết quả là bạn phải xử lý hàng tá cấu hình giống nhau, nhưng khác nhau theo cách riêng của chúng.
Bạn không nên coi cơ sở hạ tầng là một điều gì đó "làm sau cũng được". Bạn nên quan tâm đến các phần phụ thuộc của mình và đóng gói chúng ngay từ đầu khi phát triển ứng dụng.
Lý tưởng nhất là bạn nên lưu trữ tất cả các phần cần thiết để chạy thành phần của mình dưới dạng một gói duy nhất.
Không còn phải loay hoay tìm kiếm các phần phụ thuộc ngay trước khi phát hành nữa.
"Dễ nói hơn làm."
Hay có thể không?
Ý tưởng từ ngành vận tải biển
Công nghệ thông tin không phải là ngành duy nhất gặp phải vấn đề này.
Việc vận chuyển hàng hóa trong các container trên toàn cầu rất khó khăn khi bạn cần lưu trữ từng mặt hàng riêng lẻ.
Hãy tưởng tượng bạn có hàng nghìn chiếc hộp với đủ hình dạng và kích cỡ cần được lưu trữ trong khoang tàu. Bạn phải đặc biệt chú ý đến cách đóng gói các mặt hàng vì bạn không muốn bỏ sót bất kỳ thứ gì khi dỡ hàng.
Ngành vận tải biển đã đưa ra một giải pháp: container.
Công ty vận tải không vận chuyển hàng hóa; họ vận chuyển container.
Bạn có muốn vận chuyển tất cả hàng hóa của mình một cách an toàn?
Hãy đặt chúng vào một container. Khi container được dỡ xuống, bạn sẽ chắc chắn nhận được đầy đủ mọi thứ.
Bạn có thể áp dụng nguyên tắc tương tự cho các ứng dụng của mình.
Bạn có muốn triển khai ứng dụng của mình và tất cả các phần phụ thuộc của nó một cách an toàn?
Hãy đóng gói chúng vào một container Linux.
Container Linux giống như một container vận chuyển, nhưng nó đóng gói tất cả các tệp, tệp nhị phân và thư viện cần thiết để chạy quy trình của bạn.
Nghe có vẻ giống máy ảo?
Máy ảo "ăn kiêng"
Thật vậy, nếu bạn "nheo mắt" và nhìn từ xa vào các máy ảo, chúng giống với các container.
Chúng đóng gói ứng dụng và các phần phụ thuộc của nó giống như các container.
Tuy nhiên, máy ảo khởi động chậm, thường có kích thước lớn hơn và - như bạn đã biết - lãng phí tài nguyên.
Trên thực tế, bạn phải phân bổ một số lượng CPU và bộ nhớ cố định để chạy ứng dụng của mình.
Chúng cũng phải mô phỏng phần cứng và đi kèm với "gánh nặng" của một hệ điều hành.
Mặt khác, container Linux chỉ đơn thuần là các quy trình chạy trên máy chủ của bạn.
Trên cùng một hệ điều hành và máy chủ, bạn có thể chạy hàng tá container trên máy chủ đó.
Và mặc dù "cùng chung sống" trên một máy tính, các quy trình chạy trong các container không thể nhìn thấy nhau.
Các ứng dụng chạy bên trong container được cách ly hoàn toàn và không thể phân biệt được giữa máy ảo và container.
Đó là một tin tuyệt vời!
Container Linux giống như máy ảo, nhưng hiệu quả hơn.
Nhưng những container Linux này được tạo ra từ đâu?
Container Linux: Quy trình biệt lập với nhiều lợi ích
Sự kỳ diệu của container đến từ hai tính năng trong nhân Linux: nhóm điều khiển (control groups) và không gian tên (namespaces).
Nhóm điều khiển là một cách thuận tiện để giới hạn CPU hoặc bộ nhớ mà một quy trình cụ thể có thể sử dụng.
Ví dụ: bạn có thể chỉ định rằng thành phần của bạn chỉ nên sử dụng 2GB bộ nhớ và một trong bốn lõi CPU của bạn.
Mặt khác, không gian tên có nhiệm vụ cô lập quy trình và giới hạn những gì nó có thể nhìn thấy.
Thành phần chỉ có thể nhìn thấy các gói tin mạng liên quan trực tiếp đến nó. Nó sẽ không thể nhìn thấy tất cả các gói tin mạng truyền qua bộ điều hợp mạng. Nhóm điều khiển và không gian tên là các thành phần nguyên thủy cấp thấp.
Theo thời gian, các nhà phát triển đã tạo ra ngày càng nhiều lớp trừu tượng để giúp kiểm soát các tính năng của nhân dễ dàng hơn.
Một trong những lớp trừu tượng đầu tiên là LXC, nhưng bước đột phá thực sự là Docker được phát hành vào năm 2013.
Docker không chỉ trừu tượng hóa các tính năng của nhân Linux mà còn rất dễ sử dụng.
Việc chạy một Docker container rất đơn giản:
docker run <my-container>
Và vì tất cả các container đều triển khai một giao diện chuẩn, bạn có thể chạy bất kỳ container nào khác với cùng một lệnh:
docker run mysql
Và bạn có một cơ sở dữ liệu MySQL.
Tính khả chuyển của ứng dụng và giao diện chuẩn để tạo và chạy các quy trình là những gì khiến container trở nên phổ biến.
Container thật tuyệt vời!
- Bạn đã tiết kiệm tiền bằng cách không phải chạy hàng tá hệ điều hành.
- Bạn đã đóng gói các ứng dụng thành các đơn vị di động.
- Bạn có rất nhiều container.
Nghe có vẻ như container vẫn chưa giải quyết được tất cả các vấn đề.
Bạn cần một cách để quản lý các container.
Quản lý container ở quy mô lớn
Khi bạn có hàng trăm, thậm chí hàng nghìn container, bạn nên tìm cách để chạy nhiều container trên cùng một máy chủ. Và bạn cũng nên lên kế hoạch để các container được trải rộng trên nhiều máy chủ.
Nhờ đó, bạn có thể phân phối tải trên nhiều nút và ngăn chặn việc một lỗi đơn lẻ có thể làm sập toàn bộ dịch vụ.
Việc theo dõi vị trí triển khai của từng container trong cơ sở hạ tầng của bạn có vẻ không phải là cách sử dụng thời gian hiệu quả nhất.
Có lẽ có cách nào đó để tự động hóa nó?
Và điều gì sẽ xảy ra nếu bạn có thể có một thuật toán quyết định vị trí đặt các container đó?
Có lẽ nó có thể đủ thông minh để đóng gói các container một cách hiệu quả để tối đa hóa mật độ máy chủ. Thậm chí có thể lưu giữ danh sách các container đã triển khai và máy chủ của chúng.
Hóa ra ai đó đã có chính xác ý tưởng đó và đã đưa ra một giải pháp.
Kubernetes: "Nhạc trưởng" của dàn nhạc container
Kubernetes ban đầu là một sản phẩm của Google.
Google đã chạy một công nghệ tương tự như container và phải tìm cách hiệu quả để lên lịch cho khối lượng công việc.
Họ không muốn lưu giữ và cập nhật thủ công một danh sách dài các container và máy chủ. Vì vậy, họ đã quyết định viết một nền tảng có thể tự động phân tích việc sử dụng tài nguyên, lên lịch và triển khai các container.
Nhưng nó là mã nguồn đóng.
Một số kỹ sư của Google đã quyết định viết lại nền tảng này dưới dạng một dự án mã nguồn mở. Và phần còn lại là lịch sử.
Vậy Kubernetes là gì?
Bạn có thể coi Kubernetes như một bộ lập lịch (scheduler).
Kubernetes kiểm tra cơ sở hạ tầng của bạn (máy chủ vật lý hoặc đám mây, công cộng hoặc riêng tư) và đo lường CPU và bộ nhớ cho mỗi máy tính.
Khi bạn yêu cầu triển khai một container, Kubernetes sẽ xác định các yêu cầu về bộ nhớ cho container của bạn và tìm máy chủ phù hợp nhất đáp ứng yêu cầu đó.
Bạn không quyết định vị trí triển khai ứng dụng. Trung tâm dữ liệu được trừu tượng hóa khỏi bạn.
Nói cách khác, Kubernetes sẽ "chơi Tetris" với cơ sở hạ tầng của bạn.
Các container Docker là các khối, máy chủ là bảng và Kubernetes là người chơi.
Việc Kubernetes đóng gói cơ sở hạ tầng của bạn một cách hiệu quả đồng nghĩa với việc bạn nhận được nhiều tài nguyên tính toán hơn cho số tiền bỏ ra. Bạn có thể làm được nhiều việc hơn với chi phí thấp hơn.
Và kết quả là tổng chi phí sử dụng của bạn sẽ giảm xuống.
Bạn còn nhớ những công ty chỉ sử dụng 10% tài nguyên được phân bổ chứ?
Vâng, Kubernetes chính là "vị cứu tinh" của bạn.
Nhưng còn nhiều hơn thế nữa.
Kubernetes có một tính năng "sát thủ" thường bị lãng quên hoặc bỏ qua.
Kubernetes như một lớp API trên trung tâm dữ liệu của bạn
Mọi thứ bạn làm trong Kubernetes đều cách bạn một lệnh gọi API.
Bạn có cần triển khai một container?
Có một REST endpoint cho việc đó.
Có lẽ bạn muốn cung cấp một bộ cân bằng tải?
Không vấn đề gì. Chỉ cần gọi API này.
Bạn có muốn cung cấp dung lượng lưu trữ?
Vui lòng gửi yêu cầu POST đến URL này.
Mọi thứ bạn làm trong Kubernetes đều là gọi API.
Và có rất nhiều lý do chính đáng để hào hứng về điều đó:
- Bạn có thể tạo các tập lệnh (script) và daemon tương tác với API theo chương trình.
- API được quản lý phiên bản; khi bạn nâng cấp cụm của mình, bạn có thể tiếp tục sử dụng API cũ và di chuyển dần dần.
- Bạn có thể cài đặt Kubernetes trong bất kỳ nhà cung cấp dịch vụ đám mây hoặc trung tâm dữ liệu nào và bạn có thể tận dụng cùng một API.
Bạn có thể coi Kubernetes như một lớp nằm trên cơ sở hạ tầng của bạn.
Và vì lớp này là chung và có thể được cài đặt ở bất kỳ đâu, bạn luôn có thể mang nó theo mình.
Amazon Web Services quá đắt?
Không vấn đề gì.
Bạn có thể cài đặt Kubernetes trên Google Cloud Platform và di chuyển khối lượng công việc của mình đến đó.
Hoặc có lẽ bạn có thể giữ cả hai vì việc có chiến lược cho tính năng sẵn sàng cao (high availability) luôn hữu ích.
Nhưng có lẽ bạn không tin tôi.
Nghe có vẻ quá tốt đẹp để là sự thật, và tôi đang "nói quá" lên chăng?
Hãy để tôi cho bạn thấy.
Tiết kiệm chi phí đám mây với Kubernetes
Netlify là một nền tảng để xây dựng, triển khai và quản lý các trang web tĩnh.
Nó có quy trình tích hợp liên tục (CI) riêng, vì vậy mỗi khi bạn đẩy thay đổi lên kho lưu trữ, trang web của bạn sẽ được xây dựng lại.
Netlify đã chuyển sang Kubernetes thành công, tăng gấp đôi cơ sở người dùng của họ, nhưng vẫn giữ nguyên chi phí.
Đó là một tin tuyệt vời!
Hãy tưởng tượng việc tiết kiệm 50% hóa đơn Google Cloud Platform của bạn!
Nhưng Netlify không phải là trường hợp duy nhất.
Qbox - một công ty tập trung vào dịch vụ Elastic Search được lưu trữ - đã giảm được 50% chi phí AWS mỗi tháng!
Trong quá trình này, họ cũng đã mở mã nguồn cho nỗ lực của mình trong hoạt động đa đám mây.
Nếu bạn vẫn chưa ấn tượng, bạn nên xem qua những gì OpenAI đã làm được.
OpenAI là một công ty nghiên cứu phi lợi nhuận tập trung vào trí tuệ nhân tạo và học máy. Họ đã viết một thuật toán để chơi trò chơi trực tuyến nhiều người chơi Dota giống như bất kỳ người chơi nào khác.
Nhưng họ đã tiến thêm một bước nữa và huấn luyện một đội máy để chơi cùng nhau.
Và họ đã sử dụng Kubernetes để mở rộng mô hình học máy của mình trên đám mây.
Bạn có tò mò về chi tiết cụm của cụm của họ không?
128000 vCPU
Tương đương với khoảng 16000 chiếc MacBook Pro.
256 Nvidia Tesla P100
Tương đương với hiệu suất dấu phẩy động 16 bit 2100 Teraflops.
Giống như bạn đang chạy 525 chiếc PlayStation 4.
Bạn có thể đoán chi phí mỗi giờ không?
Không?
Chỉ 1280 USD/giờ cho 128000 vCPU và 400 USD cho 256 Nvidia P100.
Đó không phải là một khoản tiền lớn khi xét đến việc chiến thắng các giải đấu Dota có thể mang về cho bạn giải thưởng lên tới hàng triệu USD.
Vậy bạn còn chờ gì nữa?
Hãy sẵn sàng áp dụng Kubernetes và tiết kiệm chi phí đám mây của bạn!
Kết luận
Kubernetes và container sẽ còn tiếp tục phát triển mạnh mẽ trong tương lai.
Với sự ủng hộ từ các công ty như Google, Microsoft, Red Hat, Pivotal, Oracle, IBM và nhiều công ty khác, thật khó tin rằng nó sẽ không thành công.
Nhiều công ty đang đi đầu trong việc áp dụng Kubernetes và tham gia vào cuộc cách mạng này.
Không chỉ các công ty khởi nghiệp và doanh nghiệp vừa và nhỏ, mà cả các tập đoàn lớn như ngân hàng, tổ chức tài chính và công ty bảo hiểm cũng đang đặt cược vào container và Kubernetes là tương lai.
Thậm chí cả các công ty đầu tư vào Internet of Things và hệ thống nhúng cũng vậy.
Vẫn còn quá sớm và cộng đồng cần thời gian để trưởng thành, nhưng bạn nên theo dõi sát sao những đổi mới trong lĩnh vực này.
Bài viết được dịch lại từ tác giả Daniele Polencic, cảm ơn các bạn đã theo dõi.
All rights reserved