Minimal Nix Microservices

It is possible to use Nix to easily set up microservices. There is a misconception about microservices which dictates that they should run on a separate machine, but you do not actually have to do that, and by not running them on a seperate machine, you avoid latency costs (as well as other complexities) too.

With Nix and systemd it also becomes rather painless. Systemd manages logging of services and ensures they restart on failure, while Nix is used to setup the service itself. You can also use Unix file permissions to manage what microservice has access to what.

Here is a minimal example of a microservice for Nix:

Sample: Nix config
users.users.hiservice = {
     isNormalUser = false;
     isSystemUser = true;
     group = "greeters";
   };
   users.groups.greeters = { };
   environment = {
     SOCKET_PATH = "/run/hi-service.sock"
   }
 systemd.services.hiservice = {
     name = "hi-service.socket";
     enable = true;
     group = "greeters";
     user = "hiservice";
     wantedBy = [ "multi-user.target" ];
     description = "My microservice";
     serviceConfig.SocketUser = "hiservice";
     serviceConfig.SocketGroup = "greeters";
     serviceConfig.ExecStartPre = "rm -f $SOCKET_PATH";
     script = ''
     set -e
     while true; do echo "HI" | nc -l -U "$SOCKET_PATH"; done
     '';
     };
   };
};
	

By adding .socket to the name, you indicate to systemd that this is a socket service.

Systemd socket service documentation

Now, any user that is part of the greeters group should be able to access this hiservice and communicate with it to get a greeting.

In Javascript, a service talking to it could look something like this:

const net = require('net');
function afellowgreeter(message) {
    const client = net.createConnection({ path: '/run/hi-service.sock' });
    client.on('connect', () => {
        client.write(message);
    });
    client.on('data', (data) => {
        console.log(data.toString());
        client.end();
    });
    client.on('error', (err) => {
        console.error('Error:', err.message);
    });
}
afellowgreeter('Hello there!');

This is great if you’re using a niche language that doesn’t support whatever functionality you’re missing: just create a small microservice with a socket to handle that particular functionality! This was one of the foundational ideas behind microservices to begin with, and by using Nix the packaging of all these different services become rather easy.