더 작은 NixOS ISO를 만들 수 있을까?
(natkr.com)- NixOS는 설정만으로 VM이나 ISO를 만들기 쉽지만, 최소에 가까운 라이브 이미지도 처음부터 458MiB로 생성되어 Alpine VM ISO 약 66MiB와 큰 차이를 보임
- 크기의 대부분은 nix-store.squashfs가 차지했고, 그 안에는 Python 3.13.13, Linux modules, systemd, Perl, GRUB, 문서, Nix 관련 의존성이 들어 있었음
nix.enable = false,documentation.enable = false,register-nix-paths제거를 거치며 ISO는 458MiB → 384MiB → 360MiB로 줄었고 Boost 의존성도 빠짐- OpenSSH 클라이언트, 기본 패키지, GRUB 설치 도구, 런타임 커널 모듈, Perl 기반 활성화 경로까지 걷어내 최종 크기는 183MiB까지 내려감
- 작은 실험용 부팅 이미지에는 참고할 만하지만, 필요한 기능을 많이 제거하므로 데스크톱이나 중요한 환경에 그대로 쓰기는 어려움
NixOS 설정에서 ISO 만들기
- NixOS는 설정을 기반으로 VM을 쉽게 만들 수 있음
nixos-rebuild build-vm은 현재 시스템 설정의 VM을 생성함pkgs.nixos를 사용하면 시스템 설정이 아니더라도 임의 설정으로 VM을 만들 수 있음
- 기본 예시는
system.stateVersion = "26.05"와services.getty.autologinUser = "root"만 둔 최소 VM을 생성함 - 이 VM은 thin VM으로 동작함
- 디스크 이미지에는 VM 안에서 직접 만든 파일만 들어감
/nix/store등 나머지는 호스트 OS에서 마운트됨
- 호스트에 Nix가 없거나 원격 호스트, 일반 하이퍼바이저에서 실행하려면 자체 포함 ISO가 필요함
- NixOS의
iso-image.nix모듈을 import하면 ISO를 빌드할 수 있음image.baseName = lib.mkForce "nixos"로 출력 ISO 이름을 지정함- 실행 예시는
qemu-system-x86_64 --cdrom .../nixos.iso -m 1G --accel kvm형태임 - amd64의 현대 Linux 환경이 아니라면 아키텍처나 가속 방식 변경이 필요할 수 있음
시작점: 458MiB ISO
- 기본 ISO 빌드 결과는 458MiB였음
- 이 이미지는 아직
vim도 포함하지 않음- 부팅 후
vim실행 시command not found가 나옴
- 부팅 후
- 비교 대상으로 든 Alpine의 VM ISO는 약 66MiB임
- Damn Small Linux는 훨씬 작은 크기로 완성도 있는 데스크톱 환경을 제공했던 사례로 등장함
- 목표는 Damn Small Linux 수준에 도달하는 것이 아니라, NixOS ISO를 어느 정도라도 더 줄일 수 있는지 확인하는 데 있음
ISO 내부 크기 분석
- ISO를 마운트해
du로 확인하니 크기는 다음처럼 나뉨nix-store.squashfs: 416MiB- initrd: 26MiB
- kernel: 13MiB
- 전체 ISO: 458MiB
- 핵심 크기 요인은 주 사용자 공간인
nix-store.squashfs였음 - squashfs를 마운트하면 Nix store처럼 보이는 경로들이 들어 있음
python3-3.13.13: 128MiBlinux-6.18.35-modules: 144MiBsystemd-260.1: 60MiBperl-5.42.0: 56MiBgrub-2.12: 여러 항목 합산 약 62MiBnix-manual-2.34.7,nixos-manual-html등 문서도 포함됨
- ISO는 호스트에서 빌드되므로, ISO 안의 store 경로는 호스트
/nix/store에서도 추적할 수 있음 nix why-depends로 의존성의 출처를 확인함- Boost는 Nix daemon 경로를 통해 들어왔음
nix-daemon.conf,nix,libnixutil.so를 거쳐boost-1.89.0에 도달함
Nix와 문서 제거
nix.enable = false로 Nix 자체를 이미지에서 제거하려고 시도함documentation.enable = false로 문서도 비활성화함- 첫 결과는 458MiB → 384MiB였음
- 하지만 Boost는 여전히 남아 있었음
register-nix-paths.service가 ISO store 내용을 부팅 시 등록하려고 함- 이 경로가 다시 Nix와 Boost를 끌어옴
systemd.services.register-nix-paths = lib.mkForce {}로 해당 서비스를 비워 제거함- 그 결과 ISO는 360MiB가 되었고,
nix why-depends에서 Boost 의존성이 없다고 확인됨
OpenSSH와 기본 패키지 제거
- 비슷한 방식으로
environment.defaultPackages도 비울 수 있었음 ssh제거는 더 까다로웠음modules/programs/ssh.nix가 OpenSSH를environment.corePackages에 추가함- 이를 제어할
programs.ssh.enable같은 옵션을 찾을 수 없었음 services.openssh.enable은 서버 설정이지 클라이언트 제거 옵션이 아님
disabledModules로programs/ssh.nix를 제외할 수는 있었지만, 다른 모듈들이programs.ssh옵션 존재를 기대해 연쇄 오류가 발생함- 해결책은
programs.ssh옵션을 쓰지 않는 stub 옵션을 별도 모듈로 제공하는 방식이었음options.programs.ssh = lib.mkOption {};- 이후
disabledModules = [ "programs/ssh.nix" ];로 실제 SSH 모듈을 제외함
- 이 과정에서 다음 설정도 함께 적용함
documentation.man.enable = falsenetworking.firewall.enable = falseenvironment.defaultPackages = lib.mkForce []
NixOS 모듈 구조 메모
- NixOS 모듈은 크게 세 부분을 가짐
- 모듈 수준 항목:
imports,disabledModules - 옵션 정의:
options.* - 구현:
config.*
- 모듈 수준 항목:
- 옵션을 정의하지 않는 모듈은
config.접두어 없이 구현 속성을 쓰는 축약형을 사용할 수 있음 - 나머지 설정에서 축약형을 유지하기 위해,
programs.sshstub 옵션은 별도 import 모듈로 분리함
GRUB 설치 도구 제거
- 남은 큰 항목 중 하나는 약 62MiB의 GRUB 관련 파일이었음
- 부트로더 자체는 필요하지만, 설치 도구를 모두 포함할 필요는 없다고 판단함
- NixOS ISO preset은 UEFI와 BIOS 버전 GRUB를 모두 번들함
- 이를 끄는 명확한 옵션은 없어, 더 거친 방식으로 다음 값을 재설정함
system.extraDependencies = lib.mkForce []environment.systemPackages = lib.mkForce config.environment.corePackages
environment.systemPackages를 완전히 비우지는 않음bash가 없으면 getty가 계속 crashloop할 수 있어, 셸이 어느 정도 동작하도록corePackages는 유지함
커널 모듈 제거
linux-6.18.35-modules는 144MiB였고, 전체 크기의 약 4분의 1에 해당함- NixOS에는 런타임에 사용할 커널 모듈을 제한하는 좋은 훅이 보이지 않았음
- 대신 시스템 출력에서
kernel-modules폴더를 제거함system.systemBuilderCommands = lib.mkAfter "rm $out/kernel-modules";
- 이 방식은 런타임 모듈 로딩을 사실상 비활성화함
- 필요한 모듈은
boot.initrd.kernelModules또는availableKernelModules에 넣어야 함
- 필요한 모듈은
- 이 변경 뒤 더 편한 디스플레이 해상도로 전환하는 기능을 잃었지만, 부팅은 가능했음
- ISO 크기는 197MiB까지 내려감
Perl 제거와 실험적 대체 기능
- 여전히 56MiB의 Perl이 포함되어 있었음
nix why-depends로 확인하니 Perl은 시스템 활성화 중 사용자와/etc를 구성하는 데 쓰였음- 사용자와
/etc구성을 완전히 버릴 수는 없었음 - 대신 실험적 기능으로 기존 경로를 대체함
/etc관리는 overlay 방식 사용- 사용자 관리는 native userborn 사용
- 적용한 설정은 다음과 같음
system.etc.overlay.enable = truesystem.etc.overlay.mutable = falseservices.userborn.enable = true
- 최종 ISO 크기는 183MiB가 됨
최종 상태와 한계
- 시작점 458MiB에서 최종 183MiB까지 줄어, 원본의 거의 3분의 1 수준이 됨
- 그래도 결과를 “좋다”고 부르기는 어렵다고 봄
- 실제로 사용해야 하는 데스크톱이나 중요한 환경에는 적합하지 않음
- 제거한 기능들은 모두 존재 이유가 있음
- 작은 실험용 부팅 이미지가 필요하고 아주 작은 작업만 수행하면 되는 경우에는 참고할 수 있음
- 최종 설정을 그대로 복사해 쓰면 목적에 필요한 기능이 빠져 있을 수 있음
더 줄일 여지
- 이번 작업은 “그냥 제거 가능”하거나 비교적 명확한 대체 수단이 있는 항목에 집중함
- 더 깊은 작업이 필요한 영역도 남아 있음
- 현재
systemdMinimal과systemd가 모두 번들됨 - 둘 중 하나를 제거하려고 하면 다른 빌드 경로가 깨졌음
- 현재
- 작은 항목들도 더 걷어낼 수 있고, 합산하면 의미 있는 크기가 될 수 있음
- 추가 최적화에는 더 많은 조사와 실험이 필요함
댓글과 토론
Lobste.rs 의견들
-
딱 이런 용도로 만든 모듈이 있음. 컴파일은 꽤 필요하지만, NixOS 사용자 공간 전체를 포함한 완전 독립형 initrd를 zstd 압축 기준 약 80MiB로 만들 수 있음
이 작업은 독립형 initrd에만 한정되지 않고, 어떤 NixOS든 용량을 줄이는 데 쓸 수 있음. 설치 ISO에도 아마 적용 가능할 것 같음
https://github.com/wucke13/minimal-nixos/ -
TinyCore Linux 기본 시스템은 17MB인 Core임
X와 FLTK/FLWM까지 원하면 23MB인 TinyCore이고, 더 많은 창 관리자와 앱까지 원하면 248MB인 CorePlus가 있음
http://www.tinycorelinux.net/downloads.html- 그게 선언형 설정이나 재현 가능한 VM과 어떤 관련이 있는지 모르겠음
-
NixCon에서 NixOS를 Yocto 대안으로 작게 줄인 발표를 추천함: https://youtu.be/AsXY61laNb8
기대한 만큼 자세하진 않았지만, 컨퍼런스에서 Óli와 Matthew에게 직접 들은 내용은 굉장했음. 혹시 정리 글이 있는지 궁금함 -
NixOS에서 작은 설치 공간을 만들려면 항상 조금 답답함
SSH 쪽 크기는 아래 설정으로 줄일 수 있을 것 같음programs.ssh.setXAuthLocation = false; security.pam.services.su.forwardXAuth = lib.mkForce false; fonts.fontconfig.enable = false;"${nixpkgs}/nixos/modules/profiles/minimal.nix"도 가져올 수 있음. 거기에 글에서 한 최적화 일부가 들어 있음- 원래 글을 쓰게 된 사용 사례에서는 사실 ssh 자체가 거의 필요 없었음
그래도 대부분의 경우에는 이 방식이 더 합리적일 가능성이 큼
"${nixpkgs}/nixos/modules/profiles/minimal.nix"는 예전에 보고 기대보다 별로라고 느껴서, 조사를 시작할 때 포함할 생각을 못 했음. 나중에 떠올렸을 때는 이미 절반쯤 진행한 뒤라, 원래 들어갔어야 할 초반에 끼워 넣는 건 조금 정직하지 않게 느껴졌음
- 원래 글을 쓰게 된 사용 사례에서는 사실 ssh 자체가 거의 필요 없었음
-
요즘 시스템에 Perl이 끌려 들어오는 경우가 너무 많아서 이상함. 작은 ISO에도 Perl, 뭔가 제대로 된 걸 처음부터 컴파일하려 해도 openssl -> Perl로 이어짐
- 기본 시스템에서 Perl 의존성을 줄이고 더 엄격히 제한하려는 작업이 있음: https://github.com/NixOS/nixpkgs/…
-
읽기 전부터, 누가 C로 다시 쓰지 않은 멍청한 Perl 스크립트 때문일 거라고 예상함
수정: 역시 맞았음 -
NixOS는 26.05부터 기본 initrd에서 systemd를 사용함. 현대 운영체제가 지원해야 하는 initrd 사용 사례가 많기 때문임
systemdMinimal은 더 적은 플래그와 의존성으로 컴파일한 systemd 바이너리라 initrd를 더 작게 유지하는 데 도움이 됨
다만 최소 ISO가 목표라면 둘 다 같은 바이너리에 의존하게 만들 수도 있어 보임