Các Container Có Thể Làm Mọi Thứ: balena-hoá Steam


Container có thể làm bất cứ điều gì: balena hóa Steam

Trái với niềm tin phổ biến, bất cứ điều gì bạn có thể làm hoặc truy cập trên Linux (như GPU, âm thanh, v.v…) bạn cũng có thể làm được trong một container Docker, và mở rộng ra là trên balenaOS.

Containers Can Do Anything

Trên các diễn đàn trực tuyến, người ta thường nói rằng nếu một ứng dụng yêu cầu truy cập trực tiếp tới phần cứng mạnh như GPU, âm thanh hay các đơn vị xử lý thần kinh (NPU) thì đó không phải là ứng dụng phù hợp để container hóa. Trong bài viết này, chúng ta sẽ phá bỏ quan niệm đó bằng cách xem xét một dự án mẫu thành công trong việc container hóa Steam, nền tảng chơi game trực tuyến nổi tiếng.

Tại sao lại chọn Steam?

Việc chạy Steam thành công đặt ra một số thách thức kỹ thuật thú vị cho một ứng dụng được đóng container:

  • Truy cập bộ nhớ lưu trữ cục bộ
  • Truy cập GPU để xử lý đồ họa mạnh mẽ
  • Truy cập âm thanh
  • Cần giao tiếp giữa các tiến trình (giữa các container)
  • Yêu cầu về compositing (Wayland/Xorg)

Nếu tất cả những yêu cầu này được giải quyết để container hóa thành công Steam, bạn cũng có thể áp dụng tương tự để container hóa gần như bất kỳ ứng dụng nào khác! Hãy cùng xem cách một đồng nghiệp của balena đã vượt qua từng thách thức này trong dự án của anh ấy! (Bạn có thể xem toàn bộ bài trình bày tại đây.)

Truy cập bộ nhớ lưu trữ cục bộ

Đây có lẽ là yêu cầu dễ nhất – Steam lưu trữ mọi thứ cần thiết (bao gồm game đã tải về và shaders đã biên dịch) trong thư mục “home”, vì vậy chỉ cần sử dụng volume được ánh xạ tới thư mục home:

Volume mapping

Truy cập GPU từ container

Để truy cập phần cứng vật lý như GPU hay âm thanh từ bên trong container, chúng ta cần xem xét một loại đặc biệt của file hệ thống Linux gọi là file thiết bị (device file). Thao tác trên file thiết bị sẽ tương tác trực tiếp với phần cứng. Bạn có thể tưởng tượng các file này như giao diện với driver thiết bị xuất hiện dưới dạng file thông thường.

Khi xem thư mục /dev trên máy Linux tiêu chuẩn, bạn sẽ thấy rất nhiều file thiết bị:

/dev directory

Tuy nhiên, bên trong container, Docker mặc định chỉ cấp phép một số file thiết bị giới hạn từ host. Để truy cập vào một thiết bị cụ thể, chúng ta phải ánh xạ nó thủ công. Có ít nhất năm cách ánh xạ thiết bị vào container, nhưng trong ví dụ Steam này, chúng ta chỉ dùng hai cách:

Hướng dẫn Docker Compose

Hướng dẫn Docker Compose là cấu hình trong file docker-compose.yml. Docker Compose cho phép ánh xạ thiết bị cụ thể và có thuộc tính group_add để cấp quyền cho nhóm thiết bị. Đây là cách được khuyến nghị vì kiểm soát bảo mật tinh vi hơn. Tuy nhiên, cũng có nhược điểm là container sẽ không khởi động nếu thiết bị không có sẵn và không hỗ trợ hot plugging thiết bị.

Ví dụ trong container steam có chỉ thị compose cho thiết bị đồ họa:

Docker Compose directive

Bất kỳ ứng dụng nào cần truy cập API đồ họa như OpenGL hay Vulkan đều phải cài đặt thư viện người dùng phù hợp trong container. Container này dùng driver Mesa mã nguồn mở. Nếu sử dụng GPU NVIDIA, cần phải cài các thư viện NVIDIA trong container.

devtmpfs

Cách này phức tạp hơn một chút để thiết lập, cung cấp quyền truy cập đầy đủ đến tất cả các file thiết bị trên host, bao gồm cả thiết bị hot plugged, nhưng có thể làm lộ nhiều thiết bị hơn mức cần thiết giống như tùy chọn “privileged”.

Ví dụ devtmpfs xuất hiện trong dịch vụ seatd của dự án mẫu. Seatd được sử dụng bởi compositor để truy cập màn hình và thiết bị đầu vào trong môi trường đa ghế (multi-seat).

devtmpfs example

Container hóa trình compositing Wayland

Đến đây ta đã thấy container có thể kết nối GPU và xử lý đồ họa, nhưng Steam còn muốn ghép nhiều thành phần hình ảnh lại thành một màn hình duy nhất và thêm hiệu ứng. Đó chính là nhiệm vụ của compositor.

Một compositor Wayland là một server hiển thị dùng giao thức Wayland và đóng vai trò là trình quản lý cửa sổ compositing. Steam thông báo cho compositor biết các nội dung mới cần được đặt ở đâu.

Trong ví dụ này, compositor Wayland được chạy trong một container riêng biệt mà bạn thấy định nghĩa trong file docker compose:

Wayland compositor container

  • Cần truy cập node DRM tại /dev/dri để làm master DRM và thực hiện rendering
  • Cần thư viện người dùng đồ họa (Mesa)
  • Cần volume chia sẻ để giao tiếp với client thông qua socket
  • Hỗ trợ cả client X thông qua Xwayland
  • Xwayland cần volume chia sẻ khác tại /tmp/.X11-unix

Truy cập âm thanh

Truy cập âm thanh từ container có những thách thức và giải pháp tương tự như đồ họa. Kernel cung cấp âm thanh thông qua hệ thống ALSA, với các file thiết bị âm thanh nằm trong /dev/snd.

Việc phối trộn âm thanh do các daemon như pulseaudio hoặc pipewire đảm nhiệm. Trong ví dụ này, daemon âm thanh là một dịch vụ riêng biệt và các ứng dụng (Steam) chỉ cần truy cập socket giao tiếp âm thanh:

Audio access

Đi xa hơn

Nếu bạn quan tâm chi tiết dự án mẫu container hóa Steam này, hãy truy cập kho mã nguồn tại đây hoặc xem bài trình bày gốc được nhúng bên dưới.

Điều quan trọng hơn là ngay cả một ứng dụng phức tạp yêu cầu đồ họa, âm thanh và xử lý sự kiện cũng có thể chia thành các dịch vụ thành phần chạy trong các container tách biệt giao tiếp với nhau. Những dịch vụ này có thể được nâng cấp hoặc sửa đổi độc lập để tăng tính linh hoạt.

BalenaOS được thiết kế để chạy container Docker trên các thiết bị edge, có thể quản lý dễ dàng qua balenaCloud. Tất cả các kỹ thuật trong bài viết này cũng áp dụng tốt trên Docker hay balenaOS. Bạn có dự án container hóa thử thách nào cần hỗ trợ?