Skip to content

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 小时无活动自动关闭