使用systemd进行资源隔离的JupyterHub Spawner
项目描述
功能 | 要求 | 安装 | 配置 | 获取帮助 | 许可证
systemdspawner
systemdspawner 允许 JupyterHub 使用 systemd 启动单用户笔记本服务器。
功能
如果您想使用 Linux 容器(Docker、rkt 等)以实现隔离和安全性,但又不想处理容器镜像管理的头痛和复杂性,那么您应该使用 SystemdSpawner。
使用 systemdspawner,您可以使用熟悉的传统系统管理工具,无论您喜欢还是不喜欢,而不需要学习额外的容器相关工具。
以下功能目前可用:
-
限制每个用户允许的最大内存。
如果他们请求超过此内存,则不会授予(
malloc
将失败,具体表现取决于您使用的编程语言)。 -
限制每个用户可用的最大 CPU。
-
为用户提供公平的调度,独立于他们运行的进程数量。
例如,如果用户 A 正在运行 100 个占用 CPU 的进程,通常意味着用户 B 的 2 个占用 CPU 的进程将永远得不到足够的 CPU 时间,因为传统的调度是按进程进行的。使用 Systemd Spawner,这两个用户的进程将作为一个整体获得相同数量的 CPU 时间,无论运行了多少个进程。如果用户是 B,这是一个好消息。
-
精确统计内存和 CPU 使用情况(通过 cgroups,systemd 内部使用)。
您可以使用
systemd-cgtop
检查此功能。 -
/tmp
隔离。每个用户都获得自己的
/tmp
,以防止意外信息泄露。 -
在系统上以特定本地用户身份启动笔记本服务器。
这可以替代使用 SudoSpawner 的需要。
-
限制用户在笔记本内sudo到root(或作为其他用户)的能力。
这是一项额外的安全措施,以确保 jupyterhub 笔记本实例的妥协不会允许root访问。
-
限制用户可以写入的路径。
这允许将
/
设置为只读,并且只授予特定路径的写入权限,以提高安全性。 -
自动将每个用户的笔记本日志收集到
journald
中,它还处理日志轮换。 -
使用 Systemd 的 动态用户 功能动态分配用户。与 tmpauthenticator 结合使用非常有用。
要求
Systemd 和 Linux 发行版
建议使用 SystemdSpawner 1 与 systemd 版本 245 或更高版本一起使用,但 可能 也适用于 systemd 版本 243-244。以下是使用 systemd 并有推荐版本的 Linux 发行版的示例。
- Ubuntu 20.04+
- Debian 11+
- Rocky 9+ / CentOS 9+
可以使用 systemctl --version
命令来验证是否使用 systemd,以及使用的是哪个版本。
内核配置
某些内核选项需要启用才能使 CPU / 内存限制功能正常工作。如果没有启用这些选项,CPU / 内存限制将静默失败。您可以通过运行 check-kernel.bash
脚本来检查您的内核是否支持这些功能。
root 权限
目前,JupyterHub 必须以 root 用户身份运行才能使用 Systemd Spawner。需要以 root 用户身份运行 systemd-run
才能设置内存和 CPU 限制。简单的 sudo 规则不起作用,因为对 systemd-run
的无限制访问等同于 root。我们将很快探索加固方法。
本地用户
如果以c.SystemdSpawner.dynamic_users = False
(默认值)运行,则每个用户的服务器都会以本地Unix用户账户的身份启动。因此,此启动器要求所有进行身份验证的用户已在机器上拥有本地账户。
如果以c.SystemdSpawner.dynamic_users = True
运行,则不需要本地用户账户。Systemd将自动根据需要创建动态用户。有关详细信息,请参阅这篇博客文章。
安装
您可以使用以下命令从PyPI安装它:
pip install jupyterhub-systemdspawner
您可以在jupyterhub_config.py
文件中使用以下行为您自己的jupyterhub启用它:
c.JupyterHub.spawner_class = "systemd"
请注意,为了确认systemdspawner已正确安装在jupyterhub环境中,新生成的配置文件应在配置行上方列出systemdspawner
作为可用的启动器类之一(在注释中)。
配置
有许多配置选项供您选择!您应将这些选项全部放入您的jupyterhub_config.py
文件中
mem_limit
cpu_limit
user_workingdir
username_template
default_shell
extra_paths
unit_name_template
unit_extra_properties
isolate_tmp
isolate_devices
disable_user_sudo
readonly_paths
readwrite_paths
dynamic_users
mem_limit
指定每个用户可以使用的最大内存。它可以指定为绝对字节值。您可以使用后缀K
、M
、G
或T
分别表示千字节、兆字节、吉字节或太字节。将其设置为None
将禁用内存限制。
即使您希望单个用户使用尽可能多的内存,仍然建议将内存限制设置为总物理内存的80-90%。这可以防止一个用户意外地通过OOM(内存不足)而使整个机器崩溃。
c.SystemdSpawner.mem_limit = '4G'
默认值为None
,不提供内存限制。
此信息作为整数字节的环境变量MEM_LIMIT
暴露给单用户服务器。
cpu_limit
表示每个用户可以使用的总CPU核心数的浮点数。1
代表一个完整的CPU,4
代表4个完整的CPU,0.5
代表半个CPU,等等。此值最终转换为百分比并四舍五入到最接近的整数百分比,即1.5
转换为150%,0.125
转换为12%,等等。
c.SystemdSpawner.cpu_limit = 4.0
默认值为None
,不提供CPU限制。
此信息作为浮点数环境变量CPU_LIMIT
暴露给单用户服务器。
注意:systemd v231中存在一个错误,该错误阻止CPU限制设置为大于100%的值。
CPU公平性
与cpu_limit
完全无关的是CPU公平性的概念——在没有限制的情况下,每个用户应平等地访问所有CPU。在正常情况下,对于Jupyter笔记本,这并不完全适用,因为CPU调度是在进程级别而不是用户级别进行的。这意味着运行100个进程的用户比运行一个进程的用户有100倍多的CPU访问权限。这远非理想情况。
由于每个用户的笔记本服务器都运行在其自己的Systemd服务中,因此这个问题得到了缓解——来自用户笔记本服务器的所有进程都在一个cgroup中运行,并且cgroups在CPU调度中被平等对待。因此,独立于每个用户正在运行的进程数量,他们都会平等地访问CPU。这对于大多数情况来说非常理想,因为它允许用户在没有人使用CPU时爆发式地使用所有CPU,并强制他们在其他用户想要使用CPU时自动释放。
user_workingdir
为每个用户的笔记本服务器生成目录。当用户打开他们的笔记本服务器时,他们会看到这个目录。通常,这是用户的家目录。
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
c.SystemdSpawner.user_workingdir = '/home/{USERNAME}'
默认为用户的家目录。如果dynamic_users
为真,则不予以尊重。
username_template
每个被生成用户应该以Unix用户名模板来生成。
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
此用户应该已经在系统中存在。
c.SystemdSpawner.username_template = 'jupyter-{USERNAME}'
如果dynamic_users
设置为True,则不予以尊重。
default_shell
笔记本终端默认要使用的shell。将SHELL
环境变量设置为这个值。
c.SystemdSpawner.default_shell = '/bin/bash'
默认为JupyterHub进程中的SHELL
环境变量的值,如果没有设置SHELL
,则为/bin/bash
。
extra_paths
应添加到生成笔记本服务器的PATH
环境变量的路径列表。这比设置env
属性更容易,因为您想要添加到PATH,而不是完全替换它。当您想默认将virtualenv或conda安装添加到用户的PATH
中时,这非常有用。
c.SystemdSpawner.extra_paths = ['/home/{USERNAME}/conda/bin']
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
默认为[]
,不会向PATH
添加任何额外路径。
unit_name_template
用于为每个用户笔记本服务器形成Systemd服务单元名的模板。这允许在相同机器上使用Systemd Spawner区分多个jupyterhubs。应只包含[a-zA-Z0-9_-]。
c.SystemdSpawner.unit_name_template = 'jupyter-{USERNAME}-singleuser'
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
默认为jupyter-{USERNAME}-singleuser
。
unit_extra_properties
用于向生成的Jupyterhub单元添加任意属性的键值对字典。
c.SystemdSpawner.unit_extra_properties = {'LimitNOFILE': '16384'}
有关瞬态单元中可用的每个单元属性,请参阅man systemd-run
的详细信息。
每个参数值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
默认为{}
,不会向瞬态范围添加任何额外属性。
isolate_tmp
将此设置为true为每个用户提供单独的、私有的/tmp
。这对于防止意外泄露其他信息非常有用 - 可能您使用的库/工具在您不知情的情况下创建了/tmp文件,从而导致信息泄露。
c.SystemdSpawner.isolate_tmp = True
默认为false。
isolate_devices
将此设置为true为每个用户提供单独的、私有的/dev
。这防止用户直接访问硬件设备,这可能是潜在的安全问题的来源。/dev/null
、/dev/zero
、/dev/random
和ttyp伪设备已经挂载,所以当此功能启用时,大多数用户应该看不到任何变化。
c.SystemdSpawner.isolate_devices = True
默认为false。
disable_user_sudo
设置为true,这阻止用户使用sudo
(或任何其他方式)成为其他用户(包括root)。这有助于在用户也有机器上的sudo权限的情况下,如果用户的凭证被泄露,限制损坏。现在,基于Web的漏洞只能损坏用户的个人物品,而不是获得完整的root权限。
c.SystemdSpawner.disable_user_sudo = True
默认为True。
readonly_paths
应为用户的笔记本服务器只读挂载的文件系统路径列表。这将覆盖可能存在的任何文件系统权限。可以标记为readwrite的只读路径的子路径可以通过readwrite_paths
标记。这有助于将/
标记为只读,并仅允许笔记本用户写入的路径。如果此处列出的路径不存在,您将得到一个错误。
c.SystemdSpawner.readonly_paths = ['/']
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
默认为None
,禁用此功能。
readwrite_paths
应为用户的笔记本服务器只读挂载的文件系统路径列表。这只有在使用readonly_paths
使某些路径只读时才有意义 - 这可以用来使特定路径可读写。这不会覆盖文件系统权限 - 用户需要具有写入这些路径的适当权限。
c.SystemdSpawner.readwrite_paths = ['/home/{USERNAME}']
在此配置值中的{USERNAME}
和{USERID}
将被扩展为被生成用户的适当值。
默认为None
,禁用此功能。
dynamic_users
为每个用户动态分配系统用户。
使用Systemd的DynamicUser=功能为每个hub用户动态创建一个新的系统用户。他们的家目录设置在/var/lib/{USERNAME}下,并且随时间持久化。当用户的服务器不再运行时,系统用户将被释放。
请参阅http://0pointer.net/blog/dynamic-users-with-systemd.html获取更多信息。
切片
在指定的systemd切片中运行生成的笔记本。这允许应用聚合配置,该配置将适用于所有启动的单元。这可以用来控制所有笔记本用户可以使用的总内存量。
请参阅https://samthursfield.wordpress.com/2015/05/07/running-firefox-in-a-cgroup-using-systemd/以了解这可能会是什么样子。
有关详细配置,请参阅manpage
获取帮助
我们鼓励您在Jupyter Discourse论坛中提问。
许可证
我们采用共享版权模式,使所有贡献者都能保留其贡献的版权。
所有代码均在修订版BSD许可证的条款下授权。
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪一个,请了解有关安装包的更多信息。
源分布
构建分布
jupyterhub-systemdspawner-1.0.1.tar.gz的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 8d614f19d89564321fe55d80ecd134a0e2bf276274d45861495c9bb5a80add28 |
|
MD5 | 957d823814b01ad718ae4efc48559100 |
|
BLAKE2b-256 | 067da5245a204a2b8a0d2f5ea0bc48ae81d9fce543d66aa1851b75e2b836d4dd |
jupyterhub_systemdspawner-1.0.1-py3-none-any.whl的哈希
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 25512c3493874b3926f12f1a12018b08f2aba91d03fbf7fc0eb63d700be6e9f7 |
|
MD5 | dd7ebc46aa1506eee1a009dbc1835995 |
|
BLAKE2b-256 | 6e23f90db6f6ff2f6ce7b4653f0c92c978e97729ebc1324a6523a0e908d49142 |