JupyterHub 配置文件
代码地址:04-jupyterhub-ai-enhanced/config/jupyterhub_config.py at main · prevailna/project-1-jupyter
配置文件
python
import os
c = get_config()
# 日志配置 - 从环境变量获取
c.JupyterHub.log_level = os.environ.get("JUPYTERHUB_LOG_LEVEL", "INFO")
c.Spawner.debug = os.environ.get("SPAWNER_DEBUG", "false").lower() == "true"
# 设置 JupyterLab 为默认界面
c.Spawner.default_url = "/lab"
# 配置 DockerSpawner
c.JupyterHub.spawner_class = "dockerspawner.DockerSpawner"
c.DockerSpawner.image = os.environ.get("DOCKER_NOTEBOOK_IMAGE", "jupyter-ai-user-image")
# 数据持久化
notebook_dir = os.environ.get("DOCKER_NOTEBOOK_DIR", "/home/jovyan/work")
c.DockerSpawner.notebook_dir = notebook_dir
c.DockerSpawner.volumes = {"jupyterhub-user-{username}": notebook_dir}
c.DockerSpawner.remove = True
c.DockerSpawner.debug = True
# 资源限制
c.DockerSpawner.mem_limit = os.environ.get("MEM_LIMIT", "4G")
c.DockerSpawner.cpu_limit = float(os.environ.get("CPU_LIMIT", "2"))
c.DockerSpawner.mem_guarantee = os.environ.get("MEM_GUARANTEE", "1G")
c.DockerSpawner.cpu_guarantee = float(os.environ.get("CPU_GUARANTEE", "0.5"))
# 网络
network_name = os.environ.get("DOCKER_NETWORK_NAME", "jupyterhub-ai-net")
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.network_name = network_name
c.JupyterHub.hub_ip = "jupyterhub-ai"
c.JupyterHub.hub_port = 8080
# PostgreSQL 数据库配置
postgres_host = os.environ.get("POSTGRES_HOST", "postgres")
postgres_port = os.environ.get("POSTGRES_PORT", "5432")
postgres_db = os.environ.get("POSTGRES_DB", "jupyterhub")
postgres_user = os.environ.get("POSTGRES_USER", "jupyterhub")
postgres_password = os.environ.get("POSTGRES_PASSWORD", "jupyterhub_password")
# 构建 PostgreSQL 连接 URL
c.JupyterHub.db_url = f"postgresql://{postgres_user}:{postgres_password}@{postgres_host}:{postgres_port}/{postgres_db}"
# 数据库连接池配置
c.JupyterHub.db_kwargs = {
"pool_pre_ping": True,
"pool_recycle": 300,
"connect_args": {"connect_timeout": 10, "application_name": "jupyterhub"},
}
# GitHub OAuth 认证
c.JupyterHub.authenticator_class = "oauthenticator.GitHubOAuthenticator"
c.GitHubOAuthenticator.client_id = os.environ.get("GITHUB_CLIENT_ID")
c.GitHubOAuthenticator.client_secret = os.environ.get("GITHUB_CLIENT_SECRET")
c.GitHubOAuthenticator.oauth_callback_url = os.environ.get("OAUTH_CALLBACK_URL")
# 设置 JupyterHub 的公共 URL,确保 OAuth 回调正确工作
public_host = os.environ.get("JUPYTERHUB_PUBLIC_HOST", "localhost:8000")
if not public_host.startswith(("http://", "https://")):
public_host = f"http://{public_host}"
# JupyterHub 应该绑定到 0.0.0.0:8000 以便从容器外部访问
c.JupyterHub.bind_url = "http://0.0.0.0:8000"
c.JupyterHub.base_url = "/"
# 设置公共 URL 以确保 OAuth 回调正确工作
c.JupyterHub.public_url = public_host
# Cookie 安全设置
c.JupyterHub.cookie_max_age_days = 1
c.JupyterHub.cookie_secret_file = "/data/jupyterhub_cookie_secret"
# 从文件读取密钥(生产环境,添加错误处理)
try:
if os.path.exists("/run/secrets/github_client_id"):
with open("/run/secrets/github_client_id", "r") as f:
c.GitHubOAuthenticator.client_id = f.read().strip()
if os.path.exists("/run/secrets/github_client_secret"):
with open("/run/secrets/github_client_secret", "r") as f:
c.GitHubOAuthenticator.client_secret = f.read().strip()
except Exception as e:
print(f"Warning: Failed to read GitHub OAuth secrets: {e}")
# 如果读取密钥文件失败,确保从环境变量获取
if not c.GitHubOAuthenticator.client_id:
c.GitHubOAuthenticator.client_id = os.environ.get("GITHUB_CLIENT_ID")
if not c.GitHubOAuthenticator.client_secret:
c.GitHubOAuthenticator.client_secret = os.environ.get("GITHUB_CLIENT_SECRET")
# 管理员用户 (GitHub 用户名)
admin_users_str = os.environ.get("GITHUB_ADMIN_USERS", "")
if admin_users_str:
# 过滤空字符串并去除空白
admin_users = set(
user.strip() for user in admin_users_str.split(",") if user.strip()
)
c.Authenticator.admin_users = admin_users
print(f"Configured admin users: {admin_users}")
else:
c.Authenticator.admin_users = set()
print("Warning: No admin users configured")
# 允许的用户列表(留空则允许所有用户)
whitelist_users_str = os.environ.get("GITHUB_WHITELIST_USERS", "")
if whitelist_users_str:
# 过滤空字符串并去除空白
allowed_users = set(
user.strip() for user in whitelist_users_str.split(",") if user.strip()
)
c.Authenticator.allowed_users = allowed_users
print(f"Configured allowed users: {len(allowed_users)} users")
else:
# 如果没有配置白名单,允许所有通过 GitHub OAuth 认证的用户
c.Authenticator.allow_all = True
print("No user whitelist configured - all GitHub users can access")
# 安全设置
c.GitHubOAuthenticator.scope = ["read:user", "user:email"] # 最小权限原则
c.Authenticator.auto_login = False # 禁用自动登录以提高安全性
# 设置环境变量 - 合并基础环境变量和 AI 相关环境变量
c.DockerSpawner.environment = {
# 基础 Jupyter 环境变量
"JUPYTER_ENABLE_LAB": "yes",
"GRANT_SUDO": "no",
"CHOWN_HOME": "yes",
"CHOWN_HOME_OPTS": "-R",
"NB_UID": "1000",
"NB_GID": "100",
# AI 相关环境变量传递给用户容器
"OPENAI_API_KEY": os.environ.get("OPENAI_API_KEY", ""),
"OPENAI_API_BASE": os.environ.get("OPENAI_API_BASE", "https://api.openai.com/v1"),
"ANTHROPIC_API_KEY": os.environ.get("ANTHROPIC_API_KEY", ""),
"ALIYUN_API_KEY": os.environ.get("ALIYUN_API_KEY", ""),
"ALIYUN_API_BASE": os.environ.get(
"ALIYUN_API_BASE", "https://dashscope.aliyuncs.com/api/v1"
),
"DEEPSEEK_API_KEY": os.environ.get("DEEPSEEK_API_KEY", ""),
"DEEPSEEK_API_BASE": os.environ.get(
"DEEPSEEK_API_BASE", "https://api.deepseek.com/v1"
),
"OLLAMA_API_BASE": os.environ.get("OLLAMA_API_BASE", "http://172.18.0.1:11434"),
"OLLAMA_API_KEY": os.environ.get("OLLAMA_API_KEY", "ollama"),
"AI_PROXY_URL": os.environ.get("AI_PROXY_URL", "http://ip:8080"),
"USE_AI_PROXY": os.environ.get("USE_AI_PROXY", "true"),
}
# 服务健康检查 - 从环境变量获取
# 注意:health_check_interval 在新版本中已被移除,使用 proxy_check_interval 替代
c.JupyterHub.proxy_check_interval = int(os.environ.get("HEALTH_CHECK_INTERVAL", "30"))
c.JupyterHub.last_activity_interval = int(
os.environ.get("LAST_ACTIVITY_INTERVAL", "300")
)
c.JupyterHub.activity_resolution = int(os.environ.get("ACTIVITY_RESOLUTION", "300"))
# 超时配置 - 从环境变量获取
c.JupyterHub.shutdown_on_logout = (
os.environ.get("SHUTDOWN_ON_LOGOUT", "false").lower() == "true"
)
c.JupyterHub.init_spawners_timeout = int(os.environ.get("INIT_SPAWNERS_TIMEOUT", "60"))
c.Spawner.http_timeout = int(os.environ.get("SPAWNER_HTTP_TIMEOUT", "60"))
c.Spawner.start_timeout = int(os.environ.get("SPAWNER_START_TIMEOUT", "180"))
c.Spawner.idle_timeout = int(
os.environ.get("SPAWNER_IDLE_TIMEOUT", "7200")
) # 2 小时无活动自动关闭