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

nixos/jupyterhub: init service #94783

Merged
merged 4 commits into from Aug 10, 2020

Conversation

costrouc
Copy link
Member

@costrouc costrouc commented Aug 6, 2020

Motivation for this change

I work at Quansight and we do a lot of python data science deployments with jupyterhub and related tooling that allows for scalable data science environments. This will be my first contributed nixos module so I am happy for feedback. The goal is to have an opinionated standard jupyterhub deployment (with extraConfig option so that you can do what you want). This opinionated service will use pam for authentication and systemd for launching processes for users. Though I will design this in mind so it is easily extensible to add oauth authentication for users and changing the spawner to use Docker, Kubernetes, etc.

Once we have this component in place I see some interesting comparisons with this nixos module and https://tljh.jupyter.org/en/latest/ and https://zero-to-jupyterhub.readthedocs.io/en/latest/. I want to make reproducible data science environments. From using tooling such as terraform and ansible a lot for these types of deployments I am excited to see if we could replace those tools with this using nixops for example. Anyways that should be enough motiviation as to why I think this PR is important.

Things needing to be done for this PR to be complete:

  • get jupyterhub service running
  • provide entry hooks for customizing jupyterlab being run and the possibilty for multiple kernels (thanks to the nixos/jupyter module I will likely be using that).
  • add a nixos test for jupyterhub: authentication with server, demonstrate launching jupyterlab instance, and running python commands
Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS linux)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@costrouc costrouc marked this pull request as draft August 6, 2020 12:04
@FRidh
Copy link
Member

FRidh commented Aug 6, 2020

I think where possible the jupyter module and the jupyterhub module should be similar. Not saying what is in the jupyter module is the way, but do aim for unity there.

Please also ping other interested parties such as past contributors to the jupyter module as well as the jupyterWith people, because I know they wanted to pull that into nixpkgs as well.

@costrouc
Copy link
Member Author

costrouc commented Aug 6, 2020

@FRidh completely agree.

Also some context about what jupyterhub is since I had some misconceptions about it as well. Jupyterhub has the unfortunate name of "jupyter" in it because it is not restricted to the python/jupyter ecosystem. It is really a standard way to authenticate users, spawn given services for those users, and manage those resources for the user. It supports authentication via ldap, oauth, pam, and othre. It spawns services for users RStudio, jupyter, and running desktop applications (think legacy windows applications running with wine at national labs) https://github.com/yuvipanda/jupyter-desktop-server.

Also I have no plan to work on getting jupyterlab extensions working here but I do want to be able to support kernels in the many different languages.

cc: @kristoff3r, @MMesch, @guaraqe (hope I didn't leave anyone else out)

@costrouc
Copy link
Member Author

costrouc commented Aug 6, 2020

The current implementation is enough to test that things work. Still need to add the kernel support done in the jupyter module.
Here is a basic nixops test that I've been doing before writing a nixos test.

deployment.nix

let pkgs = import <nixpkgs> { };
in {
  machine = {
    deployment.targetEnv = "libvirtd";
    deployment.libvirtd.imageDir = "/var/lib/libvirt/images";

    services.jupyterhub = {
      enable = true;
      port = 80;
      kernels = import ./kernels.nix { inherit pkgs; };
    };

    networking.firewall.allowedTCPPorts = [ 80 ];

    security.pam.services.login.setLoginUid = false;

    users.users.costrouc = {
      isNormalUser = true;
      home = "/home/costrouc";
      description = "Chris Ostrouchov";
      extraGroups = [ "wheel"];
      hashedPassword = "$6$og2KAu0wj$ce4zFxN5bd0fz1q/jTDO6o.wcxtm6lhXOZ.Dno34W5Rih1IJVjyiRJiIIqVxNF309XK0cP.F0eNu7ttW5qF8N.";
    };
  };
}

kernels.nix

{ pkgs }:

{
  python27Kernel = (
      let env = (pkgs.python2.withPackages(p: with p; [
            ipykernel numpy scipy
          ])).override (args: { ignoreCollisions = true; });
      in {
        displayName = "Python 2.7";
        argv = ["${env.interpreter}" "-m" "ipykernel_launcher" "-f" "{connection_file}"];
        language = "python";
        logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png";
        logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png";
      });

  python37Kernel = (
    let env = pkgs.python37.withPackages(p: with p; [
          ipykernel numpy scipy
        ]);
    in {
      displayName = "Python 3.7";
      argv = ["${env.interpreter}" "-m" "ipykernel_launcher" "-f" "{connection_file}"];
      language = "python";
      logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png";
      logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png";
    });

  python38Kernel = (
    let env = pkgs.python38.withPackages(p: with p; [
          ipykernel numpy scipy numba nixpkgs
        ]);
    in {
      displayName = "Python 3.8";
      argv = ["${env.interpreter}" "-m" "ipykernel_launcher" "-f" "{connection_file}"];
      language = "python";
      logo32 = "${env}/${env.sitePackages}/ipykernel/resources/logo-32x32.png";
      logo64 = "${env}/${env.sitePackages}/ipykernel/resources/logo-64x64.png";
    });

  cKernel = (
    let env = pkgs.python3.withPackages(p: with p; [
          jupyter-c-kernel
        ]);
    in {
      displayName = "C";
      argv = ["${env.interpreter}" "-m" "jupyter_c_kernel" "-f" "{connection_file}"];
      language = "c";
    });

  rustKernel = {
    displayName = "Rust";
    argv = ["${pkgs.evcxr}/bin/evcxr_jupyter" "--control_file" "{connection_file}"];
    language = "Rust";
  };

  rKernel = (
    let env = pkgs.rWrapper.override { packages = with pkgs.rPackages; [
        IRkernel ggplot2
    ];};
    in {
       displayName = "R";
       argv = ["${env}/bin/R" "--slave" "-e" "IRkernel::main()" "--args" "{connection_file}"];
       language = "R";
    });

  ansibleKernel = (
    let env = (pkgs.python3.withPackages(p: with p; [
          ansible-kernel ansible
        ])).override (args: { ignoreCollisions = true; });
    in {
      displayName = "Ansible";
      argv = ["${env.interpreter}" "-m" "ansible_kernel" "-f" "{connection_file}"];
      language = "ansible";
    });

  bashKernel = (
    let env = pkgs.python3.withPackages(p: with p; [
          bash_kernel
        ]);
    in {
      displayName = "Bash";
      argv = ["${env.interpreter}" "-m" "bash_kernel" "-f" "{connection_file}"];
      language = "Bash";
    });
}

The password is asdf and the service will be running on port 80

@costrouc costrouc force-pushed the nixos-jupyterhub-service branch 4 times, most recently from adc973e to bd36e0e Compare August 7, 2020 17:38
@costrouc costrouc marked this pull request as ready for review August 7, 2020 17:39
@costrouc
Copy link
Member Author

costrouc commented Aug 7, 2020

@jonringer and @FRidh I'd say I'm complete with this PR and I've added the requested changes. Adding the nixos tests might be extremely tricky due to having to store a cookie and following redirects. The example I posted above should launch a multiuser jupyterhub cluster with 7 kernels.

@costrouc
Copy link
Member Author

costrouc commented Aug 7, 2020

Not sure why the tests are failing

@jonringer
Copy link
Contributor

it fails if ofborg doesn't post results, ofborg is just backed-up due to influx of PRs

@costrouc
Copy link
Member Author

costrouc commented Aug 7, 2020

Result of nixpkgs-review pr 94783 1

7 packages built:
- python27Packages.jupyter-c-kernel
- python37Packages.bash_kernel
- python37Packages.jupyter-c-kernel
- python37Packages.jupyterhub-systemdspawner
- python38Packages.bash_kernel
- python38Packages.jupyter-c-kernel
- python38Packages.jupyterhub-systemdspawner

@ofborg ofborg bot requested a review from zimbatm August 7, 2020 20:34
@jonringer
Copy link
Contributor

cc @infinisil does this look right to you?

Copy link
Member

@aanderse aanderse left a comment

Choose a reason for hiding this comment

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

Few minor nitpicks you may or may not find useful.

nixos/modules/services/development/jupyterhub/default.nix Outdated Show resolved Hide resolved

jupyterhubEnv = mkOption {
type = types.package;
default = (pkgs.python3.withPackages (p: with p; [
Copy link
Member

Choose a reason for hiding this comment

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

defaultText could be useful.

Copy link
Member Author

Choose a reason for hiding this comment

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

couldn't get this to work when I tried it. How is this properly used?


jupyterlabEnv = mkOption {
type = types.package;
default = (pkgs.python3.withPackages (p: with p; [
Copy link
Member

Choose a reason for hiding this comment

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

defaultText could be useful.

nixos/modules/services/development/jupyterhub/default.nix Outdated Show resolved Hide resolved
@costrouc
Copy link
Member Author

costrouc commented Aug 9, 2020

@aanderse I have made your suggested changes.

Copy link
Contributor

@jonringer jonringer left a comment

Choose a reason for hiding this comment

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

diff LGTM

I didn't do any testing though.

cc @infinisil for module best practices

@jonringer
Copy link
Contributor

I'm not going to delay this forever, LGTM

@jonringer jonringer merged commit b1934ec into NixOS:master Aug 10, 2020
@costrouc costrouc deleted the nixos-jupyterhub-service branch August 10, 2020 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants