Jupyterhub на Kubernetes Nginx — не создается после входа в систему

#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) между обоими экземплярами, я думаю, это все еще было бы возможно