Storage optimization: Difference between revisions
imported>Appetrosyan m Grammar + explained trailing slashes |
imported>Appetrosyan Consistency improvements, style. Used more templates. All commands now have the appropriate privilege indicator. |
||
| Line 1: | Line 1: | ||
A recurring problem with NixOS is lack of space on <code>/</code>. Even if you only ocasionally use Nix, it is easy for <code>/nix/store</code> to grow beyond | A recurring problem with NixOS is lack of space on <code>/</code>. Even if you only ocasionally use Nix, it is easy for <code>/nix/store</code> to grow beyond reasonable sizes. What follows are generic notes on how to reduce the growth of the {{nix:store}}. | ||
== | == Optimising the store == | ||
Here we demonstrate how to configure <code>nix</code> to save space via hardlinking store files. | |||
==== | ==== Automatic ==== | ||
< | To turn on automatic optimisation for newer derivations, add the following option to <code>/etc/nixos/configuration.nix</code>: | ||
{{file|configuration.nix|nix|<nowiki> | |||
nix.autoOptimiseStore = true; | nix.autoOptimiseStore = true; | ||
</ | </nowiki>}} | ||
{{Tip|This option only applies to new files: so we recommend manually optimising your nix store in addition to this option.}} | |||
==== | ==== Manual ==== | ||
Run | Run | ||
{{ic|# nix-store --optimise}} | |||
This is a potentially long operation. | |||
== Garbage collection == | == Garbage collection == | ||
The Nix store | The Nix store accumulates entries which are no longer useful.<ref group="cf.">[https://nixos.org/nix/manual/#sec-garbage-collection Nix Manual, 11. Garbage Collection]</ref> They can be deleted with {{ic|nix-collect-garbage -d}} <ref group="cf.">{{man|nix-collect-garbage|sec=1}}</ref> or {{ic|nix-store --gc}}.<ref group="cf.">{{man|nix-store|sec=1}}, under {{ic|OPERATION --GC}}</ref> | ||
Note that if a result file still exists in the file system, and your Nix configuration has both <code>keep-outputs = true</code> and <code>keep-derivations = true</code>, all the dependencies used to build it will be kept. To see which result files prevent garbage collection, run: | Note that if a result file still exists in the file system, and your Nix configuration has both <code>keep-outputs = true</code> and <code>keep-derivations = true</code>, all the dependencies used to build it will be kept. To see which result files prevent garbage collection, run: | ||
| Line 50: | Line 53: | ||
GC roots can be found in <code>/nix/var/nix/gcroots</code>. The following script demonstrates how this directory can be used to (for example) query the state of manually made result symlinks: | GC roots can be found in <code>/nix/var/nix/gcroots</code>. The following script demonstrates how this directory can be used to (for example) query the state of manually made result symlinks: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="console"> | ||
find -H /nix/var/nix/gcroots/auto -type l | xargs -I {} sh -c 'readlink {}; realpath {}; echo' | $ find -H /nix/var/nix/gcroots/auto -type l | xargs -I {} sh -c 'readlink {}; realpath {}; echo' | ||
</syntaxhighlight> | </syntaxhighlight> | ||
This acts a simpler (but faster) version of <code>--print-roots</code> and could be implemented as a bash alias for convenience. | This acts a simpler (but faster) version of <code>--print-roots</code> and could be implemented as a bash alias for convenience. | ||
{{Tip| | |||
<code>nix-collect-garbage -d</code> operates only for the current user. To clear system profiles, run it with root privileges. | <code>nix-collect-garbage -d</code> operates only for the current user. To clear system profiles, run it with root privileges. | ||
}} | |||
=== Look for <code>result</code> symlinks === | === Look for <code>result</code> symlinks === | ||
| Line 112: | Line 116: | ||
=== Automation === | === Automation === | ||
Garbage collection can be automated,<ref group="cf.">{{nixos:option|nix.gc}}</ref> for example: | |||
< | {{file|configuration.nix|nix|<nowiki> | ||
nix.gc = { | nix.gc = { | ||
automatic = true; | automatic = true; | ||
| Line 120: | Line 124: | ||
options = "--delete-older-than 30d"; | options = "--delete-older-than 30d"; | ||
}; | }; | ||
</ | </nowiki>}} | ||
This can result in redownloads (tarballs fetched with <code>import (builtins.fetchTarball ...)</code> for example are not referenced anywhere and removed on GC), but it frees you from runnning GC manually. | This can result in redownloads (tarballs fetched with <code>import (builtins.fetchTarball ...)</code> for example are not referenced anywhere and removed on GC), but it frees you from runnning GC manually. | ||
| Line 136: | Line 140: | ||
== Moving the store == | == Moving the store == | ||
{{ic|/nix}} can reside on another device | {{ic|/nix}} can reside on another device, which is useful if your root device is very small, and you have another, larger drive available. | ||
If the | If the new partition is on the same device, some benefit can be gained by formatting the partition on which {{ic|nix}} resides with a different file system. For example: on a Raspberry Pi, {{ic|f2fs}} could be used for a gain in I/O throughput. | ||
Regardless of <code>/nix</code>'s filesystem, it can also be mounted with <code>noatime</code> (as seen in the example below). This will reduce metadata writes, improving I/O and the device's lifespan. | Regardless of <code>/nix</code>'s filesystem, it can also be mounted with <code>noatime</code> (as seen in the example below). This will reduce metadata writes, improving I/O and the device's lifespan. | ||
| Line 147: | Line 151: | ||
# Create a new partition | # Create a new partition | ||
# Mount this new partition over <code>/mnt</code> <syntaxhighlight lang=" | # Mount this new partition over <code>/mnt</code> <syntaxhighlight lang="console"> | ||
mount /dev/disk/by-label/nix /mnt | # mount /dev/disk/by-label/nix /mnt | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Copy everything from <code>/nix</code> to <code>/mnt</code> ''Trailing slashes are important'', in that without them, <code>rsync</code> will create an additional directory of the same name at the destination. | # Copy everything from <code>/nix</code> to <code>/mnt</code> ''Trailing slashes are important'', in that without them, <code>rsync</code> will create an additional directory of the same name at the destination. <syntaxhighlight lang="console"> | ||
rsync --archive --acls --one-file-system --verbose /nix/store/ /mnt/store | # rsync --archive --acls --one-file-system --verbose /nix/store/ /mnt/store | ||
rsync --archive --acls --one-file-system --verbose /nix/var/ /mnt/var | # rsync --archive --acls --one-file-system --verbose /nix/var/ /mnt/var | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# | # Mount the new partition as the new <code>/nix</code> <syntaxhighlight lang="console"> | ||
umount /mnt | # umount /mnt | ||
mount /dev/disk/by-label/nix /nix | # mount /dev/disk/by-label/nix /nix | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Restart nix daemon <syntaxhighlight lang=" | # Restart {{ic|nix-daemon}} <syntaxhighlight lang="console"> | ||
systemctl stop nix-daemon.service | $ systemctl stop nix-daemon.service | ||
systemctl restart nix-daemon.socket | $ systemctl restart nix-daemon.socket | ||
systemctl start nix-daemon.service | $ systemctl start nix-daemon.service | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Add | # Add the new <code>/nix</code> partition to your <code>/etc/nixos/configuration.nix</code> <syntaxhighlight lang="nix"> | ||
{ | { | ||
# ... | # ... | ||
| Line 172: | Line 176: | ||
options = [ "noatime" ]; | options = [ "noatime" ]; | ||
}; | }; | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Apply your configuration <syntaxhighlight lang=" | # Apply your configuration <syntaxhighlight lang="console"> | ||
nixos-rebuild switch | # nixos-rebuild switch | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Reboot to be sure <code>/nix/store</code> is properly mounted | # Reboot to be sure <code>/nix/store</code> is properly mounted | ||
''Optionally'' | ''Optionally'' | ||
# After reboot, check that <code>/nix</code> is mounted over your partition <syntaxhighlight lang=" | # After reboot, check that <code>/nix</code> is mounted over your partition <syntaxhighlight lang="console"> | ||
mount | grep "/nix" && echo "Nix | # mount | grep "/nix" && echo "Nix store is on a new partition" || echo "Nix is on the old partition" | ||
</syntaxhighlight> | </syntaxhighlight> | ||
# Once '''you are sure''' everything works, you can delete the old store <syntaxhighlight lang=" | # Once '''you are sure''' everything works, you can delete the old store <syntaxhighlight lang="console"> | ||
mkdir /tmp/old_root | # mkdir /tmp/old_root | ||
mount --bind / /tmp/old_root | # mount --bind / /tmp/old_root | ||
rm --recursive /tmp/old_root/nix | # rm --recursive /tmp/old_root/nix | ||
umount /tmp/old_root | # umount /tmp/old_root | ||
rmdir /tmp/old_root | # rmdir /tmp/old_root | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Keep in mind that all commands like <code>mount</code> and <code>bash</code> point to some executable in <code>/nix/store</code> | {{Tip|Keep in mind that all commands like <code>mount</code> and <code>bash</code> point to some executable in <code>/nix/store</code>. It is possible to get locked out of a system if one mistakenly mounted an empty drive to {{ic|nix}}. }} | ||
== See also == | == See also == | ||
<references group="cf."/> | <references group="cf."/> | ||