Nix에서 Railpack으로 전환하는 이유

1 month ago 11

  • Railway는 기존 Nixpacks 대신 새로운 빌드 시스템인 Railpack을 출시함
  • Railpack은 버전 관리의 세분화, 더 작은 이미지 크기, 향상된 캐싱 등에서 기존 Nixpacks보다 우수한 기능을 제공함
  • Nixpacks의 커밋 기반 버전 관리 방식이 다양한 사용자 요구와 확장성에 한계를 드러냈음
  • Railpack은 BuildKit 통합, 비밀 환경 변수 보호, 다양한 언어 및 프레임워크 지원 등으로 빌드 환경의 안정성과 유연성을 개선함
  • 현재 Node, Python, Go, PHP, 정적 HTML을 지원하며, 계속해서 프레임워크 및 언어 지원을 확장 중임

개요 및 배경

  • Railway는 Railpack이라는 차세대 빌드 시스템을 공개함
  • Railpack은 Railway 플랫폼에서 1천4백만 개 이상의 앱을 Nixpacks로 빌드하면서 얻은 경험을 바탕으로 새롭게 개발한 도구임
  • 기존 Nixpacks는 전체 사용자의 80%에게 적합했지만, 20만 명 이상의 사용자가 제약 사항에 부딪혀 불편을 겪음
  • 사용자 기반 확장 및 지속가능한 빌드 환경을 위해 빅 업그레이드가 필요하다고 판단함

Railpack 주요 개선점

  • 버전 관리 세분화: 각 패키지에 대하여 major.minor.patch 단위의 세밀한 버전 지정을 지원하여, Nix의 불분명한 버전 방식의 한계를 극복함
  • 작은 이미지 크기: Node는 38%, Python은 77%까지 기본 빌드 이미지 크기를 줄여, 더 빠른 배포 경험 제공
  • 캐싱 강화: BuildKit과 직접적으로 통합하여, 레이어와 파일 시스템을 제어, 캐시 적중률 향상 및 환경별 캐시 공유 가능
  • 이미 railway.com과 중앙 서비스에 Railpack 빌드가 적용된 상태임

Nixpacks 사용상 문제점

  • Nix의 패키지 버전 관리 방식은 커밋 기반 구조로, 최신 major 버전만 제공하며, 각 버전은 nixpkgs 저장소의 특정 커밋에 대응됨
  • 작은 패치 버전까지 모두 수동 관리해야 하는 비효율성 존재, 기여자도 버전 관리가 직관적이지 않아 접근성 저하
  • Node나 Python과 같은 언어의 경우도 결국 최신 major 버전만 지원
  • 버전 업데이트 시 커밋 해시 변경으로 다른 패키지 버전까지 한꺼번에 영향을 받아, 사용자의 신뢰성 저하 및 예기치 않은 빌드 실패 발생 가능
  • Nixpacks의 경우 /nix/store 하나의 레이어에 모든 의존성이 포함되어, 이미지를 효과적으로 쪼개거나 크기를 줄이기가 어려움
  • 캐싱도 환경 변수 주입 시마다 레이어가 항상 invalidate되어, 캐시를 제대로 활용하지 못함

Nix 자체의 문제가 아닌 사용 방식의 한계

  • Nix 자체의 설계 문제가 아닌, Railway의 사용 및 추상화 방식이 문제점으로 작용함
  • 사용자가 Nix의 derivation 개념이나 내부 버전 구조를 이해하지 않아도 되도록 설계하려 했지만, 현실적으로 불가능하다고 판단함
  • 위와 같은 문제를 해결하기 위해 Railpack 개발을 진행함

Railpack의 기술적 아키텍처

  • Rust → Go로 코드베이스 변화: BuildKit 활용 및 생태계 대응력 강화를 위해 Go 언어로 전환함
  • BuildKit LLB 및 프론트엔드: 커스텀 BuildKit LLB와 프론트엔드를 직접 생성하여, 빌드 이미지의 구조를 정밀하게 통제함 → Node와 Python 기본 이미지가 Nixpacks 대비 대폭 경량화됨
  • Mise로 버전 관리: 패키지 설치 및 버전 해석에 Mise를 사용, 향후 다른 실행 파일 소스도 용이하게 지원 가능
  • 성공적으로 빌드한 경우, 해당 시점의 의존성 lock-in 적용 → Node 기본 버전이 22에서 24로 바뀌어도 기존 빌드는 깨지지 않음
  • BuildKit의 secret 기능을 활용하여, 환경 변수 보안/관리를 개선

Railpack 빌드 단계

  • Analyze: 코드 분석을 통해 필요한 패키지, 실행 커맨드, 시작 명령어 도출
  • Plan: JSON 직렬화 가능한 형태의 빌드 계획 생성 (여러 단계 포함, 각 단계는 이전 단계 결과나 전체 이미지에 의존함)
  • Generates: BuildKit의 빌드 그래프 생성 (입력/출력을 기준으로)

BuildKit을 활용한 전략적 빌드

  • Dockerfile이 직렬로 동작하는 반면, BuildKit은 여러 명령을 병렬적으로 처리, 각 단계별로 세밀한 입력/출력 통제
  • Railpack은 코드 분석 결과 모든 빌드 단계를 정의하고, 각 단계의 의존관계를 낮은 수준으로 상세 지정함
  • 이 계획을 BuildKit LLB 그래프로 변환 및 해결
  • 환경 변수 등 변경 시에는 해당 값의 해시값으로 파일을 마운트, 코드와 변수에 변화가 없으면 캐시 적중 보장
  • 결과적으로 이미지 생성 방식을 완벽하게 Railpack이 컨트롤 가능

Railpack 도입으로 가능한 새로운 기능

  • Vite, Astro, CRA, Angular 정적 사이트 빌드/배포를 무설정으로 지원
  • Railway UI와 빌드 과정의 긴밀한 통합
  • 언어 최신 버전 지원이 Railpack 자체 릴리스 없이도 가능함
  • 프로젝트별로 환경 간 캐싱 최적화 제공
  • 현재 Node, Python, Go, PHP, 정적 HTML을 지원하며, 프레임워크 및 언어 지원을 계속 확장 중임

오픈소스 및 미래 계획

  • Railpack은 Beta 상태로 공개 중이며, 활성화만 하면 즉시 활용 가능
  • 공식 문서 및 실제 코드, 공개 지원 창구까지 railpack.com에서 제공
  • 향후 널리 쓰이는 언어에 대한 심층 지원을 우선하며, 코어 API 및 추상화 수준 확립 이후 범위 확장 계획 있음

Read Entire Article