Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ollama service #972

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
./services/cachix-agent.nix
./services/dnsmasq.nix
./services/emacs.nix
./services/ollama.nix
./services/eternal-terminal.nix
./services/github-runner
./services/gitlab-runner.nix
Expand Down
95 changes: 95 additions & 0 deletions modules/services/ollama.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{ config, lib, pkgs, ... }:

with lib;

let

cfg = config.services.ollama;

in {
options = {
services.ollama = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable the Ollama Daemon.";
};

package = mkOption {
type = types.path;
default = pkgs.ollama;
description = "This option specifies the ollama package to use.";
};

host = mkOption {
type = types.str;
default = "127.0.0.1";
example = "0.0.0.0";
description = ''
The host address which the ollama server HTTP interface listens to.
'';
};

port = mkOption {
type = types.port;
default = 11434;
example = 11111;
description = ''
Which port the ollama server listens to.
'';
};

home = lib.mkOption {
type = types.str;
default = "%S/ollama";
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same here

example = "/home/foo";
description = ''
The home directory that the ollama service is started in.
'';
};

models = mkOption {
type = types.str;
default = "%S/ollama/models";
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need some help here. I didn't get why in nixpkgs:

https://github.com/NixOS/nixpkgs/blob/be45e3445c7fd559f99f0581d807b1e32b381129/nixos/modules/services/misc/ollama.nix#L35

authors used string formatting specifier %S by default, without inserting anything there and just directly passing into environmental variable:

https://github.com/NixOS/nixpkgs/blob/be45e3445c7fd559f99f0581d807b1e32b381129/nixos/modules/services/misc/ollama.nix#L137

In ollama code, I can't find any string formatting related to models destination path. Am I missing something?

Also, actually, ollama uses $HOME/.ollama/models by default:

https://github.com/ollama/ollama/blob/89c79bec8cf7a7b04f761fcc5306d2edf47a4164/envconfig/config.go#L294

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is systemd‐specific syntax, documented in systemd.unit(5). I believe it would ordinarily expand to /var/lib, but because of the DynamicUser sandboxing it acts slightly differently (per systemd.exec(5)):

If DynamicUser= is used, the logic for CacheDirectory=, LogsDirectory= and StateDirectory= is slightly altered: the directories are created below /var/cache/private, /var/log/private and /var/lib/private, respectively, which are host directories made inaccessible to unprivileged users, which ensures that access to these directories cannot be gained through dynamic user ID recycling. Symbolic links are created to hide this difference in behaviour. Both from perspective of the host and from inside the unit, the relevant directories hence always appear directly below /var/cache, /var/log and /var/lib.

Since we don’t have the fancy DynamicUser sandboxing on macOS, you can just read this as /var/lib.

So basically we have a choice here. The thing that would best match NixOS is to define a user for this to run as (see modules/services/gitlab-runner.nix, modules/services/hercules-ci-agent/default.nix, modules/services/ofborg/default.nix, and modules/services/buildkite-agents.nix for examples), set the daemon to run as that user, and use paths under /var/lib here (although I don’t think that directory is commonly used on macOS). (I believe the current state of the PR would run Ollama as root, which is definitely not what we want.)

However, defining users on macOS is a bit annoying – they show up in System Settings and can potentially cause fuss on system upgrades unless you use a ~100 UID range that Apple keeps encroaching on and that Nix already puts 32 users in. So an alternative would be to define a launchd.agent instead and default this stuff to $HOME/.ollama or $HOME/LIbrary/Application Support/ollama or something. That would isolate Ollama less than the NixOS module does, and mean that every interactive user gets their own copy of the Ollama data, but I don’t know if that really matters.

Ideally we’d have a better story for defining daemon users, but for now the latter approach may be more practical.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, seems that I'll return ollama.user.agents back and use the same default as in ollama: $HOME/.ollama/models.

example = "/path/to/ollama/models";
description = ''
The directory that the ollama service will read models from and download new models to.
'';
};

environmentVariables = mkOption {
type = types.attrsOf types.str;
default = { };
example = {
OLLAMA_LLM_LIBRARY = "cpu";
HIP_VISIBLE_DEVICES = "0,1";
};
description = ''
Set arbitrary environment variables for the ollama service.

Be aware that these are only seen by the ollama server (launchd daemon),
not normal invocations like `ollama run`.
Since `ollama run` is mostly a shell around the ollama server, this is usually sufficient.
'';
};
};
};

config = mkIf cfg.enable {

environment.systemPackages = [ cfg.package ];

launchd.daemons.ollama = {
path = [ config.environment.systemPath ];

environment = cfg.environmentVariables // {
HOME = cfg.home;
OLLAMA_MODELS = cfg.models;
OLLAMA_HOST = "${cfg.host}:${toString cfg.port}";
};

serviceConfig.ProgramArguments = [ "${cfg.package}/bin/ollama" "serve" ];
serviceConfig.RunAtLoad = true;
};
};
}
Loading