-
-
Notifications
You must be signed in to change notification settings - Fork 14.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
darwin.builder: init #206951
darwin.builder: init #206951
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# darwin.builder {#sec-darwin-builder} | ||
|
||
`darwin.builder` provides a way to bootstrap a Linux builder on a macOS machine. | ||
|
||
This requires macOS version 12.4 or later. | ||
|
||
This also requires that port 22 on your machine is free (since Nix does not | ||
permit specifying a non-default SSH port for builders). | ||
|
||
You will also need to be a trusted user for your Nix installation. In other | ||
words, your `/etc/nix/nix.conf` should have something like: | ||
|
||
``` | ||
extra-trusted-users = <your username goes here> | ||
``` | ||
|
||
To launch the builder, run the following flake: | ||
|
||
```ShellSession | ||
$ nix run nixpkgs#darwin.builder | ||
``` | ||
|
||
That will prompt you to enter your `sudo` password: | ||
|
||
``` | ||
+ sudo --reset-timestamp /nix/store/…-install-credentials.sh ./keys | ||
Password: | ||
``` | ||
|
||
… so that it can install a private key used to `ssh` into the build server. | ||
After that the script will launch the virtual machine: | ||
|
||
``` | ||
<<< Welcome to NixOS 22.11.20220901.1bd8d11 (aarch64) - ttyAMA0 >>> | ||
|
||
Run 'nixos-help' for the NixOS manual. | ||
|
||
nixos login: | ||
``` | ||
|
||
> Note: When you need to stop the VM, type `Ctrl`-`a` + `c` to open the `qemu` | ||
> prompt and then type `quit` followed by `Enter` | ||
|
||
To delegate builds to the remote builder, add the following options to your | ||
`nix.conf` file: | ||
|
||
``` | ||
# - Replace ${ARCH} with either aarch64 or x86_64 to match your host machine | ||
# - Replace ${MAX_JOBS} with the maximum number of builds (pick 4 if you're not sure) | ||
builders = ssh-ng://builder@localhost ${ARCH}-linux /etc/nix/builder_ed25519 ${MAX_JOBS} - - - c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpCV2N4Yi9CbGFxdDFhdU90RStGOFFVV3JVb3RpQzVxQkorVXVFV2RWQ2Igcm9vdEBuaXhvcwo=' | ||
|
||
# Not strictly necessary, but this will reduce your disk utilization | ||
builders-use-substitutes = true | ||
``` | ||
|
||
… and then restart your Nix daemon to apply the change: | ||
|
||
```ShellSession | ||
$ sudo launchctl kickstart -k system/org.nixos.nix-daemon | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
-----BEGIN OPENSSH PRIVATE KEY----- | ||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW | ||
QyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmwAAAJASuMMnErjD | ||
JwAAAAtzc2gtZWQyNTUxOQAAACCQVnMW/wZWqrdWrjrRPhfEFFq1KLYguagSflLhFnVQmw | ||
AAAEDIN2VWFyggtoSPXcAFy8dtG1uAig8sCuyE21eMDt2GgJBWcxb/Blaqt1auOtE+F8QU | ||
WrUotiC5qBJ+UuEWdVCbAAAACnJvb3RAbml4b3MBAgM= | ||
-----END OPENSSH PRIVATE KEY----- | ||
Comment on lines
+1
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not in favor of hardcoding a private key. What alternatives do we have? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not aware of a good alternative here. However, in this case I think it's not an issue because this is only use as the SSH host key and not the client's key (which is still handled securely) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJBWcxb/Blaqt1auOtE+F8QUWrUotiC5qBJ+UuEWdVCb root@nixos |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,134 @@ | ||||||||||||||||||||||
{ config, pkgs, ... }: | ||||||||||||||||||||||
|
||||||||||||||||||||||
let | ||||||||||||||||||||||
keysDirectory = "/var/keys"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
user = "builder"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
keyType = "ed25519"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
in | ||||||||||||||||||||||
|
||||||||||||||||||||||
{ imports = [ | ||||||||||||||||||||||
../virtualisation/qemu-vm.nix | ||||||||||||||||||||||
]; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# The builder is not intended to be used interactively | ||||||||||||||||||||||
documentation.enable = false; | ||||||||||||||||||||||
|
||||||||||||||||||||||
environment.etc = { | ||||||||||||||||||||||
"ssh/ssh_host_ed25519_key" = { | ||||||||||||||||||||||
mode = "0600"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
source = ./keys/ssh_host_ed25519_key; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
"ssh/ssh_host_ed25519_key.pub" = { | ||||||||||||||||||||||
mode = "0644"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
source = ./keys/ssh_host_ed25519_key.pub; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# DNS fails for QEMU user networking (SLiRP) on macOS. See: | ||||||||||||||||||||||
# | ||||||||||||||||||||||
# https://github.com/utmapp/UTM/issues/2353 | ||||||||||||||||||||||
# | ||||||||||||||||||||||
# This works around that by using a public DNS server other than the DNS | ||||||||||||||||||||||
# server that QEMU provides (normally 10.0.2.3) | ||||||||||||||||||||||
networking.nameservers = [ "8.8.8.8" ]; | ||||||||||||||||||||||
|
||||||||||||||||||||||
nix.settings = { | ||||||||||||||||||||||
auto-optimise-store = true; | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have turned this off since a while to reduce io load but didn't do benchmarking. Is the difference noticeable? Not sure if we should turn it on by default or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually am not too attached to this setting. I don't remember why I added it |
||||||||||||||||||||||
|
||||||||||||||||||||||
min-free = 1024 * 1024 * 1024; | ||||||||||||||||||||||
|
||||||||||||||||||||||
max-free = 3 * 1024 * 1024 * 1024; | ||||||||||||||||||||||
|
||||||||||||||||||||||
trusted-users = [ "root" user ]; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
services.openssh = { | ||||||||||||||||||||||
enable = true; | ||||||||||||||||||||||
|
||||||||||||||||||||||
authorizedKeysFiles = [ "${keysDirectory}/%u_${keyType}.pub" ]; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
system.build.macos-builder-installer = | ||||||||||||||||||||||
let | ||||||||||||||||||||||
privateKey = "/etc/nix/${user}_${keyType}"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
publicKey = "${privateKey}.pub"; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# This installCredentials script is written so that it's as easy as | ||||||||||||||||||||||
# possible for a user to audit before confirming the `sudo` | ||||||||||||||||||||||
installCredentials = pkgs.writeShellScript "install-credentials" '' | ||||||||||||||||||||||
KEYS="''${1}" | ||||||||||||||||||||||
INSTALL=${hostPkgs.coreutils}/bin/install | ||||||||||||||||||||||
"''${INSTALL}" -g nixbld -m 600 "''${KEYS}/${user}_${keyType}" ${privateKey} | ||||||||||||||||||||||
"''${INSTALL}" -g nixbld -m 644 "''${KEYS}/${user}_${keyType}.pub" ${publicKey} | ||||||||||||||||||||||
Comment on lines
+65
to
+69
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
If the goal is to make the script as easy as possible then this is in the end as easy as it gets. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I deliberately did not do it that way because I wanted the script to be easier to read. In particular, I wanted the script to fit within 80 columns There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something does not get easier to read if it fits within 80 columns but has two extra lines. |
||||||||||||||||||||||
''; | ||||||||||||||||||||||
|
||||||||||||||||||||||
hostPkgs = config.virtualisation.host.pkgs; | ||||||||||||||||||||||
|
||||||||||||||||||||||
in | ||||||||||||||||||||||
hostPkgs.writeShellScriptBin "create-builder" '' | ||||||||||||||||||||||
KEYS="''${KEYS:-./keys}" | ||||||||||||||||||||||
${hostPkgs.coreutils}/bin/mkdir --parent "''${KEYS}" | ||||||||||||||||||||||
PRIVATE_KEY="''${KEYS}/${user}_${keyType}" | ||||||||||||||||||||||
PUBLIC_KEY="''${PRIVATE_KEY}.pub" | ||||||||||||||||||||||
if [ ! -e "''${PRIVATE_KEY}" ] || [ ! -e "''${PUBLIC_KEY}" ]; then | ||||||||||||||||||||||
${hostPkgs.coreutils}/bin/rm --force -- "''${PRIVATE_KEY}" "''${PUBLIC_KEY}" | ||||||||||||||||||||||
${hostPkgs.openssh}/bin/ssh-keygen -q -f "''${PRIVATE_KEY}" -t ${keyType} -N "" -C 'builder@localhost' | ||||||||||||||||||||||
fi | ||||||||||||||||||||||
if ! ${hostPkgs.diffutils}/bin/cmp "''${PUBLIC_KEY}" ${publicKey}; then | ||||||||||||||||||||||
(set -x; sudo --reset-timestamp ${installCredentials} "''${KEYS}") | ||||||||||||||||||||||
fi | ||||||||||||||||||||||
KEYS="$(nix-store --add "$KEYS")" ${config.system.build.vm}/bin/run-nixos-vm | ||||||||||||||||||||||
''; | ||||||||||||||||||||||
|
||||||||||||||||||||||
system.stateVersion = "22.05"; | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be taken from nixpkgs instead of being hardcoded here or set once on initialization. |
||||||||||||||||||||||
|
||||||||||||||||||||||
users.users."${user}"= { | ||||||||||||||||||||||
isNormalUser = true; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
virtualisation = { | ||||||||||||||||||||||
diskSize = 20 * 1024; | ||||||||||||||||||||||
|
||||||||||||||||||||||
memorySize = 3 * 1024; | ||||||||||||||||||||||
|
||||||||||||||||||||||
forwardPorts = [ | ||||||||||||||||||||||
{ from = "host"; guest.port = 22; host.port = 22; } | ||||||||||||||||||||||
]; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# Disable graphics for the builder since users will likely want to run it | ||||||||||||||||||||||
# non-interactively in the background. | ||||||||||||||||||||||
graphics = false; | ||||||||||||||||||||||
|
||||||||||||||||||||||
sharedDirectories.keys = { | ||||||||||||||||||||||
source = "\"$KEYS\""; | ||||||||||||||||||||||
target = keysDirectory; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# If we don't enable this option then the host will fail to delegate builds | ||||||||||||||||||||||
# to the guest, because: | ||||||||||||||||||||||
# | ||||||||||||||||||||||
# - The host will lock the path to build | ||||||||||||||||||||||
# - The host will delegate the build to the guest | ||||||||||||||||||||||
# - The guest will attempt to lock the same path and fail because | ||||||||||||||||||||||
# the lockfile on the host is visible on the guest | ||||||||||||||||||||||
# | ||||||||||||||||||||||
# Snapshotting the host's /nix/store as an image isolates the guest VM's | ||||||||||||||||||||||
# /nix/store from the host's /nix/store, preventing this problem. | ||||||||||||||||||||||
useNixStoreImage = true; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# Obviously the /nix/store needs to be writable on the guest in order for it | ||||||||||||||||||||||
# to perform builds. | ||||||||||||||||||||||
writableStore = true; | ||||||||||||||||||||||
|
||||||||||||||||||||||
# This ensures that anything built on the guest isn't lost when the guest is | ||||||||||||||||||||||
# restarted. | ||||||||||||||||||||||
writableStoreUseTmpfs = false; | ||||||||||||||||||||||
}; | ||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to change this via the root's ssh_config