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
Merged

Conversation

@costrouc
Copy link
Contributor

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 requested review from FRidh and jonringer as code owners Aug 6, 2020
@costrouc costrouc marked this pull request as draft Aug 6, 2020
@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
Contributor 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 costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from afee50f to d060a31 Aug 6, 2020
@costrouc costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from d060a31 to db82ca1 Aug 6, 2020
@costrouc
Copy link
Contributor 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 costrouc:nixos-jupyterhub-service branch 4 times, most recently from adc973e to bd36e0e Aug 6, 2020
@costrouc costrouc marked this pull request as ready for review Aug 7, 2020
@costrouc
Copy link
Contributor 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
Contributor Author

costrouc commented Aug 7, 2020

Not sure why the tests are failing

@jonringer
Copy link
Contributor

jonringer commented Aug 7, 2020

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

@costrouc
Copy link
Contributor 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
@chiroptical chiroptical mentioned this pull request Aug 7, 2020
4 of 10 tasks complete
@costrouc costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from bd36e0e to a6d8b9b Aug 7, 2020
@ofborg ofborg bot requested a review from zimbatm Aug 7, 2020
@jonringer
Copy link
Contributor

jonringer commented Aug 7, 2020

cc @Infinisil does this look right to you?

@costrouc costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from a6d8b9b to 2033a83 Aug 7, 2020
Copy link
Contributor

aanderse left a comment

Few minor nitpicks you may or may not find useful.


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

This comment has been minimized.

@aanderse

aanderse Aug 8, 2020 Contributor

defaultText could be useful.

This comment has been minimized.

@costrouc

costrouc Aug 8, 2020 Author Contributor

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; [

This comment has been minimized.

@aanderse

aanderse Aug 8, 2020 Contributor

defaultText could be useful.

@costrouc costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from 2033a83 to b1b1235 Aug 8, 2020
@costrouc
Copy link
Contributor Author

costrouc commented Aug 9, 2020

@aanderse I have made your suggested changes.

Copy link
Contributor

jonringer left a comment

diff LGTM

I didn't do any testing though.

cc @Infinisil for module best practices

@FRidh
FRidh approved these changes Aug 10, 2020
costrouc added 4 commits Aug 6, 2020
@costrouc costrouc force-pushed the costrouc:nixos-jupyterhub-service branch from b1b1235 to 86b458a Aug 10, 2020
@jonringer
Copy link
Contributor

jonringer commented Aug 10, 2020

I'm not going to delay this forever, LGTM

@jonringer jonringer merged commit b1934ec into NixOS:master Aug 10, 2020
16 checks passed
16 checks passed
tests tests
Details
tests
Details
Evaluation Performance Report Evaluator Performance Report
Details
grahamcofborg-eval ^.^!
Details
grahamcofborg-eval-check-maintainers matching changed paths to changed attrs...
Details
grahamcofborg-eval-check-meta config.nix: checkMeta = true
Details
grahamcofborg-eval-darwin nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./pkgs/t
Details
grahamcofborg-eval-lib-tests nix-build --arg pkgs import ./. {} ./lib/tests/release.nix
Details
grahamcofborg-eval-nixos nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./nixos/
Details
grahamcofborg-eval-nixos-manual nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./nixos/
Details
grahamcofborg-eval-nixos-options nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./nixos/
Details
grahamcofborg-eval-nixpkgs-manual nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./pkgs/t
Details
grahamcofborg-eval-nixpkgs-tarball nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./pkgs/t
Details
grahamcofborg-eval-nixpkgs-unstable-jobset nix-instantiate --arg nixpkgs { outPath=./.; revCount=999999; shortRev="86b458a"; rev="86b458a70c6bd95904a576f2969efedd08018f05"; } ./pkgs/t
Details
grahamcofborg-eval-package-list nix-env -qa --json --file .
Details
grahamcofborg-eval-package-list-no-aliases nix-env -qa --json --file . --arg config { allowAliases = false; }
Details
@costrouc costrouc deleted the costrouc:nixos-jupyterhub-service branch Aug 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.