1# Systemd services for docker.
2
3{ config, lib, pkgs, ... }:
4
5with lib;
6
7let
8
9 cfg = config.virtualisation.docker;
10 pro = config.networking.proxy.default;
11 proxy_env = optionalAttrs (pro != null) { Environment = "\"http_proxy=${pro}\""; };
12
13in
14
15{
16 ###### interface
17
18 options.virtualisation.docker = {
19 enable =
20 mkOption {
21 type = types.bool;
22 default = false;
23 description =
24 ''
25 This option enables docker, a daemon that manages
26 linux containers. Users in the "docker" group can interact with
27 the daemon (e.g. to start or stop containers) using the
28 <command>docker</command> command line tool.
29 '';
30 };
31 socketActivation =
32 mkOption {
33 type = types.bool;
34 default = false;
35 description =
36 ''
37 This option enables docker with socket activation. I.e. docker will
38 start when first called by client.
39
40 Note: This is false by default because systemd lower than 214 that
41 nixos uses so far, doesn't support SocketGroup option, so socket
42 created by docker has root group now. This will likely be changed
43 in future. So set this option explicitly to false if you wish.
44 '';
45 };
46 storageDriver =
47 mkOption {
48 type = types.enum ["aufs" "btrfs" "devicemapper" "overlay" "zfs"];
49 description =
50 ''
51 This option determines which Docker storage driver to use.
52 It is required but lacks a default value as its most
53 suitable value will depend the filesystems available on the
54 host.
55 '';
56 };
57 extraOptions =
58 mkOption {
59 type = types.separatedString " ";
60 default = "";
61 description =
62 ''
63 The extra command-line options to pass to
64 <command>docker</command> daemon.
65 '';
66 };
67
68 postStart =
69 mkOption {
70 type = types.string;
71 default = ''
72 while ! [ -e /var/run/docker.sock ]; do
73 sleep 0.1
74 done
75 '';
76 description = ''
77 The postStart phase of the systemd service. You may need to
78 override this if you are passing in flags to docker which
79 don't cause the socket file to be created.
80 '';
81 };
82
83
84 };
85
86 ###### implementation
87
88 config = mkIf cfg.enable (mkMerge [
89 { environment.systemPackages = [ pkgs.docker ];
90 users.extraGroups.docker.gid = config.ids.gids.docker;
91 }
92 (mkIf cfg.socketActivation {
93
94 systemd.services.docker = {
95 description = "Docker Application Container Engine";
96 after = [ "network.target" "docker.socket" ];
97 requires = [ "docker.socket" ];
98 serviceConfig = {
99 ExecStart = "${pkgs.docker}/bin/docker daemon --host=fd:// --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
100 # I'm not sure if that limits aren't too high, but it's what
101 # goes in config bundled with docker itself
102 LimitNOFILE = 1048576;
103 LimitNPROC = 1048576;
104 } // proxy_env;
105 };
106
107 systemd.sockets.docker = {
108 description = "Docker Socket for the API";
109 wantedBy = [ "sockets.target" ];
110 socketConfig = {
111 ListenStream = "/var/run/docker.sock";
112 SocketMode = "0660";
113 SocketUser = "root";
114 SocketGroup = "docker";
115 };
116 };
117 })
118 (mkIf (!cfg.socketActivation) {
119
120 systemd.services.docker = {
121 description = "Docker Application Container Engine";
122 wantedBy = [ "multi-user.target" ];
123 after = [ "network.target" ];
124 serviceConfig = {
125 ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
126 # I'm not sure if that limits aren't too high, but it's what
127 # goes in config bundled with docker itself
128 LimitNOFILE = 1048576;
129 LimitNPROC = 1048576;
130 } // proxy_env;
131
132 path = [ pkgs.kmod ];
133 environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
134
135 postStart = cfg.postStart;
136
137 # Presumably some containers are running we don't want to interrupt
138 restartIfChanged = false;
139 };
140 })
141 ]);
142
143}