더 작은 NixOS ISO를 만들 수 있을까?
3 hours ago
3
- 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: 128MiB
- linux-6.18.35-modules: 144MiB
- systemd-260.1: 60MiB
- perl-5.42.0: 56MiB
- grub-2.12: 여러 항목 합산 약 62MiB
- nix-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 = false
- networking.firewall.enable = false
- environment.defaultPackages = lib.mkForce []
NixOS 모듈 구조 메모
- NixOS 모듈은 크게 세 부분을 가짐
- 모듈 수준 항목: imports, disabledModules
- 옵션 정의: options.*
- 구현: config.*
- 옵션을 정의하지 않는 모듈은 config. 접두어 없이 구현 속성을 쓰는 축약형을 사용할 수 있음
- 나머지 설정에서 축약형을 유지하기 위해, programs.ssh stub 옵션은 별도 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 = true
- system.etc.overlay.mutable = false
- services.userborn.enable = true
- 최종 ISO 크기는 183MiB가 됨
최종 상태와 한계
- 시작점 458MiB에서 최종 183MiB까지 줄어, 원본의 거의 3분의 1 수준이 됨
- 그래도 결과를 “좋다”고 부르기는 어렵다고 봄
- 실제로 사용해야 하는 데스크톱이나 중요한 환경에는 적합하지 않음
- 작은 실험용 부팅 이미지가 필요하고 아주 작은 작업만 수행하면 되는 경우에는 참고할 수 있음
- 최종 설정을 그대로 복사해 쓰면 목적에 필요한 기능이 빠져 있을 수 있음
더 줄일 여지
- 이번 작업은 “그냥 제거 가능”하거나 비교적 명확한 대체 수단이 있는 항목에 집중함
- 더 깊은 작업이 필요한 영역도 남아 있음
- 현재 systemdMinimal과 systemd가 모두 번들됨
- 둘 중 하나를 제거하려고 하면 다른 빌드 경로가 깨졌음
- 작은 항목들도 더 걷어낼 수 있고, 합산하면 의미 있는 크기가 될 수 있음
- 추가 최적화에는 더 많은 조사와 실험이 필요함
-
Homepage
-
Tech blog
- 더 작은 NixOS ISO를 만들 수 있을까?