summaryrefslogtreecommitdiff
path: root/nix-modules/docker-nixos-modules.nix
blob: 8502d47456d2e89d6bc0a960393a4b5b988fd6bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{ nixpkgsPath ? <nixpkgs>
, dockerConfig
, nixConfig
, name
, tag ? ""
, ...}:

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
      nixConfig
      "${nixpkgsPath}/nixos/modules/misc/assertions.nix"
    ];
  };



in pkgs.dockerTools.buildImage {
  inherit name tag;

  # 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; dockerConfig // {
    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 -xue

                  # set up working directory
                  ${optionalString (service ? serviceConfig
                          && service.serviceConfig ? WorkingDirectory) ''
                    mkdir -p ${service.serviceConfig.WorkingDirectory}
                    cd ${service.serviceConfig.WorkingDirectory} ''}

                  # run the prestart script
                  ${optionalString (service ? preStart) ''
                    echo ${escapeShellArg name}: running preStart script
                    ${service.preStart}''}

                  echo ${name}: starting ...

                  # 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")) ];
  };
}