Running a docker-compose file automatically

Is there a facility in NixOS that allows me to include a single docker-compose.yml file into my configuration and have that been run automatically on startup from a user?

I am aware of virtualisation.oci-containers.containers and of virtualisation.arion.
However I do not wish to replace the compose file with .nix language, since it is not written by me, is quite complex and I do not want to translate it all. It is also subject to change and I don’t want to have to translate it regularly.

1 Like

There’s no module option to do that to my knowledge, I think largely because docker-compose handles all its own orchestration, so there’s no need for additional orchestration options like what virtualization.oci-containers provides. Writing a systemd unit to start docker-compose yourself is pretty trivial. Something like:

systemd.services.my-docker-compose = {
    script = ''
      docker-compose -f ${./path-to/docker-compose.yml}
    '';
    wantedBy = ["multi-user.target"];
    # If you use podman
    after = ["podman.service" "podman.socket"];
    # If you use docker
    # after = ["docker.service" "docker.socket"];
};

Replace the ${./path/to/docker-compose.yml} with whatever mechanism you use to get the compose file at runtime, of course.

When using podman you’ll also need to enable the docker socket virtualization to make docker-compose work with it, hence you need to add an after for it too.

You’ll probably need to do a little bit of extra work to clean up unstopped containers, add an ExecStop, and suchlike.

All that said, I’d recommend using NixOS modules instead of someone’s docker-compose scripts whenever possible. If you’re trying to deploy a service that has a NixOS module, seriously consider whether you need to use docker containers. It’ll be significantly easier to maintain something deployed with a NixOS module, more secure due to sensible upgrade schedules for all libraries, save disk space and system memory, and give you real, versioned releases you can rely on.

4 Likes

I must admit that I find docker services to be much more maintainable than nixos modules. With nixos modules I often need to wait much longer for packages to update or do it myself. Sometimes the person who created the update PR did something wrong which usually takes several days to resolve, where as docker containers are usually maintained by the same people who created the software that runs in it.

Also some nixos modules are a pain to update. I.e. nextcloud. Especially if I don’t update for a longer-ish time.

I find that’s rare, though it’s often stated. The nextcloud containers, for example, are maintained by a different team.

But to each their own; the reason I find NixOS modules more maintainable is because you don’t need to bridge the nix/docker worlds to do so, so if you stick to updating when NixOS does it ends up being less work, assuming you can rely on the maintainer.

It can almost entirely be handled by CI, especially if you add tests on top.

Why could i get
nixos my-docker-compose-start[8340]: /nix/store/wg8zk4mqhap4ac4njxlfxx88f0rpqcin-unit-script-my-docker-compose-start/bin/my-docker-compose-start: line 3: docker-compose: command not found
error when try to sudo nixos-rebuild switch?

i have virtualisation.docker.enable = true; in the configuration.nix, isnt that enough?

caveat: No specific knowledge about the docker module(s) in NixOS.

What is this? Is it a little script you’re inlining somewhere with writeBinScript or similar?

Nix can’t ~natively object to missing dependencies in a shell script. It’ll either need you to do something like:

  • set a path on the service definition that contains the right package (systemd.services.<name>.path)
  • give the script a nix-shell shebang (this will come with some per-invocation overhead)
  • reference the dependency’s package inline with interpolation
  • inject a PATH into the script
  • use an additional tool to find/substitute dependencies

The first of these is service specific, so it might not be ideal if you re-use the script in other contexts.

I wrote a post (not service specific) about the main strategies for supplying dependencies for a shell script with Nix (no-look, no-leap Shell script dependencies) that includes examples of the other approaches and provides a little more background on the tradeoffs.


that’s what i have in the configuration.nix, i just pasted it from the solution

Sorry–should’ve read up :slight_smile:

I imagine you can do one of the below:

  • add a path attr to the service like path = [ pkgs.docker-compose ];
  • change the script to use ${pkgs.docker-compose}/bin/docker-compose

(this assumes you have pkgs in scope; you may need to adapt this to whatever your broader config does here)

1 Like

i’ve added " path = [ pkgs.docker-compose ];" to the service and now it doesnt output any errors, thanks!

1 Like