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 default = "devicemapper";
50 description =
51 ''
52 This option determines which Docker storage driver to use.
53 '';
54 };
55 extraOptions =
56 mkOption {
57 type = types.separatedString " ";
58 default = "";
59 description =
60 ''
61 The extra command-line options to pass to
62 <command>docker</command> daemon.
63 '';
64 };
65
66 postStart =
67 mkOption {
68 type = types.lines;
69 default = ''
70 while ! [ -e /var/run/docker.sock ]; do
71 sleep 0.1
72 done
73 '';
74 description = ''
75 The postStart phase of the systemd service. You may need to
76 override this if you are passing in flags to docker which
77 don't cause the socket file to be created.
78 '';
79 };
80
81
82 };
83
84 ###### implementation
85
86 config = mkIf cfg.enable (mkMerge [
87 { environment.systemPackages = [ pkgs.docker ];
88 users.extraGroups.docker.gid = config.ids.gids.docker;
89 }
90 (mkIf cfg.socketActivation {
91
92 systemd.services.docker = {
93 description = "Docker Application Container Engine";
94 after = [ "network.target" "docker.socket" ];
95 requires = [ "docker.socket" ];
96 serviceConfig = {
97 ExecStart = "${pkgs.docker}/bin/docker daemon --host=fd:// --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
98 # I'm not sure if that limits aren't too high, but it's what
99 # goes in config bundled with docker itself
100 LimitNOFILE = 1048576;
101 LimitNPROC = 1048576;
102 } // proxy_env;
103 };
104
105 systemd.sockets.docker = {
106 description = "Docker Socket for the API";
107 wantedBy = [ "sockets.target" ];
108 socketConfig = {
109 ListenStream = "/var/run/docker.sock";
110 SocketMode = "0660";
111 SocketUser = "root";
112 SocketGroup = "docker";
113 };
114 };
115 })
116 (mkIf (!cfg.socketActivation) {
117
118 systemd.services.docker = {
119 description = "Docker Application Container Engine";
120 wantedBy = [ "multi-user.target" ];
121 after = [ "network.target" ];
122 serviceConfig = {
123 ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}";
124 # I'm not sure if that limits aren't too high, but it's what
125 # goes in config bundled with docker itself
126 LimitNOFILE = 1048576;
127 LimitNPROC = 1048576;
128 } // proxy_env;
129
130 path = [ pkgs.kmod ] ++ (optional (cfg.storageDriver == "zfs") pkgs.zfs);
131 environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules";
132
133 postStart = cfg.postStart;
134
135 # Presumably some containers are running we don't want to interrupt
136 restartIfChanged = false;
137 };
138 })
139 ]);
140
141}