{ nixpkgsPath ? , ociconfig , name , ...}: let pkgs = import nixpkgsPath {}; dummyOption = with pkgs.lib; mkOption { type = types.attrs; default = {}; }; systemModule = { lib, config, ... }: { options = { toplevel = lib.mkOption { type = lib.types.str; }; systemd = with lib; { services = dummyOption; targets = dummyOption; timers = dummyOption; }; environment = dummyOption; users.users = dummyOption; users.groups = dummyOption; meta = dummyOption; networking.enableIPv6 = lib.mkOption { type = lib.types.bool; default = false; }; }; config._module.args.pkgs = pkgs; }; config = pkgs.lib.evalModules { modules = [ systemModule ociconfig "${nixpkgsPath}/nixos/modules/misc/assertions.nix" ]; }; in pkgs.dockerTools.buildImage { inherit name; # coreutils are included since we need them in startup scripts contents = pkgs.coreutils; # create home directories of users (some services create # their state paths using this, so even without having # users it's important) runAsRoot = (with pkgs.lib; strings.concatStrings (mapAttrsToList (n: u: if u ? createHome && u.createHome then ("mkdir -p ${u.home}\n") else "") config.config.users.users)); # this maps all defined systemd services to simple shell # scripts that are started when the docker container runs. # Note that many features of the systemd.services config # are just ignored (e.g. no auto-restarts yet) config = with pkgs.lib; with pkgs.lib.strings; { Cmd = pkgs.writeScript "main-entrypoint" ("#!${pkgs.dash.outPath}/bin/dash\n" + concatStrings (map (command: "${command}&\n") (mapAttrsToList (name: service: (pkgs.writeScript "systemd-script-${name}" '' #!${pkgs.dash.outPath}/bin/dash set -ue # run the prestart script ${optionalString (service ? preStart) '' echo ${escapeShellArg name}: running preStart script ${service.preStart}''} echo ${name}: starting ... # set up working directory ${optionalString (service ? serviceConfig && service.serviceConfig ? WorkingDirectory) '' mkdir -p ${service.serviceConfig.WorkingDirectory} cd ${service.serviceConfig.WorkingDirectory} ''} # set up environment variables ${optionalString (service ? environment) (concatStrings (mapAttrsToList (n: k: "export ${n}=${escapeShellArg k}\n") service.environment))} # start the service ${if service ? script then service.script else service.serviceConfig.ExecStart} '').outPath) config.config.systemd.services)) + "\n wait"); }; }