Share

Docker từ A-Z (Phần 1): Docker là gì và tại sao bạn nên quan tâm?

Container Docker hiện đại đang đóng gói code và dependencies - Giải thích Docker là gì cho người mới bắt đầu - siucode.com

Chào anh em!

Chắc hẳn không ít lần trong sự nghiệp code của mình, anh em đã từng nghe (hoặc chính mình thốt lên) câu nói huyền thoại: “Ơ, trên máy tớ chạy ngon mà?” khi sản phẩm mình làm chạy vù vù trên local mà deploy lên server hay đưa cho người khác thì lỗi tùm lum? Hay cái cảnh một bạn mới vào team, loay hoay cả buổi sáng, thậm chí cả ngày, chỉ để cài đặt cho đúng cái môi trường với đủ thứ phiên bản trên đời (NodeJS version này, Python version kia, PHP phải đúng chấm mấy, rồi MySQL, PostgreSQL, Redis,… vân vân và mây mây) mới chạy được cái project?

Mình đã từng ở trong hoàn cảnh đó. Hồi xưa, mỗi lần setup máy mới là y như rằng “toát mồ hôi” với đủ thứ dependencies, biến môi trường, cấu hình khác nhau giữa các máy, giữa các OS (ông thì Mac, ông thì Win, ông lại Linux). Thời gian lẽ ra để tập trung phát triển tính năng ngon nghẻ cho sản phẩm thì lại tốn vào mấy việc râu ria nhưng lại cực kỳ quan trọng và dễ gây lỗi này. Mệt vãi! Chắc chắn thứ quá khứ cũ rích đầy đau thương đó anh em nào đã từng trải qua sẽ không muốn nhắc lại đâu.

Nhưng thôi, cũ thì nhắc lại cho mới :v

Những nỗi đau rất thật & cách Docker “chữa lành”

Trước khi đi sâu vào Docker là gì, hãy cùng điểm lại những nỗi đau “rất thật” mà chúng ta thường xuyên đối mặt, và xem Docker giải quyết chúng như thế nào nhé.

Lập trình viên đau đầu vì môi trường dev hỗn loạn và không nhất quán - Vấn đề Docker giúp giải quyết hiệu quả - siucode.com

Môi trường không nhất quán – “It works on my machine, but not on yours”

Tình huống: Team bạn có người dùng MacOS cài Node 16, người lại dùng Windows với Node 18. Code của bạn A (dùng Mac) chạy ngon lành, đẩy lên Git, bạn B (dùng Win) kéo về chạy thì lỗi tè le vì khác phiên bản Node, hoặc do bạn A lỡ cài một thư viện global nào đó mà không ghi vào package.json. Đau hơn nữa là khi deploy lên server Production chạy Linux, nó lại sinh ra một lỗi khác hẳn do khác biệt về hệ điều hành hoặc thiếu một thư viện hệ thống nào đó (ví dụ: thư viện xử lý ảnh như imagemagick).

Giải pháp của Docker: Docker cho phép bạn “đóng băng” môi trường chạy ứng dụng vào một thứ gọi là Image. Cái Image này chứa tất tần tật mọi thứ ứng dụng cần: đúng phiên bản Node.js bạn chỉ định (ví dụ Node 16), đúng các thư viện hệ thống cần thiết (cài luôn imagemagick vào Image nếu cần), và toàn bộ code + dependencies của bạn. Sau đó, bạn chỉ cần chạy cái Image này dưới dạng Container trên bất kỳ máy nào (Mac, Win, Linux) đã cài Docker. Môi trường bên trong container đó sẽ luôn luôn giống hệt nhau, bất kể máy chủ bên ngoài là gì. Kết quả? Bye bye “Works on my machine”!

Setup môi trường. Kiếp nạn cho người mới/máy mới

Tình huống: Dự án công ty bạn khá lớn, dùng đủ thứ công nghệ: Backend Java 11 + Maven, frontend ReactJS, database PostgreSQL 12, thêm quả Redis để caching và Elasticsearch để search nữa. Bạn new member vào team, nhận tài liệu hướng dẫn setup môi trường dài cả chục trang A4. Nào là cài đúng JDK 11 (không phải 8 hay 17), cài Maven, cài Node, setup Postgres (tạo user, database), cài Redis, cài ES,… chỉ cần sai một bước nhỏ hoặc thiếu một biến môi trường là project không chạy được. Tốn cả ngày, thậm chí vài ngày, chỉ để setup xong môi trường, quá nản!

Giải pháp của Docker: Với Docker, anh em chỉ cần định nghĩa toàn bộ các “mảnh ghép” của hệ thống (Backend Java, Frontend React, Postgres, Redis, ES) dưới dạng các services trong một file cấu hình duy nhất tên là docker-compose.yml. Mỗi service sẽ chạy trong một container riêng, được build từ Docker Image tương ứng. Người mới vào team? Đơn giản! Chỉ cần cài Docker, clone code về, mở terminal và gõ một lệnh thần thánh: docker-compose up. Bùm! Trong vài phút, toàn bộ hệ thống với đầy đủ database, cache, search engine… đã sẵn sàng hoạt động y như môi trường chuẩn. Nhanh, gọn, chuẩn không cần chỉnh!

Xung đột thư viện/phiên bản giữa các dự án

Tình huống: Máy tính của bạn đang phải “cõng” nhiều dự án cùng lúc. Dự án A là hệ thống cũ chạy PHP 5.6 với thư viện X phiên bản 1.0. Dự án B là cái mới coóng viết bằng Python 3.9 cần thư viện X nhưng phải là phiên bản 3.0 mới nhất. Cài cả hai phiên bản PHP hay Python trên cùng một máy đã là một chuyện, quản lý thư viện X cho từng cái còn đau đầu hơn. Dùng virtual environment (venv) cho Python cũng đỡ phần nào, nhưng đôi khi vẫn có những thứ cài global gây xung đột ngầm.

Giải pháp của Docker: Mỗi dự án được “Docker hóa” sẽ chạy trong container riêng của nó. Container dự án A sẽ có môi trường PHP 5.6 + lib X v1.0. Container dự án B hoàn toàn độc lập với môi trường Python 3.9 + lib X v3.0. Chúng sống trong thế giới riêng, hoàn toàn biệt lập, không bao giờ đụng chạm hay ảnh hưởng gì đến nhau, dù cùng chạy trên máy tính của bạn. Bạn có thể tự tin chạy song song cả chục dự án với các stack công nghệ và phiên bản khác nhau mà không sợ loạn cào cào.

Môi trường local khác xa môi trường Production

Tình huống: Anh em code local thường chỉ chạy thẳng app server (Node, Python, PHP…). Nhưng khi deploy lên Production, thường sẽ có thêm một lớp Nginx/Apache làm reverse proxy phía trước, rồi có thể có thêm Redis Cache, Varnish,… Cấu hình trên Production khác biệt kha khá so với local. Kết quả là nhiều lỗi trời ơi đất hỡi liên quan đến header, caching, request routing… chỉ xuất hiện khi deploy, còn ở local thì không tài nào tái hiện được.

Giải pháp của Docker: Docker (đặc biệt là Docker Compose) cho phép bạn dễ dàng dựng lên một môi trường local mô phỏng gần giống nhất với Production. Bạn có thể định nghĩa một service chạy ứng dụng của mình, một service khác chạy Nginx với cấu hình tương tự Production để làm reverse proxy, một service chạy Redis… Tất cả liên kết với nhau. Điều này giúp phát hiện sớm các vấn đề tương thích ngay từ khi còn ở local, giảm thiểu rủi ro khi deploy thật.

Những nỗi đau phía trên chỉ là 4 nỗi đau trong muôn vàn nỗi đau anh em và mình gặp phải. Hiểu được điều đó, Docker ra đời, cứu anh em 1 chén, hay thậm chí là N chén…

Vậy thì tóm lại, Docker là cái gì?

Nói một cách đơn giản và hình tượng nhất mà mình hay dùng để giải thích cho anh em mới: Hãy tưởng tượng Docker như những cái container vận chuyển hàng hóa ngoài cảng.

  • Trước khi có container: Mỗi loại hàng (phần mềm của bạn) được đóng gói theo kiểu khác nhau, vận chuyển bằng các phương tiện khác nhau (máy tính, server cấu hình khác nhau), rất dễ hư hỏng, thất lạc (lỗi tùm lum).
  • Khi có container: Mọi loại hàng hóa (code, thư viện, runtime, dependencies…) đều được đóng gói chuẩn vào trong các thùng container giống hệt nhau (đây chính là Docker Image). Những thùng container này sau đó có thể được dễ dàng bốc lên, vận chuyển bằng tàu, xe tải (chia sẻ, deploy lên bất kỳ máy nào có cài Docker) và đặt xuống chạy ở bất kỳ đâu có cảng (môi trường có Docker Engine) mà không cần quan tâm bên trong nó chứa chính xác cái gì, vì nó đã được chuẩn hóa và cô lập hoàn toàn rồi. Cái thùng container đang chạy đó chính là Docker Container.

Ngắn gọn hơn theo định nghĩa “sách vở” một chút: Docker là một nền tảng (platform) mã nguồn mở giúp bạn tự động hóa việc triển khai, mở rộng và quản lý ứng dụng bằng cách sử dụng công nghệ containerization (container hóa). Nó cho phép bạn đóng gói ứng dụng và tất cả những gì cần thiết để chạy ứng dụng đó (thư viện, dependencies, biến môi trường…) vào một đơn vị độc lập gọi là container.

Ủa, nghe giống Máy ảo (Virtual Machine – VM) thế?

À, đây là câu hỏi rất nhiều người mới thắc mắc. Đúng là cả hai đều giúp tạo ra môi trường độc lập để chạy ứng dụng, nhưng cách hoạt động và hiệu quả thì khác nhau một trời một vực:

  • Máy ảo (VM): Tưởng tượng bạn muốn chạy một cái máy tính khác bên trong máy tính hiện tại của bạn. VM tạo ra hẳn một cái máy ảo hoàn chỉnh, bao gồm cả hệ điều hành riêng (Windows, Linux ảo), phần cứng ảo hóa (CPU, RAM, Disk ảo). Điều này làm VM khá nặng nề, tốn tài nguyên (RAM, CPU, ổ cứng) và khởi động rất chậm. Giống như bạn xây hẳn một căn nhà riêng biệt chỉ để đặt một cái tủ lạnh vậy.
  • Docker Container: Thay vì tạo cả hệ điều hành ảo, container chia sẻ nhân (kernel) của hệ điều hành máy chủ (Host OS). Nó chỉ đóng gói những thứ thực sự cần thiết cho ứng dụng của bạn thôi (code, thư viện, runtime). Vì vậy, container nhẹ hơn rất nhiều, khởi động gần như tức thìtiết kiệm tài nguyên hơn VM đáng kể. Giống như bạn có nhiều phòng (container) trong cùng một ngôi nhà (Host OS), mỗi phòng chứa đồ đạc riêng (ứng dụng) nhưng đều dùng chung nền móng (kernel).
Ảnh minh họa so sánh kiến trúc Docker container (nhẹ, chia sẻ kernel) và Máy ảo VM (nặng, hệ điều hành riêng) - siucode.com

Tại sao bạn nên bỏ thời gian tìm hiểu Docker?

Dựa trên những gì mình vừa chia sẻ, đây là những lợi ích cực kỳ thực tế mà Docker mang lại, đặc biệt là với anh em lập trình viên chúng ta:

  1. Môi trường nhất quán: “Works on my machine” sẽ không còn là vấn đề. Code chạy ngon trên máy bạn thì khả năng cao cũng sẽ chạy ngon trên máy đồng nghiệp và trên server production, vì tất cả đều chạy trong cùng một “container” được định nghĩa giống hệt nhau.
  2. Setup môi trường “dễ như ăn kẹo”: Thay vì cài đặt hàng tá thứ thủ công, bạn (hoặc người mới vào team) chỉ cần cài Docker, kéo image về và chạy một lệnh là có ngay môi trường chuẩn để chiến code. Tiết kiệm thời gian và công sức cực lớn!
  3. Cô lập dependencies: Mỗi ứng dụng chạy trong container riêng, có bộ thư viện riêng, không sợ xung đột phiên bản giữa các project khác nhau trên cùng một máy. Ví dụ, bạn có thể chạy project dùng Node 14 và project dùng Node 18 trên cùng một máy mà không gặp vấn đề gì.
  4. Triển khai (deploy) nhanh chóng và dễ dàng: Build image một lần, chạy ở bất kỳ đâu có Docker. Việc đưa ứng dụng lên server staging hay production trở nên đơn giản và ít rủi ro hơn nhiều.
  5. Tối ưu tài nguyên: Nhẹ và nhanh hơn VM, cho phép bạn chạy nhiều ứng dụng hơn trên cùng một hạ tầng.

Nghe hấp dẫn rồi đúng không? Docker thực sự đã thay đổi cách chúng ta phát triển và triển khai phần mềm.

Ở bài tiếp theo…

Chúng ta đã hiểu Docker là gì và tại sao nó hữu ích rồi. Trong phần 2 của series này, mình sẽ cùng anh em “mổ xẻ” các khái niệm cốt lõi tạo nên Docker: Image, Container, Dockerfile là gì và chúng liên kết với nhau như thế nào nhé. Đây là những viên gạch nền tảng để chúng ta có thể bắt tay vào thực hành ở các phần sau.

Đừng ngần ngại bắt đầu tìm hiểu Docker nhé, tuy ban đầu có thể hơi lạ lẫm nhưng những lợi ích nó mang lại thực sự xứng đáng. Hẹn gặp lại anh em ở bài viết tiếp theo!

SiuCode – Vừa code vừa siuuuu🚀

You may also like

Mục lục