Is there a good way to deploy Docker containers on a NixOS machine declaratively, either with nixops or nixos-rebuild? Or would docker-compose be my best bet?
Normally I would use native nix packages, but some packages are a bit cumbersome to setup and docker is supported by upstream or it needs manual setup steps that the docker container has build in.
I only found ways to build docker images based on nix, but not how to deploy containers.
On that note I think I saw a project to handle imperative steps with nixops but I can’t seem to find it. Maybe that’d work?
When you install nix-built packages into a Docker image, you can provide a FROM statement to pull the base image from Dockerhub. If you need a supported base image (like CentOS for instance), you can declaratively pull it by sha256, then install your nixpkgs into it, and when built you will have a file that can be passed to docker load: Nixpkgs 23.11 manual | Nix & NixOS
Once you have a mycontainer.tar.gz, deployment is a matter of getting it to the target machine and running docker load -i mycontainer.tar.gz. If you’re already using NixOps, it can handle this for you – but most environments already have some sort of deployment infrastructure or tooling that does this type of thing.
That is mainly what I found when I searched for a solution. I am though looking for a way to run docker containers on NixOS, esp. for packages that are not in Nix yet. I.e. what docker-compose does, but using the nixos or nixops infrastructure.
Kubenix looks promising, but needs work in the documentation department. The modules have 7 contributors right now. Does anyone know more about the project?
I went looking for this and still haven’t found much other than running a whole Kubernetes stack (which seems like a lot of work). My solution so far has been to write systemd units that manage a docker container, which has been working reasonably well. for instance:
(I know there’s a Prometheus module in NixOS; I wanted a newer version than was available at the time and this was a quick solution)
This could be generalized into a reusable module in the same general way as systemd.services.* to provide an interface vaguely like what currently exists in containers.* for systemd-nspawn containres.
Hopefully there’s a better way though; what I’ve got here works, but it’s not ideal.
Using systemd to manage docker comtainers while not perfect looks like it could make a simple solution for declaratively managing docker containers on a node. Would there be interest if a naive and simple PR was added to nixpkgs to do specifically this? I’m thinking a simple solution would be to use docker compose with a nice configuration and systemd.
I’m curious, how do the Docker containers expose their services outside the container? Does it not require binding the right TCP/UDP ports to the ports inside the container when starting it up?
It depends on which network mode you’re using, but typically one uses --publish xx:yy to forward port xx on the outer host to port yy inside the container. With --network=host, the container shares the host’s network namespace so no forwarding is needed. Some setups give a routable IP to each container on an internal network, with docker network or Calico or Weave or a number of other fancy networking options. The PR I published doesn’t try to address any of those (yet), but it would at least allow the user to set network-related options with extraDockerOptions for each service.
Summary: it’s complicated, and I’m trying to avoid the need to address all possible cases by offering a manual override.
I tried the new docker-containers module and it works perfectly so that I can use it to replace my previous Docker Compose based setup. Summarized here and hope it can help whoever in the same boat.