#jupyterhub
#jupyterhub
Вопрос:
Контекст: Используя Terraform, я создал кластер EKS на AWS. На этом кластере я установил Nginx Ingress с помощью Helm 3. TLS выполняется с использованием Let’s Encrypt with cert-manager. Впоследствии я могу добавлять веб-приложения, используя deployment, services и входные файлы yaml.
Проблема: Что-то, что у меня не работает, успешно развертывает JupyterHub. Установка и предоставление доступа работают нормально, JupyterHub использует протокол TCP, а cert-manager успешно создает сертификаты. Проблема возникает, когда пользователь успешно входит в jupyterhub, но invalid or expired cookie token
возникает, когда jupyterhub должен создать notebook.
Вопрос: Мне неясно, почему создание не работает и как это можно решить. Есть ли у кого-нибудь предложения, чтобы лучше понять проблему?
jupyterhub_config.py
Заключается в следующем:
c = get_config()
c.JupyterHub.authenticator_class = 'jupyterhub.auth.DummyAuthenticator'
c.Authenticator.allowed_users = {'dummy'}
c.Authenticator.admin_users = {'dummy'}
c.DummyAuthenticator.password = "fakenews"
c.JupyterHub.admin_access = True
deployment.yaml
Заключается в следующем:
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
generation: 1
labels:
run: jupyterhub
name: jupyterhub
namespace: jhub
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 2
selector:
matchLabels:
run: jupyterhub
template:
metadata:
creationTimestamp: ~
labels:
run: jupyterhub
spec:
containers:
- name: jupyterhub
image: "jupyterhub/jupyterhub:latest"
imagePullPolicy: IfNotPresent
ports:
-
containerPort: 8000
protocol: TCP
terminationMessagePolicy: File
volumeMounts:
-
mountPath: /srv/jupyterhub/jupyterhub_config.py
name: jupyterhub-config
subPath: jupyterhub_config.py
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
-
configMap:
name: jupyterhub-config
name: jupyterhub-config
ingress.yaml
Заключается в следующем:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-resource
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
tls:
- hosts:
- hub.example.com
secretName: hub-example-com-tls
rules:
- host: hub.example.com
http:
paths:
- path: /
backend:
serviceName: jupyterhub
servicePort: 8000
Используемые команды:
$ kubectl create configmap jupyterhub-config --from-file=./jupyterhub_config.py
$ kubectl create -f deployment.yaml
$ kubectl expose deployment jupyterhub
$ kubectl apply -f ingress.yaml
Это приводит к успешному безопасному развертыванию веб-службы на https://hub.example.com
. Но после входа в систему журнал контейнера jupyterhub выдает invalid or expired cookie token
при попытке создать экземпляр jupyter.
[I 2020-08-21 08:26:42.725 JupyterHub app:2307] Running JupyterHub version 1.2.0dev
[I 2020-08-21 08:26:42.726 JupyterHub app:2338] Using Authenticator: jupyterhub.auth.DummyAuthenticator-1.2.0dev
[I 2020-08-21 08:26:42.726 JupyterHub app:2338] Using Spawner: jupyterhub.spawner.LocalProcessSpawner-1.2.0dev
[I 2020-08-21 08:26:42.726 JupyterHub app:2338] Using Proxy: jupyterhub.proxy.ConfigurableHTTPProxy-1.2.0dev
[I 2020-08-21 08:26:42.735 JupyterHub app:1442] Writing cookie_secret to /srv/jupyterhub/jupyterhub_cookie_secret
[I 2020-08-21 08:26:42.752 alembic.runtime.migration migration:155] Context impl SQLiteImpl.
[I 2020-08-21 08:26:42.752 alembic.runtime.migration migration:162] Will assume non-transactional DDL.
[I 2020-08-21 08:26:42.758 alembic.runtime.migration migration:515] Running stamp_revision -> 4dc2d5a8c53c
[I 2020-08-21 08:26:42.809 JupyterHub proxy:461] Generating new CONFIGPROXY_AUTH_TOKEN
[I 2020-08-21 08:26:42.850 JupyterHub app:2377] Initialized 0 spawners in 0.002 seconds
[W 2020-08-21 08:26:42.853 JupyterHub proxy:643] Running JupyterHub without SSL. I hope there is SSL termination happening somewhere else...
[I 2020-08-21 08:26:42.853 JupyterHub proxy:646] Starting proxy @ http://:8000
08:26:43.359 [ConfigProxy] info: Proxying http://*:8000 to (no default)
08:26:43.362 [ConfigProxy] info: Proxy API at http://127.0.0.1:8001/api/routes
08:26:43.474 [ConfigProxy] info: 200 GET /api/routes
[I 2020-08-21 08:26:43.475 JupyterHub app:2622] Hub API listening on http://127.0.0.1:8081/hub/
08:26:43.476 [ConfigProxy] info: 200 GET /api/routes
[I 2020-08-21 08:26:43.476 JupyterHub proxy:320] Checking routes
[I 2020-08-21 08:26:43.476 JupyterHub proxy:400] Adding default route for Hub: / => http://127.0.0.1:8081
08:26:43.478 [ConfigProxy] info: Adding route / -> http://127.0.0.1:8081
08:26:43.478 [ConfigProxy] info: Route added / -> http://127.0.0.1:8081
08:26:43.478 [ConfigProxy] info: 201 POST /api/routes/
[I 2020-08-21 08:26:43.479 JupyterHub app:2697] JupyterHub is now running at http://:8000
[I 2020-08-21 08:26:56.023 JupyterHub log:181] 302 GET /hub/ -> /hub/login (@10.0.1.148) 1.16ms
[I 2020-08-21 08:27:01.409 JupyterHub base:742] User logged in: dummy
[I 2020-08-21 08:27:01.429 JupyterHub log:181] 302 POST /hub/login?next= -> /hub/spawn (dummy@10.0.1.148) 68.74ms
[I 2020-08-21 08:27:01.758 JupyterHub log:181] 200 GET /hub/login?next=/hub/spawn (@10.0.1.148) 219.05ms
08:31:43.482 [ConfigProxy] info: 200 GET /api/routes
[I 2020-08-21 08:31:43.482 JupyterHub proxy:320] Checking routes
[I 2020-08-21 12:06:43.482 JupyterHub proxy:320] Checking routes
[I 2020-08-21 12:07:08.386 JupyterHub log:181] 200 GET /hub/login?next=/hub/spawn (@10.0.2.117) 1.85ms
[I 2020-08-21 12:07:13.216 JupyterHub base:742] User logged in: dummy
[I 2020-08-21 12:07:13.217 JupyterHub log:181] 302 POST /hub/login?next=/hub/spawn -> /hub/spawn (dummy@10.0.2.117) 5.40ms
[I 2020-08-21 12:07:13.309 JupyterHub log:181] 200 GET /hub/login?next=/hub/spawn (@10.0.2.117) 1.22ms
[I 2020-08-21 13:27:28.324 JupyterHub log:181] 302 GET / -> /hub/ (@10.0.2.117) 0.90ms
[I 2020-08-21 13:27:28.410 JupyterHub log:181] 200 GET /hub/login (@10.0.2.117) 1.28ms
[W 2020-08-21 13:27:34.613 JupyterHub base:392] Invalid or expired cookie token
[I 2020-08-21 13:27:34.615 JupyterHub log:181] 302 GET /hub/spawn -> /hub/login?next=/hub/spawn (@10.0.2.117) 1.88ms
Комментарии:
1. 302 — это перенаправление, а не ошибка. Возникает ли у вас реальная ошибка в пользовательском интерфейсе при входе в систему?
2. После входа на страницу
https://hub.example.com/hub/login
он перенаправляется наhttps://hub.example.com/hub/login?next=/hub/spawn
страницу, где снова отображается экран входа в систему без каких-либо ошибок. Консоль не ссылается ни на какие проблемы, за исключением ошибки 302 в ответе сети.3. @ydatskcoR Это ссылается на недопустимый или просроченный токен cookie в журнале контейнера после многократных попыток входа в систему.
[I 2020-08-21 13:27:28.324 JupyterHub log:181] 302 GET / -> /hub/ (@10.0.2.117) 0.90ms [I 2020-08-21 13:27:28.410 JupyterHub log:181] 200 GET /hub/login (@10.0.2.117) 1.28ms [W 2020-08-21 13:27:34.613 JupyterHub base:392] Invalid or expired cookie token [I 2020-08-21 13:27:34.615 JupyterHub log:181] 302 GET /hub/spawn -> /hub/login?next=/hub/spawn (@10.0.2.117) 1.88ms
4. Работает ли это с 1 репликой? @aptroost
Ответ №1:
Как упоминалось ранее, масштабирование развертывания до 1 реплики решило проблему.
Я хотел бы уточнить, в чем, по-видимому, проблема.
Jupyterhub не масштабируется. Это приложение с отслеживанием состояния, и (на данный момент) невозможно сделать его высокодоступным.
Служба K8s балансирует нагрузку между двумя модулями / репликами, отправляя трафик случайным образом.
При входе в один jupyterhub вы получаете токен. Теперь с помощью этого токена вы отправляете другой запрос. Можете ли вы предположить, что произойдет, если этот запрос с токеном, который вы только что получили, будет отправлен второму экземпляру jupyterhub. Тот, кто понятия не имеет, что это за токен, потому что это не тот, который его сгенерировал.
invalid or expired cookie token
Это то, что вы бы увидели. Второй экземпляр счел бы этот токен недействительным.
Вот почему масштабирование до одной реплики решило проблему. Это потому, что весь трафик теперь отправляется в один модуль.
Комментарии:
1. Возможен ли другой метод проверки токена, такой как работа с секретным ключом, который идентичен в обеих репликах, по которым проверяется токен? Это сделало бы его масштабируемым.
2. Записные книжки Jupyter связаны с одним экземпляром, поэтому вам нужно будет подойти к нему по-другому. Вы можете частично решить эту проблему, используя привязку к сеансу , но это все равно не решает всех проблем, потому что даже тогда, если один модуль выйдет из строя, вы будете перенаправлены на второй модуль, который не знает о первом ноутбуке. Вот запрос функции в репозитории jupyterhub на github для поддержки высокой доступности, чтобы вы могли постоянно быть в курсе.
Ответ №2:
Изменение количества реплик с 2 на 1 исправило это. Спасибо! Очень жаль, что это не работает с репликами.
Комментарии:
1. Если бы вы могли найти способ разделить
active session
таблицу (не уверен, как подробно работают сеансы jupyter) между обоими экземплярами, я думаю, это все еще было бы возможно