Vì sao Railway chuyển từ Nix sang Railpack
(blog.railway.com)- Railway đã thiết kế lại builder tạo image container từ mã của người dùng, đưa kinh nghiệm từ Nixpacks — công cụ đã build hơn 14 triệu ứng dụng — sang Railpack
- Nixpacks đủ tốt với 80% người dùng, nhưng 200.000 người dùng Railway còn lại có thể gặp giới hạn về quản lý phiên bản, kích thước image và caching
- Railpack nâng cao khả năng tái lập build bằng phiên bản
major.minor.patch, khóa dependency và luồng cài đặt dựa trên Mise, thay cho quản lý phiên bản dựa trên commit của Nix - Bằng cách trực tiếp tạo BuildKit LLB và Frontend, image Node mặc định nhỏ hơn 38%, image Python mặc định nhỏ hơn 77%, đồng thời có thể dùng cache chia sẻ giữa các môi trường
- Railpack hiện đang ở Beta và có thể bật trong phần cài đặt dịch vụ; Railway ưu tiên nâng cao độ hoàn thiện cho các ngôn ngữ được dùng thường xuyên hơn là mở rộng hỗ trợ thật nhiều ngôn ngữ
Bối cảnh Railway tạo builder mới
- Railway công bố Railpack là bước tiếp theo của Railway builder
- Railpack được phát triển lại từ đầu dựa trên kinh nghiệm thu được khi build hơn 14 triệu ứng dụng bằng Nixpacks
- Sau khi ra mắt khoảng 3 năm trước, Nixpacks trở thành cách mặc định để build image từ mã người dùng trên Railway
- Nó hoạt động tốt với 80% tổng số người dùng, nhưng 200.000 người dùng Railway còn lại có thể gặp các giới hạn
- Railway cho rằng để mở rộng cơ sở người dùng từ 1 triệu lên 100 triệu, builder cần được nâng cấp đáng kể
Những giới hạn Nixpacks gặp phải với Nix
- Vấn đề lớn nhất là quản lý phiên bản package dựa trên commit của Nix
- Mỗi package chỉ cung cấp phiên bản major mới nhất
- Phiên bản bị ràng buộc với một commit cụ thể trong nixpkgs repo
- Nỗ lực hỗ trợ mọi phiên bản patch đã dẫn đến cấu trúc ánh xạ trực tiếp chuỗi phiên bản với commit SHA, điều này không rõ ràng hoặc khó bảo trì với các contributor không quen với cách quản lý phiên bản của Nix
- Các ngôn ngữ như Node và Python cuối cùng chỉ hỗ trợ phiên bản major mới nhất
- Khi cập nhật commit SHA để hỗ trợ phiên bản package mới nhất, các phiên bản package khác cũng có thể thay đổi theo
- Nếu phiên bản mặc định thay đổi, các bản build của người dùng vốn đang hoạt động có nguy cơ thất bại do lỗi không lường trước
- Railway xem việc một bản build từng thành công bỗng nhiên bị hỏng là tệ hơn việc người dùng không truy cập được package mới nhất
Vấn đề kích thước image và caching
- Cách Nixpacks lấy dependency bằng Nix thường tạo ra image có kích thước lớn
- Nix cùng các package và thư viện liên quan cần cho build và runtime được đưa vào một layer
/nix/storeduy nhất - Không có cách tách dependency Nix thành các layer riêng, nên việc giảm kích thước image cuối bị hạn chế
- Railway xem đây không phải là vấn đề của bản thân Nix, mà là vấn đề ở cách Nixpacks sử dụng Nix
- Với caching, cũng khó kiểm soát khi nào layer cache bị vô hiệu hóa
- Railway chèn biến môi trường deployment ID vào mọi build
- Trong Dockerfile, các layer chạy sau khi biến này được thêm vào sẽ luôn bị vô hiệu hóa và không thể cache
- Cách tiếp cận cố gắng che giấu các thành phần cốt lõi của Nix khỏi người dùng cũng không thật sự phù hợp
- Họ muốn người dùng không cần hiểu derivation là gì, hoặc vì sao Node 22.14.0 lại nằm trong một phiên bản archive cụ thể của kênh unstable
Thay đổi kiến trúc của Railpack
- Railway tạo Railpack để giải quyết các vấn đề đã gặp trong Nixpacks
- Khi rời khỏi Nix, tên gọi cũng đổi từ Nixpacks thành Railpack
- Codebase được chuyển từ Rust sang Go vì thư viện BuildKit
- Railpack kiểm soát trực tiếp hơn cách tạo image cuối
- Trực tiếp tạo BuildKit LLB và Frontend
- So với Nixpacks, image Node mặc định nhỏ hơn 38%, image Python mặc định nhỏ hơn 77%
- Sử dụng Mise để phân giải phiên bản và cài đặt phần lớn package
- Vẫn để ngỏ khả năng hỗ trợ các nguồn executable khác trong tương lai
- Có thể khóa các dependency đã dùng trong một bản build thành công
- Nhờ đó build không bị hỏng ngay cả khi phiên bản Node mặc định đổi từ 22 sang 24
- Sử dụng BuildKit secrets để biến môi trường bí mật không xuất hiện trong build log hoặc image cuối
Cách build của Railpack hoạt động
- Quy trình Railpack được chia thành ba bước
- Analyze: xem mã để xác định package cần cài, lệnh cần chạy và lệnh khởi động
- Plan: tạo kế hoạch build có thể serialize thành JSON gồm nhiều bước, trong đó mỗi bước lấy input từ bước khác hoặc từ toàn bộ image
- Generate: cấu thành đồ thị build BuildKit dựa trên input và output của kế hoạch
- Dockerfile có tính tuyến tính, nhưng đồ thị BuildKit được cấu trúc song song hơn nhiều
- Mỗi lệnh chạy trong stage riêng của multi-stage build, cho phép kiểm soát chi tiết layer input và cách lắp ráp filesystem cuối
- Railpack tạo kế hoạch build chứa mọi bước build cần thiết
- Mỗi bước định nghĩa cụ thể các bước trước đó hoặc image cần dùng
- Định dạng này ở mức thấp hơn cách từng được dùng trong Nixpacks
- Kế hoạch được chuyển thành đồ thị ở định dạng LLB rồi được diễn giải
- BuildKit bắt đầu từ cuối và làm ngược lại, lấy từ cache khi có thể, và chỉ chạy lệnh khi cần để resolve layer được yêu cầu
- Để vô hiệu hóa layer khi một biến môi trường cụ thể thay đổi, Railpack hash giá trị biến đã dùng và mount một file chứa hash đó vào filesystem input
- Nếu mã và các biến đã dùng không thay đổi, layer cache sẽ hit
- Railpack có thể định nghĩa hoàn toàn cách image được tạo ra
Những việc Railpack cho phép thực hiện
- Có thể build và deploy site tĩnh Vite, Astro, CRA, Angular với zero-config
- Tích hợp giữa build và Railway UI chặt chẽ hơn
- Có thể hỗ trợ phiên bản mới nhất của ngôn ngữ mà không cần phát hành Railpack
- Có thể dùng layer caching được tối ưu hóa trên nhiều môi trường của dự án
Cách sử dụng hiện tại và phạm vi hỗ trợ
- Railpack hiện được cung cấp ở trạng thái Beta, có thể kích hoạt trong phần cài đặt dịch vụ
- Nó đã được dùng để build railway.com và central station
- Hiện hỗ trợ các mục sau
- Node
- Python
- Go
- PHP
- Deploy Static HTML
- Hỗ trợ cơ bản cho site tĩnh Vite, Astro, CRA, Angular
- Railway hướng tới một môi trường có thể deploy cả frontend lẫn backend một cách dễ dàng
- Hỗ trợ framework và ngôn ngữ vẫn tiếp tục được bổ sung
- Có thể gửi yêu cầu tại Help Station
- Cho đến khi API lõi và các abstraction được chốt, họ ưu tiên chiều sâu cho các ngôn ngữ được dùng nhiều hơn là hỗ trợ thật rộng
- Railpack là mã nguồn mở và tài liệu được cung cấp tại railpack.com
1 bình luận
Ý kiến trên Hacker News
Tôi là người thích Nix, nhưng không có ý chỉ trích việc Railway rời khỏi Nix. Chỉ là một số phàn nàn có vẻ cần được giải thích thêm
Nixpkgs rất tuyệt, nhưng không phải là một với Nix; và nếu muốn lấy các phiên bản toolchain tùy ý thì Nixpkgs chỉ đơn giản là không lý tưởng. Các công cụ Nix để lấy phiên bản Rust tùy ý hiện đã rất tốt, và các công cụ phát triển dựa trên Nix khác cũng đã cho thấy cách xử lý việc này ổn thỏa
Tôi cũng không hiểu câu “không có cách nào tách dependency Nix thành một layer riêng”. Bạn có thể tách theo bất kỳ cách nào mình muốn, và các công cụ Docker tích hợp trong Nixpkgs cũng có một phần hỗ trợ cho việc này
Việc chuyển từ Rust sang Go không liên quan trực tiếp đến Nix nhưng khá thú vị, và nghe như Railpacks với Nixpacks do những người khác nhau tạo ra. Tôi từng thấy những chuyện khá tệ xảy ra khi những người không quen với Nix phải gánh một giải pháp Nix chưa hoàn thiện trong tổ chức, nên ở nơi làm việc tôi thường không dùng Nix để tránh tạo ra tình huống như vậy
Câu “cứ chia layer theo cách bạn muốn” cũng vậy: điều quan trọng là việc đó có rõ ràng, đơn giản và là hành vi mặc định hay không
Lý do mọi người bất mãn với Nix không phải vì nó không Turing-complete, mà vì nó không cung cấp một API hạng nhất đơn giản, khớp ngay với các dự án theo quán lệ của hệ sinh thái tương ứng, khiến nó tạo ra nhiều vấn đề hơn số vấn đề nó giải quyết
Nếu dự án nào muốn dùng Nix cuối cùng cũng trôi về hướng tự viết module để sửa các vấn đề của Nix, thì lý do để dùng Nix thay vì các công cụ phổ biến có tài liệu tốt là khá yếu. Trường hợp này trông đúng như vậy, và tôi nghĩ phần lớn sẽ chỉ chọn Docker
Điều gây bực là một sản phẩm dành cho developer lại bám vào flakes thuần khiết về mặt ý thức hệ, thay vì giải quyết các vấn đề thực tế về developer experience với tốc độ không tính bằng đơn vị thời gian địa chất. Tôi hiểu đó là đóng góp tự nguyện, nhưng thật đáng tiếc khi quá nhiều nỗ lực kỹ thuật lại đổ vào một thứ mà trải nghiệm người dùng tệ khiến nó gần như khó dùng trong thực tế
Với cách Nix hoạt động cùng cấu trúc Nixpkgs, việc cố định một phiên bản package đồng nghĩa với việc cố định commit của toàn bộ cây nixpkgs. Việc build package node/python/ruby còn phụ thuộc vào trạng thái của cây bên ngoài thư mục package, nên cần có ánh xạ giữa phiên bản và commit
Abstraction này bị rò rỉ, nên Railway phải phơi bày nó cho người dùng; người dùng vốn chỉ muốn chạy
yarn add new-fancy-nodejs-package-with-linked–native-depsnhưng lại có thể bị đẩy vào tình huống phải khớp nhiều trạng thái khác nhau của repo nixpkgsVới phạm vi sử dụng hẹp thì dùng Nix mà không có Nixpkgs cũng ổn, nhưng với một nền tảng như Railway thì có vẻ khó biện minh
pkgnhìn chung hoạt động tốt, nhưng có lần tôi cố biên dịch vim từ ports với USE flag tùy chỉnh, nó kéo về hơn 20 dependency và cứ mỗi lầnmake menuconfiglại hỏi tùy chọn; rồi package thứ 16 trong 23 package thất bại theo kiểu “cái này cần cái kia, cái kia cần Fubar3.32.1, nhưng Fubar3 đã bị deprecated để chuyển sang Fubar4”, nên tôi bỏ cuộcTôi hiểu các developer của Core OS không thể hỗ trợ hơn 10.000 package, nhưng cũng cần nói rõ rằng khi thực sự bật các tính năng tùy chỉnh để dùng thì xác suất thất bại là cao. Hoặc tốt hơn là đặt tiêu chí rằng trước khi xuất hiện trong ports, bản build chuẩn được tạo độc lập phải thành công; cái nào không biên dịch được thì loại khỏi danh sách ports
Có thể phê bình ngôn ngữ Nix hàng giờ liền, nhưng nó đã cũ, là nỗ lực tốt nhất vào thời đó, và giờ có thể không còn đáng để thay đổi lớn. Hệ thống build của Nix cho cảm giác khá thô sơ, và thường build lại cả những thứ trông như không cần build lại. Ví dụ, phần lớn quá trình build ISO cài đặt NixOS phụ thuộc vào dòng lệnh truyền cho kernel
console=ttyS2,1500000n8, nên chỉ đổi tốc độ cổng serial cũng cần khoảng 3 phút build. Buồn cười thật, nhưng tôi sẽ không vì thế mà bỏ Nix; chỉ là trong build của tôi thì tôi sẽ không cho phép chuyện đóCá nhân tôi cho rằng Nix cho Docker image là lĩnh vực Nix làm kém nhất. Từ lâu, khi làm phần mềm Go, tôi cần thêm binary
pg_dumpcủa Postgres vào container image; theo đề xuất của đội hạ tầng, tôi dùng Nix, và image chứa binary Go nén 50MB phình thành 1,5GB không rõ vì sao.pg_dumpchỉ 464KB. Cuối cùng tôi dùng Bazel vàrules_debianđể cài apt package, chạy trên distroless thì gọn gàng và nhỏ hơn nhiều. Dựa trên trải nghiệm Nix thực tế, hệ thống Nix lúc nào cũng có cảm giác thành 1,4GB. ISO cài đặt cũng 1,4GB, máy vừa cài xong cũng 1,4GBTình huống muốn build một dự án C++ lớn vốn đã là con đường được dọn sẵn, và đổi C++ thành Rust về bản chất cũng không khác. Có những build system giúp tình hình thư viện bớt đau đớn hơn; chúng cũng phức tạp như Nix, nhưng có cái phù hợp hơn cho mục đích này. Vì Nix cố trở thành build system để build phần mềm của người khác và nixpkgs, nó nằm ở phía rất tổng quát. Build system được thiết kế để build phần mềm của chính bạn thường làm việc đó tốt hơn. Cá nhân tôi hài lòng với Bazel, và ngoài
go buildcho dự án chỉ dùng Go thì có lẽ tôi gần như không dùng gì khác; nhưng có rất nhiều lựa chọn. Trong 99% trường hợp, hãy dùng những thứ đó thay Nix, rồi viết flake để mọi người có thể cài phiên bản mới nhất bằng home-managerPhần chọn phiên bản nghe hơi kỳ lạ. Phiên bản của nixpkgs thì có ý nghĩa khi chạy hoặc build hệ thống, nhưng nếu cung cấp runtime hay compiler với tư cách một nền tảng thì cần cách cung cấp phiên bản trực tiếp như devenv
Nếu build một hệ thống cũ để cung cấp nodejs cũ, bạn sẽ bỏ lỡ các bản vá bảo mật của dependency. Chẳng hạn Devenv xử lý bằng cách dùng https://github.com/cachix/nixpkgs-python để “giữ mọi phiên bản Python luôn mới nhất theo từng giờ bằng Nix”
Việc Railway inject biến môi trường ID triển khai vào mọi build lẽ ra có thể làm ở một layer sau bước cài đặt. Cũng có thể chia package thành nhiều layer, và còn có tự động hóa theo cụm để giảm số lượng layer
“Bản thân Nix không có vấn đề, vấn đề nằm ở cách chúng tôi dùng nó” là một ví dụ hay cho việc dùng đúng công cụ cho đúng việc. Nix tuyệt vời cho một số mục đích, và tệ hại cho những mục đích khác
Vấn đề là đường cong học Nix quá dốc, nên đến lúc hiểu đủ để đánh giá thì bạn đã đầu tư quá nhiều thời gian, cảm thấy tiếc nếu quay lại, rồi cố gò nó vào để giải quyết nhu cầu ban đầu
Chính mô thức này khiến AI rất dễ tạo
shell.nixhoặcconfiguration.nixđúng theo đặc tả. Ví dụ có thể chứa package Python, package Linux, biến môi trường, mục đường dẫn, v.v.Tôi thường dùng thứ này để đưa vào repository một môi trường hỗ trợ đầy đủ package đó. Dùng flakes thì sẽ tái lập được tốt hơn, nhưng tôi hiểu
flake.nixgiống nhưshell.nixcó pin phiên bản, và vẫn đang học thêmTrông như đang cố nhét phiên bản vào nơi vốn không có phiên bản. Giống như nhét một khối vuông vào lỗ tròn
“Phiên bản mặc định” làm hỏng những thứ phụ thuộc vào nó là sao, tôi không hiểu. Nó giống như dùng tag
:latestcủa Docker rồi ngạc nhiên khi mỗi lần server mới bật lên lại hỏng vì khác phiên bản so với image “mặc định” trước đóTôi chẳng hiểu nổi phần giải thích nào trong bài blog này. Trông như những người hoàn toàn không biết “phiên bản” của phần mềm là gì
Câu “không có cách nào tách dependency Nix thành layer riêng” cũng không hiểu vì sao. Tất nhiên có thể chia
/nix/storethành bao nhiêu layer tùy cần. Tôi còn nghi họ có biết container và Nix được dùng thế nào ngay từ đầu khôngNhìn sự non tay rõ ràng như vậy, cũng không ngạc nhiên khi giải pháp họ đề xuất có mùi cá ươn. Đây là hội chứng NIH điển hình, và rất có khả năng những vấn đề tương tự mà họ không giải được bằng Nix sẽ lan nguyên sang “giải pháp” mới
Như những người khác đã nói, nix2container và flakes có vẻ sẽ giải quyết mọi vấn đề của họ
Về quản lý phiên bản, flakes tôi viết 3 năm trước đến nay vẫn build ra đúng cùng phiên bản và cùng output như lúc mới viết
Nghe có vẻ như họ đang muốn ra thị trường như một nền tảng để gọi vốn
Chỉnh sửa: Tôi vừa xem GitHub của nixpacks, và điều lập tức đập vào mắt là họ dùng
rustPlatformcủa nixpkgs thay vì rust-overlay[0] của oxalica, thứ lẽ ra chỉ cần tìm sơ qua về vấn đề Rust là thấy.rust-overlaylà một trong những overlay hữu ích và mạnh mẽ nhất mà tôi từng dùng[0] https://github.com/oxalica/rust-overlay
nix2container[1] thực sự có thể tách dependency thành layer riêng. Bạn có thể tạo rõ ràng một layer chỉ chứa một phần dependency cần cho image, và ví dụ cũng có trong mục này: https://github.com/nlewo/nix2container?tab=readme-ov-file#is...Ví dụ nếu các image dùng bash, bạn có thể tạo rõ ràng một layer chứa closure của bash. Layer này sẽ được tái sử dụng trong mọi image, và chỉ được build lại, push lại khi closure bash đó thay đổi
Việc image phình to vì một layer
/nix/storeduy nhất đúng với hàmnixpkgs.dockerTools.buildImagemặc định, nhưng không đúng với nix2container haynixpkgs.dockerTools.streamLayeredImage. Các công cụ này không ghi layer vào Nix store, mà dùng các store path hiện có để tạo script thực sự push image. Triển khai của nix2container tạo một file JSON mô tả các Nix store path của mọi layer, rồi Skopeo tiêu thụ JSON này để push image lên Docker daemon, registry, podman, v.v.Nhân tiện, tôi là tác giả của nix2container
[1] https://github.com/nlewo/nix2container
Vấn đề cốt lõi ở đây là bám vào thái độ món súp phiên bản tùy biến mà các trình quản lý package theo ngôn ngữ cổ vũ. Cách này hoàn toàn không bền vững
Phương án thay thế Mise dường như không có khả năng hiểu ràng buộc phiên bản giữa các package, và có vẻ cũng không chạy test để xem từng package đã cài có hoạt động tốt với các phiên bản xung quanh hay không. Vậy thì bạn không hề nhận được cùng một thứ
“Món súp phiên bản tùy biến” là không bền vững, nhưng một trong những lý do mọi người vẫn tiếp tục dùng là vì nhìn chung nó hoạt động tốt. Một trong những lý do nó hoạt động tốt là các thư viện cấp hệ điều hành đến từ một thế giới khác, bảo thủ hơn nhiều, và cố gắng tối đa để tránh phá vỡ tương thích ngược
Vì vậy, có thể lấy một hệ điều hành ổn định và được quản lý tốt làm nền, rồi chồng lên đó “món súp phiên bản tùy biến” của công cụ và runtime ngôn ngữ bằng các công cụ như mise hoặc asdf, sau đó chạy ứng dụng. Nó hầu như không hỏng. Khi hỏng, ta chỉnh qua lại phiên bản và vài bản sửa nhỏ cho đến khi nó chạy lại rồi tiếp tục. Việc nó hỏng thì khó chịu, nhưng không quan trọng. Những thứ làm tăng ma sát, đòi hỏi học thêm hoặc cần nhiều việc hơn đều là lãng phí thời gian
Ngược lại, cũng có những người tìm giải pháp để nó không bao giờ hỏng nữa. Với họ, vấn đề này quan trọng, nên giải pháp có đòi hỏi ma sát, học hỏi và thêm công việc cũng không sao. Những người như vậy muốn Nix
Phần lớn thuộc nhóm đầu tiên, nên một công ty muốn tăng trưởng như Railway rốt cuộc sẽ chọn giải pháp phù hợp với nhóm đó
Cargo.locklà chuyện nhỏ. nixpkgs đi theo hướng ngược lại với “món súp phiên bản tùy biến”, nhưng bản thân Nix cũng xử lý được cách đó khá ổnTừ kinh nghiệm làm DevOps/SRE, khi ai đó cố xây một hệ thống quản lý dependency và những thứ tương tự, thường họ đi theo một trong hai hướng. Có thể lấy Python làm ví dụ
Lựa chọn 1: “Hãy dùng một kho đơn khối dùng chung thật lớn.” Ưu điểm là mọi thứ ở một chỗ, thứ cần có đều được đưa vào, mọi người dùng cùng một thứ nên dễ sửa các vấn đề như lỗ hổng. Nhược điểm là luôn có người muốn một phiên bản đặc biệt, triển khai theo từng giai đoạn khó nên thay đổi dễ thành kiểu big bang, và rồi sẽ xuất hiện câu hỏi “làm bản Docker nhỏ như thế nào?”
Lựa chọn 2: “Mỗi người có conda/venv của riêng mình.” Ưu điểm là ai cũng có đúng thứ mình muốn, không dùng các package không cần thiết, và nâng cấp từng bước dễ hơn. Nhược điểm là sẽ thành “rốt cuộc có bao nhiêu môi trường conda?”, các thư viện của những nhóm khác nhau có thể không được test với cùng tổ hợp thư viện Python, và thậm chí không biết các môi trường conda khác nhau nằm ở đâu nên quản lý lỗ hổng trở thành ác mộng
Vì vậy tôi luôn hoài nghi với câu “cách mới này giải quyết được tất cả”. Càng nhiều kinh nghiệm, câu “không có giải pháp, chỉ có đánh đổi” càng ngày càng đúng
Dù chỉ có chút kinh nghiệm với Nix, tôi thấy các luận điểm ở đây không có vẻ đúng lắm
Có câu “không rõ ràng hoặc khó bảo trì đối với contributor chưa quen với cách quản lý phiên bản của Nix”, và “Node và Python đã chỉ còn hỗ trợ các major version mới nhất”, nhưng tôi không hiểu vì sao điều này lại không thể bảo trì. Nếu lý do là phải tạo danh sách các phiên bản có thể dùng, thì tôi thắc mắc liệu không thể tự động hóa được sao
Hơn nữa, tôi cũng không hiểu vì sao Railway lại định nghĩa cách người dùng dùng Nix. Một trong những điểm cốt lõi của Nix chẳng phải là có thể cấu hình một máy trống với đúng phiên bản các package mình muốn sao. Tôi không hiểu vì sao Railway phải chen vào giữa người dùng và các phiên bản đó để giới hạn
Nếu kiến trúc là không cho người dùng thấy trực tiếp Nix, thì câu hỏi ban đầu vẫn còn đó. Không thể tự động hóa danh sách phiên bản package sao?
Thành thật mà nói, các lý do đưa ra trông không vững lắm. Có lẽ người đưa Nix vào đã rời đi, và những người còn lại không thích nó cho lắm. Bản thân ngôn ngữ cũng không thật sự tốt, tài liệu cũ cũng không xuất sắc
Dù vậy, tôi không biết đủ về stack họ chọn, nhưng tôi tò mò liệu nó có cung cấp mức tính quyết định gần với Nix hay không. Nếu không, sau này nó có thể gây vướng víu hoặc làm vận hành khó hơn
/nix/storeduy nhất, trong đó có tất cả package và thư viện liên quan đến Nix cần cho build và runtime”Câu này giống như nói “không thể làm ô tô chạy về phía trước nên bỏ ô tô”. Đây là một trong những việc Nix làm ổn định nhất. Nó tự động phát hiện dependency runtime thực sự được tham chiếu từ binary kết quả bằng cách khớp chuỗi hash trong
/nix/storeNếu họ không làm được việc đó thì hoặc là đang dùng theo cách khá kỳ lạ, hoặc là đã làm sai nghiêm trọng. Thậm chí tôi khó nghĩ ra cách nào để ngăn Nix tự động giải quyết việc này
Vì vậy tôi sẽ không quá coi trọng trải nghiệm Nix của họ. Nội dung về quản lý phiên bản là vấn đề rất phổ biến mà ai cũng gặp, nên nếu họ thử giải quyết thì đã thú vị hơn
Nix không cung cấp bảo đảm về phiên bản tùy ý, mà cung cấp bảo đảm theo commit. Khi gặp edge case, họ sẽ khổ vì thay đổi glibc hoặc các shared library xung đột
Có lẽ hơi muộn, nhưng tôi sẵn lòng cung cấp tư vấn để làm cho nó hoạt động theo cách idiomatic của Nix. Sản phẩm trông rất hay
Không chỉ vậy, còn tiếp tục đến dependency của dependency, rồi dependency của dependency đó, nên các đợt rebuild lớn xảy ra thường xuyên
Nó sẽ tránh được xung đột shared library, nhưng giải pháp này cực kỳ lãng phí và có thể khiến việc phát triển rất đau đớn. Nhìn vào quy trình staging của nixpkgs là thấy
Dù vậy, có lẽ nó vẫn sẽ ở trạng thái “được đóng gói với khả năng hoạt động đúng cao” hơn 95% phần mềm trên đời
Tôi không hiểu vì sao họ không thể tạo derivation riêng thay vì phụ thuộc vào hash của nixpkgs