mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-11 20:25:32 +03:00
nixos/qemu-vm: simplify building nix store image
Summary of this change: - Simplify code. - Stop a disk image from being cached in the binary cache. - Make erofs Nix Store image build in an acceptable time outside of testing environments (like `darwin.builder`). - Do not regress on performance for tests that use many store paths in their Nix store image. - Slightly longer startup time for tests where not many store paths are included in the image (these probably shouldn't use `useNixStoreImage` anyways). - Slightly longer startup time when inputs of VM do not change because the Nix store image is not cached anymore. Remove the `storeImage` built with make-disk-image.nix. This produced a separate derivation which is then cached in the binary cache. These types of images should be avoided because they gunk up the cache as they change frequently. Now all Nix store images, whether read-only or writable are based on the erofs image previously only used for read-only images. Additionally, simplify the way the erofs image is built by copying the paths to include to a separate directory and build the erofs image from there. Before this change, the list of Nix store paths to include in the Nix store image was converted to a complex regex that *excludes* all other paths from a potentially large Nix store. This previous approach suffers from two issues: 1. The regex is complex and, as admitted in the source code of the includes-to-excludes.py script, most likely contains at least one error. This means that it's unlikely that anyone will touch this piece of software again. 2. When the Nix store image is built from a large Nix store (like when you build the VM script to run outside of any testing context) this regex becomes painfully slow. There is at least one prominent use-case where this matters: `darwin.builder`. Benchmarking impressions: - Building Nix store via make-disk-image.nix takes ~25s - Building Nix store as an erofs image takes ~4s - Running nixosTests.qemu-vm-writable-store-image takes ~10s when building the erofs image with the regex vs ~14s when building by copying to a temporary directory. - nixosTests.gitlab which had the biggest gains from the initial erofs change takes the same time as before. - On a host with ~140k paths in /nix/store, building the erofs image with the regex takes 410s as opposed to 6s when copying to a temporary directory.
This commit is contained in:
parent
ff5889a84c
commit
289dd22132
2 changed files with 30 additions and 153 deletions
|
@ -134,32 +134,25 @@ let
|
|||
TMPDIR=$(mktemp -d nix-vm.XXXXXXXXXX --tmpdir)
|
||||
fi
|
||||
|
||||
${lib.optionalString (cfg.useNixStoreImage)
|
||||
(if cfg.writableStore
|
||||
then ''
|
||||
# Create a writable copy/snapshot of the store image.
|
||||
${qemu}/bin/qemu-img create -f qcow2 -F qcow2 -b ${storeImage}/nixos.qcow2 "$TMPDIR"/store.img
|
||||
''
|
||||
else ''
|
||||
(
|
||||
cd ${builtins.storeDir}
|
||||
${hostPkgs.erofs-utils}/bin/mkfs.erofs \
|
||||
--force-uid=0 \
|
||||
--force-gid=0 \
|
||||
-L ${nixStoreFilesystemLabel} \
|
||||
-U eb176051-bd15-49b7-9e6b-462e0b467019 \
|
||||
-T 0 \
|
||||
--exclude-regex="$(
|
||||
<${hostPkgs.closureInfo { rootPaths = [ config.system.build.toplevel regInfo ]; }}/store-paths \
|
||||
sed -e 's^.*/^^g' \
|
||||
| cut -c -10 \
|
||||
| ${hostPkgs.python3}/bin/python ${./includes-to-excludes.py} )" \
|
||||
"$TMPDIR"/store.img \
|
||||
. \
|
||||
</dev/null >/dev/null
|
||||
)
|
||||
''
|
||||
)
|
||||
${lib.optionalString (cfg.useNixStoreImage) ''
|
||||
echo "Creating Nix store image..."
|
||||
|
||||
${hostPkgs.gnutar}/bin/tar --create \
|
||||
--absolute-names \
|
||||
--verbatim-files-from \
|
||||
--transform 'flags=rSh;s|/nix/store/||' \
|
||||
--files-from ${hostPkgs.closureInfo { rootPaths = [ config.system.build.toplevel regInfo ]; }}/store-paths \
|
||||
| ${hostPkgs.erofs-utils}/bin/mkfs.erofs \
|
||||
--force-uid=0 \
|
||||
--force-gid=0 \
|
||||
-L ${nixStoreFilesystemLabel} \
|
||||
-U eb176051-bd15-49b7-9e6b-462e0b467019 \
|
||||
-T 0 \
|
||||
--tar=f \
|
||||
"$TMPDIR"/store.img
|
||||
|
||||
echo "Created Nix store image."
|
||||
''
|
||||
}
|
||||
|
||||
# Create a directory for exchanging data with the VM.
|
||||
|
@ -298,21 +291,6 @@ let
|
|||
OVMF = cfg.efi.OVMF;
|
||||
};
|
||||
|
||||
storeImage = import ../../lib/make-disk-image.nix {
|
||||
name = "nix-store-image";
|
||||
inherit pkgs config lib;
|
||||
additionalPaths = [ regInfo ];
|
||||
format = "qcow2";
|
||||
onlyNixStore = true;
|
||||
label = nixStoreFilesystemLabel;
|
||||
partitionTableType = "none";
|
||||
installBootLoader = false;
|
||||
touchEFIVars = false;
|
||||
diskSize = "auto";
|
||||
additionalSpace = "0M";
|
||||
copyChannel = false;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
@ -788,10 +766,14 @@ in
|
|||
this can drastically improve performance, but at the cost of
|
||||
disk space and image build time.
|
||||
|
||||
As an alternative, you can use a bootloader which will provide you
|
||||
with a full NixOS system image containing a Nix store and
|
||||
avoid mounting the host nix store through
|
||||
{option}`virtualisation.mountHostNixStore`.
|
||||
The Nix store image is built just-in-time right before the VM is
|
||||
started. Because it does not produce another derivation, the image is
|
||||
not cached between invocations and never lands in the store or binary
|
||||
cache.
|
||||
|
||||
If you want a full disk image with a partition table and a root
|
||||
filesystem instead of only a store image, enable
|
||||
{option}`virtualisation.useBootLoader` instead.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -1019,25 +1001,7 @@ in
|
|||
];
|
||||
|
||||
warnings =
|
||||
optional (
|
||||
cfg.writableStore &&
|
||||
cfg.useNixStoreImage &&
|
||||
opt.writableStore.highestPrio > lib.modules.defaultOverridePriority)
|
||||
''
|
||||
You have enabled ${opt.useNixStoreImage} = true,
|
||||
without setting ${opt.writableStore} = false.
|
||||
|
||||
This causes a store image to be written to the store, which is
|
||||
costly, especially for the binary cache, and because of the need
|
||||
for more frequent garbage collection.
|
||||
|
||||
If you really need this combination, you can set ${opt.writableStore}
|
||||
explicitly to true, incur the cost and make this warning go away.
|
||||
Otherwise, we recommend
|
||||
|
||||
${opt.writableStore} = false;
|
||||
''
|
||||
++ optional (cfg.directBoot.enable && cfg.useBootLoader)
|
||||
optional (cfg.directBoot.enable && cfg.useBootLoader)
|
||||
''
|
||||
You enabled direct boot and a bootloader, QEMU will not boot your bootloader, rendering
|
||||
`useBootLoader` useless. You might want to disable one of those options.
|
||||
|
@ -1050,8 +1014,6 @@ in
|
|||
boot.loader.grub.device = mkVMOverride (if cfg.useEFIBoot then "nodev" else cfg.bootLoaderDevice);
|
||||
boot.loader.grub.gfxmodeBios = with cfg.resolution; "${toString x}x${toString y}";
|
||||
|
||||
boot.initrd.kernelModules = optionals (cfg.useNixStoreImage && !cfg.writableStore) [ "erofs" ];
|
||||
|
||||
boot.loader.supportsInitrdSecrets = mkIf (!cfg.useBootLoader) (mkVMOverride false);
|
||||
|
||||
# After booting, register the closure of the paths in
|
||||
|
@ -1171,7 +1133,7 @@ in
|
|||
name = "nix-store";
|
||||
file = ''"$TMPDIR"/store.img'';
|
||||
deviceExtraOpts.bootindex = "2";
|
||||
driveExtraOpts.format = if cfg.writableStore then "qcow2" else "raw";
|
||||
driveExtraOpts.format = "raw";
|
||||
}])
|
||||
(imap0 (idx: _: {
|
||||
file = "$(pwd)/empty${toString idx}.qcow2";
|
||||
|
@ -1226,6 +1188,7 @@ in
|
|||
});
|
||||
"/nix/.ro-store" = lib.mkIf cfg.useNixStoreImage {
|
||||
device = "/dev/disk/by-label/${nixStoreFilesystemLabel}";
|
||||
fsType = "erofs";
|
||||
neededForBoot = true;
|
||||
options = [ "ro" ];
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue