Port the work from nixpkgs

This commit is contained in:
Graham Christensen 2018-04-10 14:53:42 -04:00
parent b540c3e293
commit 66c9ba4c16
10 changed files with 532 additions and 136 deletions

View File

@ -1,6 +1,6 @@
with (import <nixpkgs> { }).forceSystem "x86_64-linux" "x86_64";
dockerTools.buildImage {
name = "linuxkit-builder-example";
contents = hello;
name = "linuxkit-builder-example-${toString builtins.currentTime}";
contents = [ hello gitAndTools.tig ];
}

27
go-vpnkit/default.nix Normal file
View File

@ -0,0 +1,27 @@
{ stdenv, lib, buildGoPackage, fetchFromGitHub }:
buildGoPackage rec {
name = "vpnkit-unstable-${version}";
version = "2017-06-28";
rev = "db7b7b0f8147f29360d69dc81af9e2877647f0de";
goPackagePath = "github.com/moby/vpnkit";
src = fetchFromGitHub {
owner = "moby";
repo = "vpnkit";
inherit rev;
sha256 = "192mfrhyyhfszjbd052gpmnf2gr86sxc2wfid45cc1dcdnljcshx";
};
postInstall = ''
ln -s $bin/bin/vpnkit-forwarder $bin/bin/vpnkit-expose-port
'';
meta = {
description = "Client commands for VPNKit";
homepage = "https://github.com/moby/vpnkit";
maintainers = [ lib.maintainers.puffnfresh ];
platforms = lib.platforms.linux;
};
}

3
go-vpnkit/deps.nix Normal file
View File

@ -0,0 +1,3 @@
# This file was generated by https://github.com/kamilchm/go2nix v1.2.0
[
]

View File

@ -1,3 +1,9 @@
# Builds a script to start a Linux x86_64 remote builder using LinuxKit. This
# script relies on darwin-x86_64 and linux-x86_64 dependencies so an existing
# remote builder should be used.
# The VM runs SSH with Nix available, so we can use it as a remote builder.
# TODO: Sadly this file has lots of duplication with vmTools.
{ system
@ -5,23 +11,54 @@
, perl
, xz
, bash
, nix
, pathsFromGraph
, hyperkit
, linuxkit
, vpnkit
, socat
, linuxkit
, buildEnv
, writeScript
, writeScriptBin
, writeText
, writeTextFile
, runCommand
, forceSystem
, vmTools
, makeInitrd
, shellcheck
, linuxkitKernel ? (forceSystem "x86_64-linux" "x86_64").callPackage ./kernel.nix { }
, storeDir ? builtins.storeDir
, hostPort ? "24083"
}:
let
writeScriptDir = name: text: writeTextFile {inherit name text; executable = true; destination = "/${name}"; };
writeRunitForegroundService = name: run: writeTextFile {inherit name; text = run; executable = true; destination = "/${name}/run"; };
shellcheckedScriptBin = name: src: substitutions: runCommand "shellchecked-${name}" {
sub_src = shellcheckedScript name src substitutions;
} "mkdir -p $out/bin; cp $sub_src $out/bin/${name}";
shellcheckedScript = name: src: substitutions: runCommand "shellchecked-${name}" (substitutions // {
buildInputs = [ shellcheck ];
}) ''
cp ${src} './${name}'
substituteAllInPlace '${name}'
patchShebangs '${name}'
if grep -qE '@[^[:space:]]+@' '${name}'; then
echo "WARNING: Found @alpha@ placeholders!"
grep -E '@[^[:space:]]+@' '${name}'
exit 1
fi
if [ "''${debug:-0}" -eq 1 ]; then
cat '${name}'
fi
shellcheck -x '${name}'
chmod +x '${name}'
mv '${name}' $out
'';
pkgsLinux = forceSystem "x86_64-linux" "x86_64";
vmToolsLinux = vmTools.override { kernel = linuxkitKernel; pkgs = pkgsLinux; };
containerIp = "192.168.65.2";
@ -37,115 +74,165 @@ let
}
];
};
stage1Init = writeScript "vm-run-stage1" ''
#! ${vmToolsLinux.initrdUtils}/bin/ash -e
export PATH=${vmToolsLinux.initrdUtils}/bin
mkdir /etc
echo -n > /etc/fstab
mount -t proc none /proc
mount -t sysfs none /sys
echo 2 > /proc/sys/vm/panic_on_oom
# echo "loading kernel modules..."
# for i in $(cat ${vmToolsLinux.modulesClosure}/insmod-list); do
# insmod $i
# done
mount -t devtmpfs devtmpfs /dev
ifconfig lo up
mkdir /fs
mount -t ext4 /dev/${hd} /fs 2>/dev/null || {
${pkgsLinux.e2fsprogs}/bin/mkfs.ext4 -q /dev/${hd}
mount -t ext4 /dev/${hd} /fs
} || true
mkdir -p /fs/dev
mount -o bind /dev /fs/dev
mkdir -p /fs/dev/shm /fs/dev/pts
mount -t tmpfs -o "mode=1777" none /fs/dev/shm
mount -t devpts none /fs/dev/pts
echo "extracting Nix store..."
EXTRACT_UNSAFE_SYMLINKS=1 tar -C /fs -xf ${systemTarball}/tarball/nixos-system-${system}.tar.xz nix nix-path-registration
mkdir -p /fs/tmp /fs/run /fs/var
mount -t tmpfs -o "mode=755" none /fs/run
ln -sfn /run /fs/var/run
mkdir -p /fs/proc
mount -t proc none /fs/proc
mkdir -p /fs/sys
mount -t sysfs none /fs/sys
mkdir -p /fs/etc
ln -sf /proc/mounts /fs/etc/mtab
echo "127.0.0.1 localhost" > /fs/etc/hosts
echo "starting stage 2 ($command)"
exec switch_root /fs $command
'';
stage1Init = shellcheckedScript "vm-run-stage1" ./stage-1.sh {
inherit (vmToolsLinux) initrdUtils;
inherit (vmToolsLinux) modulesClosure;
inherit (pkgsLinux) e2fsprogs;
inherit hd stage2Init;
systemTarballPath = "${systemTarball}/tarball/nixos-system-${system}.tar.xz";
};
sshdConfig = writeText "linuxkit-sshd-config" ''
LogLevel VERBOSE
PermitRootLogin yes
PasswordAuthentication no
ChallengeResponseAuthentication no
'';
stage2Init = writeScript "vm-run-stage2" ''
#! ${pkgsLinux.bash}/bin/bash
export NIX_STORE=${storeDir}
export NIX_BUILD_TOP=/tmp
export TMPDIR=/tmp
cd "$NIX_BUILD_TOP"
stage2Init = shellcheckedScript "vm-run-stage2" ./stage-2.sh rec {
inherit (pkgsLinux) coreutils busybox bash runit;
inherit storeDir containerIp;
${pkgsLinux.coreutils}/bin/mkdir -p /bin
${pkgsLinux.coreutils}/bin/ln -fs ${pkgsLinux.bash}/bin/sh /bin/sh
script_modprobe = writeScript "modeprobe" ''
#! /bin/sh
export MODULE_DIR=${pkgsLinux.linux}/lib/modules/
exec ${pkgsLinux.kmod}/bin/modprobe "$@"
'';
# # Set up automatic kernel module loading.
export MODULE_DIR=${pkgsLinux.linux}/lib/modules/
${pkgsLinux.coreutils}/bin/cat <<EOF > /run/modprobe
#! /bin/sh
export MODULE_DIR=$MODULE_DIR
exec ${pkgsLinux.kmod}/bin/modprobe "\$@"
EOF
${pkgsLinux.coreutils}/bin/chmod 755 /run/modprobe
echo /run/modprobe > /proc/sys/kernel/modprobe
file_passwd = writeText "passwd" ''
root:x:0:0:System administrator:/root:${pkgsLinux.bash}/bin/bash
sshd:x:1:65534:SSH privilege separation user:/var/empty:${pkgsLinux.shadow}/bin/nologin
nixbld1:x:30001:30000:Nix build user 1:/var/empty:${pkgsLinux.shadow}/bin/nologin
'';
ln -sfn /proc/self/fd /dev/fd
file_group = writeText "group" ''
nixbld:x:30000:nixbld1
root:x:0:root
'';
echo "root:x:0:0:System administrator:/root:${pkgsLinux.bash}/bin/bash" >> /etc/passwd
echo "sshd:x:1:65534:SSH privilege separation user:/var/empty:${pkgsLinux.shadow}/bin/nologin" >> /etc/passwd
echo "nixbld1:x:30001:30000:Nix build user 1:/var/empty:${pkgsLinux.shadow}/bin/nologin" >> /etc/passwd
echo "nixbld:x:30000:nixbld1" >> /etc/group
file_bashrc = writeScript "bashrc" ''
export PATH="${vmToolsLinux.initrdUtils}/bin:${pkgsLinux.nix}/bin"
export NIX_SSL_CERT_FILE='${pkgsLinux.cacert}/etc/ssl/certs/ca-bundle.crt'
'';
export PATH="${vmToolsLinux.initrdUtils}/bin:${pkgsLinux.nix}/bin"
script_poweroff = writeScript "poweroff" ''
#!/bin/sh
exec ${pkgsLinux.busybox}/bin/poweroff -f
'';
if [ -f /nix-path-registration ]; then
cat /nix-path-registration | nix-store --load-db
rm /nix-path-registration
fi
file_instructions = writeText "instructions" ''
======================================================================
Remote builder has started.
mkdir -p /etc/ssh /root/.ssh /var/db /var/empty
If this is a fresh VM you need to run the following on the host:
~/.nixpkgs/linuxkit-builder/finish-setup.sh
ifconfig eth0 ${containerIp}
route add default gw 192.168.65.1 eth0
echo 'nameserver 192.168.65.1' > /etc/resolv.conf
export NIX_SSL_CERT_FILE="${pkgsLinux.cacert}/etc/ssl/certs/ca-bundle.crt"
mkdir -p /run/nix-daemon
${pkgsLinux.virtsock}/bin/vsudd -inport 2374:unix:/run/nix-daemon/daemon.sock &
${pkgsLinux.socat}/bin/socat UNIX-LISTEN:/run/nix-daemon/daemon.sock EXEC:"nix-daemon --stdio"
exec halt -f
'';
Exit this VM by running:
kill $(cat ~/.nixpkgs/linuxkit-builder/nix-state/hyperkit.pid)
======================================================================
'';
runit_targets = buildEnv {
name = "runit-targets";
paths = [
# Startup
(writeScriptDir "1" ''
#!/bin/sh
echo 'Hello world!'
touch /etc/runit/stopit
chmod 0 /etc/runit/stopit
'')
# Run-time
(writeScriptDir "2" ''
#!/bin/sh
echo "Entering run-time"
cat /proc/uptime
echo "Running services in ${service_targets}..."
exec ${pkgsLinux.runit}/bin/runsvdir -P ${service_targets}
'')
# Shutdown
(writeScriptDir "3" ''
#!/bin/sh
echo 'Ok, bye...'
'')
];
};
service_targets = buildEnv {
name = "service-targets";
paths = [
(writeRunitForegroundService "acpid" ''
#!/bin/sh
exec ${pkgsLinux.busybox}/bin/acpid -f
'')
(writeRunitForegroundService "sshd" ''
#!/bin/sh
exec ${pkgsLinux.openssh}/bin/sshd -D -e -f ${sshdConfig}
'')
(writeRunitForegroundService "vpnkit-expose-port" ''
#!/bin/sh
${pkgsLinux.go-vpnkit}/bin/vpnkit-expose-port \
-i \
-host-ip 127.0.0.1 -host-port ${hostPort} \
-container-ip 192.168.65.2 -container-port 22 \
-no-local-ip
echo "VPNKit expose port exited $?, which may be fine"
kill -stop $$
'')
(writeRunitForegroundService "vpnkit-forwarder" ''
#!/bin/sh
exec ${pkgsLinux.go-vpnkit}/bin/vpnkit-forwarder
'')
(writeRunitForegroundService "postboot-instructions" ''
#!/bin/sh
sleep 1
inst() {
echo
echo -e '\033[91;47m'
cat ${file_instructions}
echo -e '\033[0m'
}
inst
(while read x; do
case "$x" in
stop)
${script_poweroff}
;;
ping)
echo "pong"
;;
ps)
${pkgsLinux.busybox}/bin/ps auxfg
;;
df)
${pkgsLinux.coreutils}/bin/df -ha
;;
shell)
${pkgsLinux.bash}/bin/bash 2>&1
;;
*)
inst
echo "I know stop, ping, ps, df, shell"
;;
esac
done) < /dev/console > /dev/console
'')
];
};
};
img = "bzImage";
initrd = makeInitrd {
@ -155,43 +242,22 @@ let
}
];
};
dir = "/var/run/nix/linuxkit-builder";
linuxkit-nix-daemon = writeScriptBin "linuxkit-nix-daemon" ''
#!${bash}/bin/bash
in shellcheckedScriptBin "linuxkit-builder" ./ui.sh {
inherit bash hostPort vpnkit hyperkit linuxkit containerIp;
SIZE="1G"
CPUS=1
MEM=1024
boot_files = runCommand "linuxkit-kernel-files" {
kernel_path = "${linuxkitKernel}/${img}";
initrd_path = "${initrd}/initrd";
kernel_cmdline_path = writeText "nix-cmdline"
"console=ttyS0 panic=1 command=${stage2Init} loglevel=7 debug";
} ''
mkdir $out
cd $out
mkdir -p "${dir}"
ln -fs ${linuxkitKernel}/${img} "${dir}/nix-kernel"
ln -fs ${initrd}/initrd "${dir}/nix-initrd.img"
echo -n "console=ttyS0 panic=1 command=${stage2Init} loglevel=7 debug acpi=debug" > "${dir}/nix-cmdline"
exec ${linuxkit}/bin/linuxkit run \
hyperkit \
-hyperkit ${hyperkit}/bin/hyperkit \
-vpnkit ${vpnkit}/bin/vpnkit \
-disk "${dir}/nix-disk,size=$SIZE" \
-cpus $CPUS \
-mem $MEM \
-networking vpnkit \
-ip ${containerIp} \
-vsock-ports 2374 \
-console-file \
"${dir}/nix"
ln -fs $kernel_path "./nix-kernel"
ln -fs $initrd_path "./nix-initrd.img"
ln -fs $kernel_cmdline_path "./nix-cmdline"
'';
linuxkit-builder = writeScriptBin "linuxkit-builder" ''
#!${bash}/bin/bash
${linuxkit-nix-daemon}/bin/linuxkit-nix-daemon >/dev/null &
while ! grep -q "Listening on port 2374" "${dir}/nix-state/console-ring"; do
echo "Waiting for LinuxKit VM to boot..." >&2
sleep 2
done
sleep 1
exec ${socat}/bin/socat UNIX-CONNECT:"${dir}/nix-state/00000003.00000946" -
'';
in
linuxkit-builder
integrated_path = ./integrated.sh;
example_path = ./example.nix;
}

View File

@ -0,0 +1,5 @@
with (import <nixpkgs> { }).forceSystem "x86_64-linux" "x86_64";
hello.overrideDerivation (x: {
name = "hello-${toString builtins.currentTime}";
})

View File

@ -0,0 +1,19 @@
#!/bin/sh
set -eu
root=$(dirname "$0")
(
i=0
while ! ssh -F "$root/ssh-config" nix-linuxkit -o ConnectTimeout=1 true; do
i=$((i + 1))
if [ "$i" -gt 30 ]; then
echo "Failed to connect to the linuxkit builder within 30 tries"
exit 1
fi
sleep 1
done
) >&2 < /dev/null
exec ssh -F "$root/ssh-config" nix-linuxkit nix-daemon --stdio

View File

@ -0,0 +1,64 @@
#! @initrdUtils@/bin/ash -eu
# shellcheck shell=dash
export PATH=@initrdUtils@/bin:@e2fsprogs@/bin;
HD=/dev/@hd@
SYSTEM_TARBALL_PATH=@systemTarballPath@
STAGE_TWO=@stage2Init@
MODULE_LIST=@modulesClosure@/insmod-list
mkdir /etc
echo -n > /etc/fstab
mount -t proc none /proc
mount -t sysfs none /sys
echo 2 > /proc/sys/vm/panic_on_oom
if [ -f "$MODULE_LIST" ]; then
echo "loading kernel modules..."
while IFS= read -r module
do
insmod "$module"
done < "$MODULE_LIST"
else
echo "Not loading kernel modules: $MODULE_LIST does not exist."
fi
mount -t devtmpfs devtmpfs /dev
ifconfig lo up
mkdir /fs
if ! mount -t ext4 "$HD" /fs 2>/dev/null; then
mkfs.ext4 -q "$HD"
mount -t ext4 "$HD" /fs
fi
mkdir -p /fs/dev
mount -o bind /dev /fs/dev
mkdir -p /fs/dev/shm /fs/dev/pts
mount -t tmpfs -o "mode=1777" none /fs/dev/shm
mount -t devpts none /fs/dev/pts
echo "extracting Nix store..."
EXTRACT_UNSAFE_SYMLINKS=1 tar -C /fs -xf "$SYSTEM_TARBALL_PATH" nix nix-path-registration
mkdir -p /fs/tmp /fs/run /fs/var
mount -t tmpfs -o "mode=755" none /fs/run
ln -sfn /run /fs/var/run
mkdir -p /fs/proc
mount -t proc none /fs/proc
mkdir -p /fs/sys
mount -t sysfs none /fs/sys
mkdir -p /fs/etc
ln -sf /proc/mounts /fs/etc/mtab
echo "127.0.0.1 localhost" > /fs/etc/hosts
echo "starting stage 2: $STAGE_TWO"
exec switch_root /fs "$STAGE_TWO"

View File

@ -0,0 +1,97 @@
#! @bash@/bin/bash -eu
export PATH=@coreutils@/bin:@busybox@/bin
export SH_PATH=@bash@/bin/sh
export RUNIT_PATH=@runit@/bin/runit
export MODPROBE_PATH=@script_modprobe@
export PASSWD_PATH=@file_passwd@
export GROUP_PATH=@file_group@
export BASHRC_PATH=@file_bashrc@
export POWEROFF_PATH=@script_poweroff@
export RUNIT_TARGETS_PATH=@runit_targets@
export CONTAINER_IP=@containerIp@
export NIX_STORE=@storeDir@
export NIX_BUILD_TOP=/tmp
export TMPDIR=/tmp
cd "$NIX_BUILD_TOP"
mkdir -p /bin
ln -fs "$SH_PATH" /bin/sh
ln -s /proc/self/fd /dev/fd
# # Set up automatic kernel module loading.
cat $MODPROBE_PATH > /run/modprobe
chmod 755 /run/modprobe
echo /run/modprobe > /proc/sys/kernel/modprobe
cat $PASSWD_PATH > /etc/passwd
cat $GROUP_PATH > /etc/group
mkdir -p /etc/ssh /root /var/db /var/empty
chown root:root /root
chmod 0700 /root
cat $BASHRC_PATH > /root/.bashrc
# Note: I try not to reference substituted variables in the body of
# the program because I think it is confusing, and easier to
# understand by declaring them all at the top. However, shellcheck can
# follow the bashrc only if we explicitly specif its source here, and
# it won't follow a variable (even though it is statically set
# above...) so, here we go.
#
# shellcheck source=@file_bashrc@
. $BASHRC_PATH
ls -la /nix/var/nix/ || true
ls -la /nix/var/nix/db || true
if [ -f /nix-path-registration ]; then
nix-store --load-db < /nix-path-registration
rm /nix-path-registration
fi
ifconfig eth0 $CONTAINER_IP
route add default gw 192.168.65.1 eth0
echo 'nameserver 192.168.65.1' > /etc/resolv.conf
mkdir -p /mnt
mount /dev/sr0 /mnt
if [ ! -f /mnt/config ]; then
echo "FAIL FAIL FAIL"
echo "You must pass an SSH key data file via via a CDROM (ie: -data on linuxkit)"
exit 1
fi
mkdir /extract-ssh-keys
(
rm -rf /root/.ssh
mkdir -p /root/.ssh
chmod 0700 /root/.ssh
cd /extract-ssh-keys
tar -xf /mnt/config
chmod 0600 ./*
chmod 0644 ./*.pub
mv client.pub /root/.ssh/authorized_keys
chmod 0600 /root/.ssh/authorized_keys
chown root:root /root/.ssh/authorized_keys
mv ssh_host_* /etc/ssh/
)
rm -rf /extract-ssh-keys
mkdir -p /port
mount -v -t 9p -o trans=virtio,dfltuid=1001,dfltgid=50,version=9p2000 port /port
mkdir -p /etc/acpi/PWRF /etc/acpi/events
cat $POWEROFF_PATH > /etc/acpi/PWRF/00000080
chmod +x /etc/acpi/PWRF/00000080
mkdir -p /dev/input /var/log
rm -rf /etc/runit
cp -r $RUNIT_TARGETS_PATH /etc/runit/
exec $RUNIT_PATH

114
linuxkit-builder/ui.sh Normal file
View File

@ -0,0 +1,114 @@
#!@bash@/bin/bash -eu
BOOT_FILES=@boot_files@
HOST_PORT=@hostPort@
INTEGRATED_PATH=@integrated_path@
EXAMPLE_PATH=@example_path@
VPNKIT_ROOT=@vpnkit@
HYPERKIT_ROOT=@hyperkit@
LINUXKIT_ROOT=@linuxkit@
CONTAINER_IP=@containerIp@
usage() {
echo "Usage: $(basename "$0") [-d directory] [-f features] [-s size] [-c cpus] [-m mem]" >&2
}
NAME="linuxkit-builder"
DIR="$HOME/.nixpkgs/$NAME"
FEATURES="big-parallel"
SIZE="10G"
CPUS=1
MEM=1024
while getopts "d:f:s:c:m:h" opt; do
case $opt in
d) DIR="$OPTARG" ;;
f) FEATURES="$OPTARG" ;;
s) SIZE="$OPTARG" ;;
c) CPUS="$OPTARG" ;;
m) MEM="$OPTARG" ;;
h | \?)
usage
exit 64
;;
esac
done
mkdir -p "$DIR"
if [ ! -d "$DIR/keys" ]; then
mkdir -p "$DIR/keys"
(
cd "$DIR/keys"
ssh-keygen -C "Nix LinuxKit Builder, Client" -N "" -f client
ssh-keygen -C "Nix LinuxKit Builder, Server" -f ssh_host_ecdsa_key -N "" -t ecdsa
tar -cf server-config.tar client.pub ssh_host_ecdsa_key.pub ssh_host_ecdsa_key
echo -n "[localhost]:$HOST_PORT " > known_host
cat ssh_host_ecdsa_key.pub >> known_host
)
fi
cp "$INTEGRATED_PATH" "$DIR/integrated.sh"
chmod +x "$DIR/integrated.sh"
cp "$EXAMPLE_PATH" "$DIR/example.nix"
cat <<EOF > "$DIR/ssh-config"
Host nix-linuxkit
HostName localhost
User root
Port $HOST_PORT
IdentityFile $DIR/keys/client
StrictHostKeyChecking yes
UserKnownHostsFile $DIR/keys/known_host
IdentitiesOnly yes
EOF
cat <<-EOF > "$DIR/finish-setup.sh"
#!/bin/sh
cat <<EOI
1. Add the following to /etc/nix/machines:
ssh://nix-linuxkit x86_64-linux $DIR/keys/client $CPUS 1 $FEATURES
2. Add the following to /var/root/.ssh/config:
Host nix-linuxkit
HostName localhost
User root
Port $HOST_PORT
IdentityFile $DIR/keys/client
StrictHostKeyChecking yes
UserKnownHostsFile $DIR/keys/known_host
IdentitiesOnly yes
3. Try it out!
nix-build $DIR/example.nix
Note, if you're already using
https://github.com/puffnfresh/nix-script-store-plugin you can skip
steps #1 and #2 and instead add the following to /etc/nix/machines:
script://$DIR/integrated.sh x86_64-linux - $CPUS 1 $FEATURES
EOF
chmod +x "$DIR/finish-setup.sh"
PATH="$VPNKIT_ROOT/bin:$PATH"
exec "$LINUXKIT_ROOT/bin/linuxkit" run \
hyperkit \
-hyperkit "$HYPERKIT_ROOT/bin/hyperkit" "$@" \
-networking vpnkit \
-ip "$CONTAINER_IP" \
-disk "$DIR/nix-disk,size=$SIZE" \
-data-file "$DIR/keys/server-config.tar" \
-cpus "$CPUS" \
-mem "$MEM" \
-state "$DIR/nix-state" \
"$BOOT_FILES/nix"

View File

@ -6,6 +6,7 @@ self: super: {
};
virtsock = self.callPackage ./virtsock { };
vpnkit = self.callPackage ./vpnkit { };
go-vpnkit = self.callPackage ./go-vpnkit { };
linuxkit = self.callPackage ./linuxkit { };
linuxkit-builder = self.callPackage ./linuxkit-builder { };