1{ lib, callPackage }:
2
3let
4 dockerGen =
5 {
6 version,
7 cliRev,
8 cliHash,
9 mobyRev,
10 mobyHash,
11 runcRev,
12 runcHash,
13 containerdRev,
14 containerdHash,
15 tiniRev,
16 tiniHash,
17 buildxSupport ? true,
18 composeSupport ? true,
19 sbomSupport ? false,
20 initSupport ? false,
21 # package dependencies
22 stdenv,
23 fetchFromGitHub,
24 buildGoModule,
25 makeBinaryWrapper,
26 installShellFiles,
27 pkg-config,
28 glibc,
29 go-md2man,
30 go,
31 containerd,
32 runc,
33 tini,
34 libtool,
35 sqlite,
36 iproute2,
37 docker-buildx,
38 docker-compose,
39 docker-sbom,
40 docker-init,
41 iptables,
42 e2fsprogs,
43 xz,
44 util-linuxMinimal,
45 xfsprogs,
46 gitMinimal,
47 procps,
48 rootlesskit,
49 slirp4netns,
50 fuse-overlayfs,
51 nixosTests,
52 clientOnly ? !stdenv.hostPlatform.isLinux,
53 symlinkJoin,
54 withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
55 systemd,
56 withBtrfs ? stdenv.hostPlatform.isLinux,
57 btrfs-progs,
58 withLvm ? stdenv.hostPlatform.isLinux,
59 lvm2,
60 withSeccomp ? stdenv.hostPlatform.isLinux,
61 libseccomp,
62 knownVulnerabilities ? [ ],
63 versionCheckHook,
64 }:
65 let
66 docker-meta = {
67 license = lib.licenses.asl20;
68 maintainers = with lib.maintainers; [
69 offline
70 vdemeester
71 periklis
72 teutat3s
73 ];
74 };
75
76 docker-runc = runc.overrideAttrs {
77 pname = "docker-runc";
78 inherit version;
79
80 src = fetchFromGitHub {
81 owner = "opencontainers";
82 repo = "runc";
83 tag = runcRev;
84 hash = runcHash;
85 };
86
87 preBuild = ''
88 substituteInPlace Makefile --replace-warn "/bin/bash" "${stdenv.shell}"
89 '';
90
91 # docker/runc already include these patches / are not applicable
92 patches = [ ];
93 };
94
95 docker-containerd = containerd.overrideAttrs (oldAttrs: {
96 pname = "docker-containerd";
97 inherit version;
98
99 # We only need binaries
100 outputs = [ "out" ];
101
102 src = fetchFromGitHub {
103 owner = "containerd";
104 repo = "containerd";
105 tag = containerdRev;
106 hash = containerdHash;
107 };
108
109 buildInputs = oldAttrs.buildInputs ++ lib.optionals withSeccomp [ libseccomp ];
110
111 # See above
112 installTargets = "install";
113 });
114
115 docker-tini = tini.overrideAttrs {
116 pname = "docker-tini";
117 inherit version;
118
119 src = fetchFromGitHub {
120 owner = "krallin";
121 repo = "tini";
122 rev = tiniRev;
123 hash = tiniHash;
124 };
125
126 # Do not remove static from make files as we want a static binary
127 postPatch = "";
128
129 buildInputs = [
130 glibc
131 glibc.static
132 ];
133
134 env.NIX_CFLAGS_COMPILE = "-DMINIMAL=ON";
135 };
136
137 moby-src = fetchFromGitHub {
138 owner = "moby";
139 repo = "moby";
140 tag = mobyRev;
141 hash = mobyHash;
142 };
143
144 moby = buildGoModule (
145 lib.optionalAttrs stdenv.hostPlatform.isLinux {
146 pname = "moby";
147 inherit version;
148
149 src = moby-src;
150
151 vendorHash = null;
152
153 nativeBuildInputs = [
154 makeBinaryWrapper
155 pkg-config
156 go-md2man
157 go
158 libtool
159 installShellFiles
160 ];
161
162 buildInputs = [
163 sqlite
164 ]
165 ++ lib.optionals withLvm [ lvm2 ]
166 ++ lib.optionals withBtrfs [ btrfs-progs ]
167 ++ lib.optionals withSystemd [ systemd ]
168 ++ lib.optionals withSeccomp [ libseccomp ];
169
170 extraPath = lib.optionals stdenv.hostPlatform.isLinux (
171 lib.makeBinPath [
172 iproute2
173 iptables
174 e2fsprogs
175 xz
176 xfsprogs
177 procps
178 util-linuxMinimal
179 gitMinimal
180 ]
181 );
182
183 extraUserPath = lib.optionals (stdenv.hostPlatform.isLinux && !clientOnly) (
184 lib.makeBinPath [
185 rootlesskit
186 slirp4netns
187 fuse-overlayfs
188 ]
189 );
190
191 postPatch = ''
192 patchShebangs hack/make.sh hack/make/ hack/with-go-mod.sh
193 '';
194
195 buildPhase = ''
196 runHook preBuild
197
198 export GOCACHE="$TMPDIR/go-cache"
199 # build engine
200 export AUTO_GOPATH=1
201 export DOCKER_GITCOMMIT="${cliRev}"
202 export VERSION="${version}"
203 ./hack/make.sh dynbinary
204
205 runHook postBuild
206 '';
207
208 installPhase = ''
209 runHook preInstall
210
211 install -Dm755 ./bundles/dynbinary-daemon/dockerd $out/libexec/docker/dockerd
212 install -Dm755 ./bundles/dynbinary-daemon/docker-proxy $out/libexec/docker/docker-proxy
213
214 makeWrapper $out/libexec/docker/dockerd $out/bin/dockerd \
215 --prefix PATH : "$out/libexec/docker:$extraPath"
216
217 ln -s ${docker-containerd}/bin/containerd $out/libexec/docker/containerd
218 ln -s ${docker-containerd}/bin/containerd-shim $out/libexec/docker/containerd-shim
219 ln -s ${docker-runc}/bin/runc $out/libexec/docker/runc
220 ln -s ${docker-tini}/bin/tini-static $out/libexec/docker/docker-init
221
222 # systemd
223 install -Dm644 ./contrib/init/systemd/docker.service $out/etc/systemd/system/docker.service
224 substituteInPlace $out/etc/systemd/system/docker.service --replace-fail /usr/bin/dockerd $out/bin/dockerd
225 install -Dm644 ./contrib/init/systemd/docker.socket $out/etc/systemd/system/docker.socket
226
227 # rootless Docker
228 install -Dm755 ./contrib/dockerd-rootless.sh $out/libexec/docker/dockerd-rootless.sh
229 makeWrapper $out/libexec/docker/dockerd-rootless.sh $out/bin/dockerd-rootless \
230 --prefix PATH : "$out/libexec/docker:$extraPath:$extraUserPath"
231
232 runHook postInstall
233 '';
234
235 env.DOCKER_BUILDTAGS = toString (
236 lib.optionals withSystemd [ "journald" ]
237 ++ lib.optionals (!withBtrfs) [ "exclude_graphdriver_btrfs" ]
238 ++ lib.optionals (!withLvm) [ "exclude_graphdriver_devicemapper" ]
239 ++ lib.optionals withSeccomp [ "seccomp" ]
240 );
241
242 meta = docker-meta // {
243 homepage = "https://mobyproject.org/";
244 description = "Collaborative project for the container ecosystem to assemble container-based systems";
245 };
246 }
247 );
248
249 plugins =
250 lib.optionals buildxSupport [ docker-buildx ]
251 ++ lib.optionals composeSupport [ docker-compose ]
252 ++ lib.optionals sbomSupport [ docker-sbom ]
253 ++ lib.optionals initSupport [ docker-init ];
254
255 pluginsRef = symlinkJoin {
256 name = "docker-plugins";
257 paths = plugins;
258 };
259 in
260 buildGoModule (
261 {
262 pname = "docker";
263 inherit version;
264
265 src = fetchFromGitHub {
266 owner = "docker";
267 repo = "cli";
268 # Cannot use `tag` since upstream forgot to tag release, see
269 # https://github.com/docker/cli/issues/5789
270 rev = cliRev;
271 hash = cliHash;
272 };
273
274 vendorHash = null;
275
276 nativeBuildInputs = [
277 makeBinaryWrapper
278 pkg-config
279 go-md2man
280 go
281 libtool
282 installShellFiles
283 ];
284
285 buildInputs =
286 plugins
287 ++ lib.optionals (stdenv.hostPlatform.isLinux) [
288 glibc
289 glibc.static
290 ];
291
292 postPatch = ''
293 patchShebangs man scripts/build/
294 substituteInPlace ./scripts/build/.variables --replace-fail "set -eu" ""
295 ''
296 + lib.optionalString (plugins != [ ]) ''
297 substituteInPlace ./cli-plugins/manager/manager_unix.go --replace-fail /usr/libexec/docker/cli-plugins \
298 "${pluginsRef}/libexec/docker/cli-plugins"
299 '';
300
301 # Keep eyes on BUILDTIME format - https://github.com/docker/cli/blob/${version}/scripts/build/.variables
302 buildPhase = ''
303 runHook preBuild
304
305 export GOCACHE="$TMPDIR/go-cache"
306
307 # Mimic AUTO_GOPATH
308 mkdir -p .gopath/src/github.com/docker/
309 ln -sf $PWD .gopath/src/github.com/docker/cli
310 export GOPATH="$PWD/.gopath:$GOPATH"
311 export GITCOMMIT="${cliRev}"
312 export VERSION="${version}"
313 export BUILDTIME="1970-01-01T00:00:00Z"
314 make dynbinary
315
316 runHook postBuild
317 '';
318
319 outputs = [ "out" ];
320
321 installPhase = ''
322 runHook preInstall
323
324 install -Dm755 ./build/docker $out/libexec/docker/docker
325
326 makeWrapper $out/libexec/docker/docker $out/bin/docker \
327 --prefix PATH : "$out/libexec/docker:$extraPath"
328 ''
329 + lib.optionalString (!clientOnly) ''
330 # symlink docker daemon to docker cli derivation
331 ln -s ${moby}/bin/dockerd $out/bin/dockerd
332 ln -s ${moby}/bin/dockerd-rootless $out/bin/dockerd-rootless
333
334 # systemd
335 mkdir -p $out/etc/systemd/system
336 ln -s ${moby}/etc/systemd/system/docker.service $out/etc/systemd/system/docker.service
337 ln -s ${moby}/etc/systemd/system/docker.socket $out/etc/systemd/system/docker.socket
338 ''
339 # Required to avoid breaking cross builds
340 + lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
341 # completion (cli)
342 installShellCompletion --cmd docker \
343 --bash <($out/bin/docker completion bash) \
344 --fish <($out/bin/docker completion fish) \
345 --zsh <($out/bin/docker completion zsh)
346 ''
347 + ''
348 runHook postInstall
349 '';
350
351 doInstallCheck = true;
352 nativeInstallCheckInputs = [ versionCheckHook ];
353 versionCheckProgramArg = "--version";
354
355 passthru = {
356 # Exposed for tarsum build on non-linux systems (build-support/docker/default.nix)
357 inherit moby-src;
358 tests = lib.optionalAttrs (!clientOnly) { inherit (nixosTests) docker; };
359 };
360
361 meta = docker-meta // {
362 homepage = "https://www.docker.com/";
363 description = "Open source project to pack, ship and run any application as a lightweight container";
364 longDescription = ''
365 Docker is a platform designed to help developers build, share, and run modern applications.
366
367 To enable the docker daemon on NixOS, set the `virtualisation.docker.enable` option to `true`.
368 '';
369 mainProgram = "docker";
370 inherit knownVulnerabilities;
371 };
372 }
373 // lib.optionalAttrs (!clientOnly) {
374 # allow overrides of docker components
375 # TODO: move packages out of the let...in into top-level to allow proper overrides
376 inherit
377 docker-runc
378 docker-containerd
379 docker-tini
380 moby
381 ;
382 }
383 );
384in
385{
386 # Get revisions from
387 # https://github.com/moby/moby/tree/${version}/hack/dockerfile/install/*
388 docker_25 =
389 let
390 version = "25.0.13";
391 in
392 callPackage dockerGen {
393 inherit version;
394 # Upstream forgot to tag release
395 # https://github.com/docker/cli/issues/5789
396 cliRev = "43987fca488a535d810c429f75743d8c7b63bf4f";
397 cliHash = "sha256-OwufdfuUPbPtgqfPeiKrQVkOOacU2g4ommHb770gV40=";
398 mobyRev = "v${version}";
399 mobyHash = "sha256-X+1QG/toJt+VNLktR5vun8sG3PRoTVBAcekFXxocJdU=";
400 runcRev = "v1.2.5";
401 runcHash = "sha256-J/QmOZxYnMPpzm87HhPTkYdt+fN+yeSUu2sv6aUeTY4=";
402 containerdRev = "v1.7.27";
403 containerdHash = "sha256-H94EHnfW2Z59KcHcbfJn+BipyZiNUvHe50G5EXbrIps=";
404 tiniRev = "369448a167e8b3da4ca5bca0b3307500c3371828";
405 tiniHash = "sha256-jCBNfoJAjmcTJBx08kHs+FmbaU82CbQcf0IVjd56Nuw=";
406 };
407
408 docker_28 =
409 let
410 version = "28.4.0";
411 in
412 callPackage dockerGen {
413 inherit version;
414 cliRev = "v${version}";
415 cliHash = "sha256-SgePAc+GvjZgymu7VA2whwIFEYAfMVUz9G0ppxeOi7M=";
416 mobyRev = "v${version}";
417 mobyHash = "sha256-hiuwdemnjhi/622xGcevG4rTC7C+DyUijE585a9APSM=";
418 runcRev = "v1.3.0";
419 runcHash = "sha256-oXoDio3l23Z6UyAhb9oDMo1O4TLBbFyLh9sRWXnfLVY=";
420 containerdRev = "v1.7.28";
421 containerdHash = "sha256-vz7RFJkFkMk2gp7bIMx1kbkDFUMS9s0iH0VoyD9A21s=";
422 tiniRev = "369448a167e8b3da4ca5bca0b3307500c3371828";
423 tiniHash = "sha256-jCBNfoJAjmcTJBx08kHs+FmbaU82CbQcf0IVjd56Nuw=";
424 };
425
426}