livebook: Use mix release to build instead of escript

The current build of livebook does not work with the new [Livebook
Teams](https://livebook.dev/teams/) features. The problem can be observed by
running the current version of livebook, adding a new team and going to the team
page. The process will crash and the team page will show a 500 error.

The base of the problem is that the escript build method is not officially
supported. This commit changes the livebook package to use the `mix release`
workflow, which is also the one used to build the official Docker container.

Unfortunately, the binary built with `mix release` does not support command line
arguments like the `escript` binary does. Instead, users need to pass in most of
the configuration as environment variables, as documented
[here](https://hexdocs.pm/livebook/readme.html#environment-variables). As a
result, this commit also changes the Livebook service to reflect this new way of
configuring Livebook.

Finally, the Livebook release configuration specifically excludes the
ERTS (Erlang Runtime System), which means that the resulting release cannot run
without Erlang installed.

I have tested the results (both of the package and the service) locally.
This commit is contained in:
Philip Munksgaard 2024-01-23 22:36:52 +01:00
parent 6aee40bc72
commit 897d5670a3
No known key found for this signature in database
GPG key ID: 4CE62A90EFC0B9B2
5 changed files with 84 additions and 73 deletions

View file

@ -202,6 +202,13 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
- `nomad_1_4` has been removed, as it is now unsupported upstream.
- The `livebook` package is now built as a `mix release` instead of an `escript`.
This means that configuration now has to be done using [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) instead of command line arguments.
This has the further implication that the `livebook` service configuration has changed:
- The `erlang_node_short_name`, `erlang_node_name`, `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter.
Use the appropriate [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) inside `environment` to configure the service instead.
## Other Notable Changes {#sec-release-24.05-notable-changes}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

View file

@ -15,11 +15,12 @@ which runs the server.
{
services.livebook = {
enableUserService = true;
port = 20123;
environment = {
LIVEBOOK_PORT = 20123;
LIVEBOOK_PASSWORD = "mypassword";
};
# See note below about security
environmentFile = pkgs.writeText "livebook.env" ''
LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
'';
environmentFile = "/var/lib/livebook.env";
};
}
```
@ -30,14 +31,19 @@ The Livebook server has the ability to run any command as the user it
is running under, so securing access to it with a password is highly
recommended.
Putting the password in the Nix configuration like above is an easy
way to get started but it is not recommended in the real world because
the `livebook.env` file will be added to the world-readable Nix store.
A better approach would be to put the password in some secure
user-readable location and set `environmentFile = /home/user/secure/livebook.env`.
Putting the password in the Nix configuration like above is an easy way to get
started but it is not recommended in the real world because the resulting
environment variables can be read by unprivileged users. A better approach
would be to put the password in some secure user-readable location and set
`environmentFile = /home/user/secure/livebook.env`.
:::
The [Livebook
documentation](https://hexdocs.pm/livebook/readme.html#environment-variables)
lists all the applicable environment variables. It is recommended to at least
set `LIVEBOOK_PASSWORD` or `LIVEBOOK_TOKEN_ENABLED=false`.
### Extra dependencies {#module-services-livebook-extra-dependencies}
By default, the Livebook service is run with minimum dependencies, but

View file

@ -14,58 +14,64 @@ in
package = mkPackageOption pkgs "livebook" { };
environmentFile = mkOption {
type = types.path;
description = lib.mdDoc ''
Environment file as defined in {manpage}`systemd.exec(5)` passed to the service.
This must contain at least `LIVEBOOK_PASSWORD` or
`LIVEBOOK_TOKEN_ENABLED=false`. See `livebook server --help`
for other options.'';
};
erlang_node_short_name = mkOption {
type = with types; nullOr str;
default = null;
example = "livebook";
description = "A short name for the distributed node.";
};
erlang_node_name = mkOption {
type = with types; nullOr str;
default = null;
example = "livebook@127.0.0.1";
description = "The name for the app distributed node.";
};
port = mkOption {
type = types.port;
default = 8080;
description = "The port to start the web application on.";
};
address = mkOption {
type = types.str;
default = "127.0.0.1";
description = lib.mdDoc ''
The address to start the web application on. Must be a valid IPv4 or
IPv6 address.
'';
};
options = mkOption {
type = with types; attrsOf str;
environment = mkOption {
type = with types; attrsOf (nullOr (oneOf [ bool int str ]));
default = { };
description = lib.mdDoc ''
Additional options to pass as command-line arguments to the server.
Environment variables to set.
Livebook is configured through the use of environment variables. The
available configuration options can be found in the [Livebook
documentation](https://hexdocs.pm/livebook/readme.html#environment-variables).
Note that all environment variables set through this configuration
parameter will be readable by anyone with access to the host
machine. Therefore, sensitive information like {env}`LIVEBOOK_PASSWORD`
or {env}`LIVEBOOK_COOKIE` should never be set using this configuration
option, but should instead use
[](#opt-services.livebook.environmentFile). See the documentation for
that option for more information.
Any environment variables specified in the
[](#opt-services.livebook.environmentFile) will supersede environment
variables specified in this option.
'';
example = literalExpression ''
{
cookie = "a value shared by all nodes in this cluster";
LIVEBOOK_PORT = 8080;
}
'';
};
environmentFile = mkOption {
type = with types; nullOr types.path;
default = null;
description = lib.mdDoc ''
Additional dnvironment file as defined in {manpage}`systemd.exec(5)`.
Secrets like {env}`LIVEBOOK_PASSWORD` (which is used to specify the
password needed to access the livebook site) or {env}`LIVEBOOK_COOKIE`
(which is used to specify the
[cookie](https://www.erlang.org/doc/reference_manual/distributed.html#security)
used to connect to the running Elixir system) may be passed to the
service without making them readable to everyone with access to
systemctl by using this configuration parameter.
Note that this file needs to be available on the host on which
`livebook` is running.
For security purposes, this file should contain at least
{env}`LIVEBOOK_PASSWORD` or {env}`LIVEBOOK_TOKEN_ENABLED=false`.
See the [Livebook
documentation](https://hexdocs.pm/livebook/readme.html#environment-variables)
and the [](#opt-services.livebook.environment) configuration parameter
for further options.
'';
example = "/var/lib/livebook.env";
};
extraPackages = mkOption {
type = with types; listOf package;
default = [ ];
@ -81,17 +87,11 @@ in
serviceConfig = {
Restart = "always";
EnvironmentFile = cfg.environmentFile;
ExecStart =
let
args = lib.cli.toGNUCommandLineShell { } ({
inherit (cfg) port;
ip = cfg.address;
name = cfg.erlang_node_name;
sname = cfg.erlang_node_short_name;
} // cfg.options);
in
"${cfg.package}/bin/livebook server ${args}";
ExecStart = "${cfg.package}/bin/livebook start";
};
environment = mapAttrs (name: value:
if isBool value then boolToString value else toString value)
cfg.environment;
path = [ pkgs.bash ] ++ cfg.extraPackages;
wantedBy = [ "default.target" ];
};

View file

@ -9,13 +9,15 @@ import ./make-test-python.nix ({ lib, pkgs, ... }: {
services.livebook = {
enableUserService = true;
port = 20123;
environment = {
LIVEBOOK_PORT = 20123;
LIVEBOOK_COOKIE = "chocolate chip";
LIVEBOOK_TOKEN_ENABLED = true;
};
environmentFile = pkgs.writeText "livebook.env" ''
LIVEBOOK_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
'';
options = {
cookie = "chocolate chip";
};
};
};
};

View file

@ -22,13 +22,9 @@ beamPackages.mixRelease rec {
hash = "sha256-dyKhrbb7vazBV6LFERtGHLQXEx29vTgn074mY4fsHy4=";
};
installPhase = ''
mix escript.build
mkdir -p $out/bin
mv ./livebook $out/bin
postInstall = ''
wrapProgram $out/bin/livebook \
--prefix PATH : ${lib.makeBinPath [ elixir ]} \
--prefix PATH : ${lib.makeBinPath [ elixir erlang ]} \
--set MIX_REBAR3 ${rebar3}/bin/rebar3
'';