Docker trên macOS không ngon như trên Linux

Docker trên macOS không ngon như trên Linux
Photo by Venti Views from Unsplash

Docker là một công cụ giúp phát triển và chạy các ứng dụng trong một môi trường ảo gọi là container. Nó cho phép tạo các môi trường độc lập và tách biệt với hệ điều hành. Dù là một công cụ được tin dùng, Docker trên macOS không được đánh giá cao như trên Linux. Trong bài viết này tôi sẽ trình bày những vấn đề của Docker trên macOS.

Môi trường ảo (Container) vs. Máy ảo (Virtual Machine)

Trước hết, khi nói đến Docker hầu như ai cũng nghĩ đến kiến trúc container và sự khác biệt của nó so với cách ảo hóa trước kia dùng máy ảo (Virtual Machine – VM).

Có nhiều quan điểm khác nhau về chuyện đóng gói container, nhưng với tôi thì cách đóng gói container của Docker là “môi trường ảo”, tức là chỉ đóng gói môi trường thực thi ứng dụng vào container mà thôi. Còn máy ảo là đóng gói nguyên một hệ thống phần cứng, phần mềm vào một máy ảo.

Sự khác biệt của hai hình thức này được mô tả rất rõ qua hình ảnh sau.

container vs virtual machine
Nguồn: Atlassian

Điểm khác biệt quan trọng là container sẽ sử dụng Host OS và hạt nhân (kernel) của nó. Vì vậy mới nói container là môi trường ảo, còn CPU, RAM và các phần cứng khác đều là thật. Do đó, hiệu suất làm việc của container cao hơn máy ảo nhiều. Ví dụ, để container đọc/ghi các tập tin trong ổ cứng của máy tính, việc nó cần làm là mount ổ cứng này vào container và việc đọc/ghi này được thực hiện hoàn toàn giống như thao tác trên Host OS vậy.

Còn với máy ảo, trên nền Host OS, máy ảo phải cài đặt thêm một hệ điều hành nữa (Guest OS) cũng như một tầng ảo hóa (gọi là Hypervisor) để xây dựng phần cứng ảo. Vì mọi thứ đều là ảo, từ phần cứng đến phần mềm, được xây dựng thông qua Hypervisor nên máy ảo rất nặng và hiệu suất cũng không cao. Để đọc/ghi ổ cứng của máy tính, thao tác với máy ảo phải trải qua 3 bước:

  • Mount ổ cứng vào Guest OS
  • Mount ổ cứng từ Host OS vào Hypervisor
  • Hypervisor đồng bộ sự thay đổi của các tập tin giữa Host OS và Guest OS.

Docker for macOS

Hầu hết các bài chia sẻ kiến thức liên quan đến Docker hay container sẽ có nội dung tương tự như trên (sẽ rõ ràng, chi tiết hơn, phần tôi viết hơi ngắn gọn một chút). Nhưng, có một điều mà hầu hết các bài viết đó, không rõ vô tình hay cố ý, đều lờ đi một sự thật là những kiến thức đó chỉ áp dụng với Docker chạy trên các bản phân phối Linux mà thôi (Docker trên Linux là native).

Container ở đây đều là Linux container, và nó cần hạt nhân Linux mới có thể sử dụng sức mạnh của Host OS. Với những hệ điều hành không có hạt nhân Linux như Windows hay macOS, mọi thứ phức tạp hơn nhiều.

Với Windows, Docker có hai phiên bản sử dụng Hyper-V (công nghệ ảo hóa của Microsoft xuất hiện trên Windows 10) hoặc WSL2 (Windows Subsystem for Linux). Trước khi những công nghệ này xuất hiện, muốn dùng Docker trên Windows sẽ phải cài thêm VirtualBox để chạy máy ảo. Dù là WSL2 hay Hyper-V, thực chất hạt nhân Linux vẫn được cài đặt trong một máy ảo, nhưng khá gọn nhẹ và có hiệu năng cao.

Với macOS cũng tương tự như vậy. Docker Desktop cho macOS, cũng sử dụng máy ảo, được xây dựng dựa trên Hypervisor frameworkHyperKit.

Giờ đã có cả phiên bản Docker Desktop for Linux cũng sử dụng VM tương tự như trên macOS hay Windows. Muốn chạy Docker native trên Linux thì cần cài Docker Engine riêng.

Kiến trúc của Docker trên macOS rất khác so với Linux và nó như hình dưới đây:

Mac Architecture
Nguồn: everyday.codes

Docker container không thể giao tiếp trực tiếp với macOS, thay vào đó, Docker xây dựng một máy ảo Linux riêng. Quá trình hoạt động của Docker trên macOS lại tương tự như trường hợp dùng virtual machine chứ không phải container. Do đó, hiệu suất làm việc của Docker trên macOS không được đánh giá cao.

Cũng may, thông thường macOS chỉ được dùng cho môi trường local của một dự án phần mềm mà thôi. Không ai lại chạy production trên macOS cả. Và với trường hợp như vậy, việc sử dụng Docker container trên macOS sẽ kiểu như thế này:

  • macOS:
    • Các công cụ phát triển phần mềm (editor, IDE, v.v…)
    • Quản lý version (git)
    • Viết code trên macOS
  • Container:
    • Đồng bộ code từ macOS vào container
    • Cài đặt dependency
    • Chạy ứng dụng trong container

Khi macOS chạy các container, việc đồng bộ code từ macOS vào container sẽ tốn kha khá thời gian, vì tốc độ đọc/ghi của container không được tối ưu. Đặc biệt, vì sử dụng Hyperkit, CPU và RAM sẽ phải hoạt động ở mức độ cao, dù nhiều lúc container cũng không có hoạt động gì. Với môi trường local thì những điều đó có thể tạm chấp nhận được 😄.

Tùy chọn mới cho Docker trên macOS

Docker trên macOS vẫn tiếp tục được phát triển với những kỹ thuật mới để nâng cao hiệu suất. Sau một thời gian thử nghiệm (ở phiên bản 4.6 mới là Experimental Features), thì phiên bản Docker Desktop hiện nay đã có tùy chọn cho phép sử dụng VirtioFS để nâng cao hiệu suất đọc/ghi ổ cứng cho container.

VirtioFS

Tôi sẽ so sánh hiệu suất của tùy chọn này so với tùy chọn mặc định trước đây (gRPC FUSE). So sánh chỉ đơn giản là xem tốc độ đọc/ghi một file dung lượng 100MiB bằng lệnh dd.

Dưới đây là kết quả của tùy chọn mặc định gRPC FUSE:

$ dd if=/dev/zero of=test bs=1024 count=102400 
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 161.366 s, 650 kB/s

Với một máy tính MacBook Pro dùng SSD mà tốc độ 650 kB/s thì quá thấp. Còn nếu dùng VirtioFS thì kết quả như dưới đây:

$ dd if=/dev/zero of=test bs=1024 count=102400 
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 44.1365 s, 2.4 MB/s

Tốc độ là 2.4 MB/s, tuy chưa thể nói là cao, nhưng so với tùy chọn mặc định thì nó đã tăng lên khoảng 4 lần. Để so sánh rõ hơn thì đây là kết quả khi chạy trực tiếp trên macOS, tốc độ là hơn 166MB/s. Như vậy, Docker container chỉ dùng chưa đến 2% sức mạnh của ổ cứng trên macOS.

$ dd if=/dev/zero of=test bs=1024 count=102400
102400+0 records in
102400+0 records out
104857600 bytes transferred in 0.631085 secs (166154480 bytes/sec)

Nói chung, tốc độ đọc/ghi file của Docker trên macOS đã được cải thiện (nhiều là khác – khoảng 4 lần), nhưng nó chưa tiệm cận đến mức hiệu suất của Docker chạy trên Linux. Đó là chưa kể nói về hiệu suất còn nhiều yếu tố khác nữa. Thậm chí, có nhiều ý kiến cho rằng hiệu suất trên macOS của Docker còn kém hơn cả trên Windows dùng WSL2, dù macOS là một hệ điều hành UNIX gần gũi với Linux hơn Windows rất nhiều.

Kết luận

Docker được phát triển là một công cụ chạy với hạt nhân Linux. Vì không có hạt nhân Linux, máy ảo là phương pháp được áp dụng để chạy Docker trên macOS và điều này dẫn đến hiệu suất kém hơn. Tuy đã có nhiều cải tiến, nhưng Docker trên macOS chưa thể so được với Docker trên Linux.

Thế nhưng, hiện tại và trong tương lai, tôi vẫn tiếp tục sử dụng Docker. Tốc độ chậm nhưng không phải là vấn đề lớn (vì chỉ dùng cho local), quan trọng hơn, Docker mang lại quá nhiều lợi ích khi phải cài đặt và cấu hình môi trường phát triển cho từng dự án. Nhất là kết hợp Docker và VSCode dev container thì rất tiện.

Tôi xin lỗi nếu bài viết có bất kỳ typo nào. Nếu bạn nhận thấy điều gì bất thường, xin hãy cho tôi biết.

Nếu có bất điều gì muốn nói, bạn có thể liên hệ với tôi qua các mạng xã hội, tạo discussion hoặc report issue trên Github.