mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-05 01:07:49 +02:00
✨(helm) deploy new infra using helm
The new infra we have must be configured in the helm chart. This commit all the missing templates to deploy yhub, it also automate the creation of the private keys needed by all services.
This commit is contained in:
@@ -5,6 +5,10 @@ __pycache__
|
||||
**/*.pyc
|
||||
venv
|
||||
.venv
|
||||
# the pattern above only matches at the root, and every image is built from
|
||||
# there: without this one, the backend virtualenv travels to the daemon on
|
||||
# every build
|
||||
**/.venv
|
||||
|
||||
# System-specific files
|
||||
.DS_Store
|
||||
@@ -34,4 +38,7 @@ db.sqlite3
|
||||
|
||||
# Frontend
|
||||
node_modules
|
||||
# same as .venv above: nested ones are not matched by the pattern above, and no
|
||||
# image copies them — every one of them runs its own install
|
||||
**/node_modules
|
||||
**/.next
|
||||
|
||||
@@ -60,11 +60,26 @@ jobs:
|
||||
should_push: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'preview') }}
|
||||
docker_user: 1001:127
|
||||
|
||||
build-and-push-yhub:
|
||||
uses: ./.github/workflows/docker-publish.yml
|
||||
permissions:
|
||||
contents: read
|
||||
secrets: inherit
|
||||
with:
|
||||
image_name: lasuite/impress-yhub
|
||||
context: .
|
||||
file: src/yhub-server/Dockerfile
|
||||
target: yhub
|
||||
should_push: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'preview') }}
|
||||
# no docker_user: the image defaults to uid 1000, the `node` user the
|
||||
# base image already declares in /etc/passwd
|
||||
|
||||
notify-argocd:
|
||||
needs:
|
||||
- build-and-push-backend
|
||||
- build-and-push-frontend
|
||||
- build-and-push-y-provider
|
||||
- build-and-push-yhub
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'preview')
|
||||
steps:
|
||||
|
||||
@@ -158,3 +158,50 @@ jobs:
|
||||
run: |
|
||||
docker system prune -af
|
||||
docker volume prune -f
|
||||
|
||||
build-and-push-yhub:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.repository.fork == true
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ github.repository }}/yhub
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7
|
||||
with:
|
||||
context: .
|
||||
file: ./src/yhub-server/Dockerfile
|
||||
target: yhub
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: DOCKER_USER=${{ env.DOCKER_USER }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
- name: Cleanup Docker after build
|
||||
if: always()
|
||||
run: |
|
||||
docker system prune -af
|
||||
docker volume prune -f
|
||||
|
||||
+40
-4
@@ -143,6 +143,24 @@ and this project adheres to
|
||||
on its own
|
||||
- 🔧(dev) generate the JWT signing key of the collaboration server when
|
||||
bootstrapping the dev stack, alongside the backend one
|
||||
- ✨(helm) generate the JWT signing keys of the services on the cluster
|
||||
(`jwtKeys.enabled`, off by default): a job generates the backend and the
|
||||
collaboration server keys with `openssl`, hands them to a secret both mount
|
||||
read-only, and sets the `*_FILE` variables pointing at them. No key is
|
||||
templated into a manifest or kept in a values file, and the job is the only
|
||||
thing granted a write: its role may create a secret and read whether that one
|
||||
exists, nothing else, and the services never call the kubernetes API.
|
||||
Idempotent — an existing secret is left alone, so it re-runs on every sync,
|
||||
and rolling the keys is deleting the secret and letting the next run create
|
||||
it again. `jwtKeys.existingSecret` points at keys of your own instead, and
|
||||
skips both the job and its rights
|
||||
- ✨(helm) deploy the collaboration server: the chart gains a `yhub` deployment,
|
||||
its service, and the job running the `init-db` script that creates and
|
||||
upgrades its schema — next to the backend migrate job, retrying while the
|
||||
postgres server does not answer, since nothing in the chart creates it.
|
||||
Configured under the `yhub` values key, where `REDIS` and `POSTGRES` are
|
||||
required and have no default; the image is published as
|
||||
`lasuite/impress-yhub`
|
||||
- ✨(backend) serve `documents/{id}/formatted-content/` from yhub
|
||||
- ✨(backend) duplicate a document through the collaboration server
|
||||
- ✨(backend) call YHubService to seed initial document content
|
||||
@@ -204,13 +222,31 @@ and this project adheres to
|
||||
- 💥(backend) remove the `documents/{id}/content/` endpoint
|
||||
- 💥(backend) remove the `documents/{id}/can-edit/` endpoint
|
||||
- 💥(y-provider) the published `lasuite/impress-y-provider` image becomes
|
||||
converter-only and no longer serves `/collaboration/ws/`; deployments using
|
||||
the existing helm values lose collaboration until the helm chart routes
|
||||
collaboration to yhub (follow-up)
|
||||
converter-only and no longer serves `/collaboration/ws/`
|
||||
- 💥(helm) route `/collaboration/` to yhub instead of the y-provider: both
|
||||
collaboration ingresses now point at the yhub service, and
|
||||
`ingressCollaborationApi` serves the routes yhub exposes to browsers
|
||||
(`ingressCollaborationApi.paths`, one ingress rule each) instead of the
|
||||
single `/collaboration/api/` path — what is not listed stays in-cluster, so
|
||||
`create-ydoc`, `reset-connections`, `migrate`, `restore-ydoc` and
|
||||
`reset-ydoc` are not published. The `upstream-hash-by: $arg_room` annotation
|
||||
is dropped: yhub replicas exchange updates through redis, so a room needs no
|
||||
sticky upstream — and hashing on a query argument its urls do not carry would
|
||||
pin every connection to a single pod
|
||||
- 💥(helm) drop the `yProvider.converter` values, its deployment and its
|
||||
service: the y-provider serves nothing but the conversion API since the
|
||||
collaboration moved to yhub, so the `yProvider` release *is* the converter
|
||||
and there is no second one to enable. Deployments that had it on lose the
|
||||
`-converter` suffix on the url the backend calls —
|
||||
`Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/` — and
|
||||
`yProvider.converter.*` values are now ignored, their `yProvider.*`
|
||||
counterparts taking over
|
||||
- 🔧(collaboration) split the yhub image into a development and a production
|
||||
stage, like the other services: the dev stack now bind-mounts
|
||||
`src/yhub-server` and runs the server through nodemon, so editing a source
|
||||
file restarts it instead of needing `make build-yhub`
|
||||
file restarts it instead of needing `make build-yhub`. The production stage
|
||||
gains the un-privileged user and the entrypoint the other images have, and
|
||||
both are now built from the repository root like the rest of them
|
||||
|
||||
## [v5.4.1] - 2026-07-09
|
||||
|
||||
|
||||
@@ -42,8 +42,21 @@ docker_build(
|
||||
]
|
||||
)
|
||||
|
||||
docker_build(
|
||||
'localhost:5001/impress-yhub:latest',
|
||||
context='..',
|
||||
dockerfile='../src/yhub-server/Dockerfile',
|
||||
only=['./src/yhub-server', './docker', './.dockerignore'],
|
||||
target = 'yhub',
|
||||
build_args={'DOCKER_USER': '1000:1000'},
|
||||
live_update=[
|
||||
sync('../src/yhub-server', '/app'),
|
||||
]
|
||||
)
|
||||
|
||||
k8s_resource('impress-docs-backend-migrate', resource_deps=['dev-backend-postgres'])
|
||||
k8s_resource('impress-docs-backend-createsuperuser', resource_deps=['impress-docs-backend-migrate'])
|
||||
k8s_resource('impress-docs-yhub-init-db', resource_deps=['dev-backend-postgres'])
|
||||
k8s_resource('dev-backend-keycloak', resource_deps=['dev-backend-keycloak-pg'])
|
||||
k8s_resource('impress-docs-backend', resource_deps=['impress-docs-backend-migrate', 'dev-backend-redis', 'dev-backend-keycloak', 'dev-backend-postgres', 'dev-backend-minio:statefulset'])
|
||||
k8s_yaml(local('cd ../src/helm && helmfile -n impress -e dev template .'))
|
||||
|
||||
+7
-8
@@ -235,8 +235,8 @@ services:
|
||||
yhub:
|
||||
user: ${DOCKER_USER:-1000}
|
||||
build:
|
||||
context: ./src/yhub-server
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: ./src/yhub-server/Dockerfile
|
||||
target: yhub-development
|
||||
image: impress:yhub-development
|
||||
environment:
|
||||
@@ -255,6 +255,11 @@ services:
|
||||
- env.d/development/common.local
|
||||
volumes:
|
||||
- ./data/jwt:/data/jwt:ro
|
||||
# editing a source file restarts the server (nodemon), no rebuild
|
||||
- ./src/yhub-server:/app
|
||||
# node_modules is installed in the image, not in the source tree: keep
|
||||
# the bind mount above from hiding it
|
||||
- /app/node_modules
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3002:3002"
|
||||
@@ -267,12 +272,6 @@ services:
|
||||
# starting before minio would cache 401s for the first accessed docs
|
||||
minio:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
# editing a source file restarts the server (nodemon), no rebuild
|
||||
- ./src/yhub-server:/app
|
||||
# node_modules is installed in the image, not in the source tree: keep
|
||||
# the bind mount above from hiding it
|
||||
- /app/node_modules
|
||||
|
||||
kc_postgresql:
|
||||
image: postgres:14.3
|
||||
|
||||
@@ -1,12 +1,65 @@
|
||||
# Collaboration
|
||||
|
||||
By default with Docs, collaboration is enabled. To allow the collaboration between users, a connection to a websocket server is made (the y-provider service), you only have to configure the Django backend URL and the allowed origin in your y-provider service:
|
||||
By default with Docs, collaboration is enabled. To allow the collaboration between users, a connection to a websocket server is made (the yhub service), you only have to configure the Django backend URL and the allowed origin in your yhub service:
|
||||
|
||||
```yaml
|
||||
COLLABORATION_BACKEND_BASE_URL: https://{yourdocsdomain.tld}
|
||||
COLLABORATION_SERVER_ORIGIN: https://{yourdocsdomain.tld}
|
||||
```
|
||||
|
||||
The collaboration server keeps the live state of a document in Redis and persists it to a PostgreSQL database of its own, so it needs both:
|
||||
|
||||
```yaml
|
||||
REDIS: redis://{redis-host}:6379/0
|
||||
POSTGRES: postgres://{user}:{password}@{postgres-host}:5432/yhub
|
||||
```
|
||||
|
||||
Nothing creates that schema at startup: the server never runs DDL. Run the script yhub ships (`npm run init-db`, which the helm chart runs as a job) once before starting it, and again after every upgrade that adds a table. It creates the database when it is missing, it is idempotent, and until it has run every document read fails with `relation "..." does not exist`.
|
||||
|
||||
The Django backend reads and writes document content there too, so point it at the service:
|
||||
|
||||
```yaml
|
||||
YHUB_API_BASE_URL: http://{yhub-service}:443
|
||||
```
|
||||
|
||||
Prefer the internal service url: the routes the backend calls are not meant to be reachable from the outside. Route `/collaboration/ws/` to the service publicly — that is the one the browsers open — plus the document routes (`/collaboration/ydoc/`, `rollback`, `prune`, `changeset`, `activity`) and `/collaboration/jwks/`, which carries public keys and nothing else. Keep `reset-connections`, `migrate`, `restore-ydoc`, `reset-ydoc` and `create-ydoc` in-cluster.
|
||||
|
||||
Both directions are authenticated with short-lived RS256 JWTs rather than a shared secret, and each side verifies the other against the JWKS it publishes — so both need a signing key of their own, and neither needs a copy of the other's:
|
||||
|
||||
```yaml
|
||||
# Django
|
||||
JWT_PRIVATE_KEY_FILE: /path/to/backend-private.pem
|
||||
# yhub
|
||||
YHUB_JWT_PRIVATE_KEY_FILE: /path/to/yhub-private.pem
|
||||
```
|
||||
|
||||
They are ordinary PKCS#8 RSA keys (`openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048`), and rolling one needs no change on the other side. Without them the documents still open and edit, but the backend cannot create, delete or restore a document's content, and yhub cannot tell it that a document changed — its `updated_at` stops following the edits.
|
||||
|
||||
### Generating them on the cluster
|
||||
|
||||
The helm chart generates both for you, so that no key has to be created by hand, put in a values file or in a secret:
|
||||
|
||||
```yaml
|
||||
jwtKeys:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
A job then creates the two keys, once, in a secret every service mounts read-only, and points the backend and yhub at them. It generates them with `openssl` in a pod-local volume and hands them to `kubectl create secret`, so they never touch a disk, a manifest or a values file. The secret is left alone when it is already there, so the job is safe to re-run — it runs on every sync — and rolling the keys is deleting the secret and letting the next run create it again. Both sides follow: they pick the verification key by its `kid` and fetch the set again when they meet one they do not know.
|
||||
|
||||
The job is the only thing allowed near that secret: the chart gives it a service account whose role can `create` a secret and read whether that one exists, nothing more. The services never call the kubernetes API — they read a mounted file. The secret is not part of the release either, so uninstalling keeps the same identities; delete the secret to start over.
|
||||
|
||||
Deployments already holding their keys in a secret of their own point the chart at it instead, and the job and its rights are not created at all:
|
||||
|
||||
```yaml
|
||||
jwtKeys:
|
||||
enabled: true
|
||||
existingSecret: my-jwt-keys # holding private.pem and yhub-private.pem
|
||||
```
|
||||
|
||||
Setting `JWT_PRIVATE_KEY_FILE` or `YHUB_JWT_PRIVATE_KEY_FILE` yourself keeps priority over what the job provides, so a deployment holding its keys in a secret of its own can leave `jwtKeys` disabled and mount them where it wants.
|
||||
|
||||
Several replicas can serve the same document: they exchange updates through Redis, so no sticky routing is needed on the websocket ingress.
|
||||
|
||||
## What happens when connection to the websocket is not allowed?
|
||||
|
||||
When multiple users access a Docs and the connection to the websocket is not allowed, then they will be in a situation where they can lose data.
|
||||
|
||||
@@ -67,7 +67,9 @@ backend:
|
||||
AWS_STORAGE_BUCKET_NAME: docs-media-storage
|
||||
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||
USER_RECONCILIATION_FORM_URL: https://docs.127.0.0.1.nip.io
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
|
||||
# the collaboration server, reached in-cluster
|
||||
YHUB_API_BASE_URL: http://impress-docs-yhub:443
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
|
||||
Y_PROVIDER_API_KEY: my-secret
|
||||
CACHES_KEY_PREFIX: "{{ now | unixEpoch }}"
|
||||
migrate:
|
||||
@@ -135,6 +137,26 @@ yProvider:
|
||||
COLLABORATION_LOGGING: true
|
||||
COLLABORATION_SERVER_ORIGIN: https://docs.127.0.0.1.nip.io
|
||||
|
||||
# The collaboration server: it serves everything under /collaboration/, the
|
||||
# websocket included. It keeps the live state of a document in redis and
|
||||
# persists it to a PostgreSQL database of its own, created by the init-db job
|
||||
# the chart ships — give the user in POSTGRES the right to create it, or create
|
||||
# the database yourself beforehand.
|
||||
yhub:
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
repository: lasuite/impress-yhub
|
||||
pullPolicy: Always
|
||||
tag: "latest"
|
||||
|
||||
envVars:
|
||||
POSTGRES: postgres://dinum:pass@postgresql-dev-backend-postgres:5432/yhub
|
||||
REDIS: redis://user:pass@redis-dev-backend-redis:6379/2
|
||||
REDIS_PREFIX: yhub
|
||||
COLLABORATION_BACKEND_BASE_URL: https://docs.127.0.0.1.nip.io
|
||||
COLLABORATION_SERVER_ORIGIN: https://docs.127.0.0.1.nip.io
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
host: docs.127.0.0.1.nip.io
|
||||
|
||||
@@ -26,33 +26,17 @@ COLLABORATION_BACKEND_BASE_URL: http://{django-service}:8000
|
||||
|
||||
The JWKS url defaults to `{COLLABORATION_BACKEND_BASE_URL}/api/v1.0/jwks`; override it with `JWKS_URL` if Django is not reachable at that base url from the y-provider service.
|
||||
|
||||
### Splitting conversion service
|
||||
### One service, not two anymore
|
||||
|
||||
The conversion service is present in the `y-provider` server. The same server used to manage websockets. You can split in one side the websocket server and in an other side the converter service.
|
||||
This feature is only available in our helm chart, if you are deploying an other way you can take example of what is made to implement it.
|
||||
The idea is to deploy twice the `y-provider` server, one dedicated for websockets and one dedicated to the conversion.
|
||||
The `y-provider` server used to serve the websockets as well, which is why it could be deployed twice — one release for the collaboration, one for the conversion (`yProvider.converter`). The collaboration is served by [yhub](collaboration.md) now, so the conversion is all that is left: the `y-provider` service **is** the converter, and the `yProvider.converter` values are gone.
|
||||
|
||||
In the helm chart, you can use this value that will do the job for you:
|
||||
|
||||
```yaml
|
||||
yProvider:
|
||||
converter:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Every parameter in the `yProvider` key can be overridden in the `yProvider.converter` key.
|
||||
|
||||
Once enabled, you have to enable the `Y_PROVIDER_API_BASE_URL` with the url of the newly created service, it is the same as before with `-converter` at the end.
|
||||
If before it was
|
||||
|
||||
```yaml
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
|
||||
```
|
||||
|
||||
now it is
|
||||
A deployment coming from a chart older than this one has one thing to change, the url the backend calls, which loses its suffix:
|
||||
|
||||
```yaml
|
||||
# before
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider-converter:443/api/
|
||||
# now
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
|
||||
```
|
||||
|
||||
## Docspec configuration
|
||||
|
||||
@@ -226,6 +226,7 @@ impress-docs-backend-8494fb797d-8k8wt 1/1 Running 0 6m45s
|
||||
impress-docs-celery-worker-764b5dd98f-9qd6v 1/1 Running 0 6m45s
|
||||
impress-docs-frontend-5b69b65cc4-s8pps 1/1 Running 0 6m45s
|
||||
impress-docs-y-provider-5fc7ccd8cc-6ttrf 1/1 Running 0 6m45s
|
||||
impress-docs-yhub-6d84f9b7c5-2xqzp 1/1 Running 0 6m45s
|
||||
keycloak-dev-backend-keycloak-0 1/1 Running 0 24m
|
||||
keycloak-dev-backend-keycloak-pg-0 1/1 Running 0 24m
|
||||
minio-dev-backend-minio-0 1/1 Running 0 8m24s
|
||||
|
||||
@@ -71,7 +71,10 @@ backend:
|
||||
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||
DOCSPEC_API_URL: http://impress-docs-docspec:4000/conversion
|
||||
USER_RECONCILIATION_FORM_URL: https://docs.127.0.0.1.nip.io
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider-converter:443/api/
|
||||
# the collaboration server, reached in-cluster: the backend reads and
|
||||
# writes document content there, and fetches its JWKS from the same host
|
||||
YHUB_API_BASE_URL: http://impress-docs-yhub:443
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
|
||||
Y_PROVIDER_API_KEY: my-secret
|
||||
CACHES_KEY_PREFIX: "{{ now | unixEpoch }}"
|
||||
django:
|
||||
@@ -159,11 +162,6 @@ frontend:
|
||||
runAsNonRoot: false
|
||||
|
||||
yProvider:
|
||||
|
||||
converter:
|
||||
enabled: true
|
||||
replicas: 2
|
||||
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
@@ -192,6 +190,47 @@ yProvider:
|
||||
- key: cacert.pem
|
||||
path: cacert.pem
|
||||
|
||||
# The keys the backend and the collaboration server sign the calls they make to
|
||||
# each other with, generated on the cluster by a job into a secret both mount
|
||||
# read-only.
|
||||
jwtKeys:
|
||||
enabled: true
|
||||
|
||||
yhub:
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
repository: localhost:5001/impress-yhub
|
||||
pullPolicy: Always
|
||||
tag: "latest"
|
||||
|
||||
envVars:
|
||||
# its own logical database on the dev-backend postgres: the init-db job
|
||||
# creates it, the backend never touches it
|
||||
POSTGRES: postgres://dinum:pass@dev-backend-postgres:5432/yhub
|
||||
# a redis database of its own too — the backend cache and celery live in /1
|
||||
REDIS: redis://user:pass@dev-backend-redis:6379/2
|
||||
REDIS_PREFIX: yhub
|
||||
COLLABORATION_BACKEND_BASE_URL: https://docs.127.0.0.1.nip.io
|
||||
COLLABORATION_SERVER_ORIGIN: https://docs.127.0.0.1.nip.io
|
||||
NODE_EXTRA_CA_CERTS: /cert/cacert.pem
|
||||
# YHUB_JWT_PRIVATE_KEY_FILE comes from the jwtKeys job below
|
||||
|
||||
# Extra volume mounts to manage our local custom CA and avoid to set ssl_verify: false
|
||||
extraVolumeMounts:
|
||||
- name: certs
|
||||
mountPath: /cert/cacert.pem
|
||||
subPath: cacert.pem
|
||||
|
||||
# Extra volumes to manage our local custom CA and avoid to set ssl_verify: false
|
||||
extraVolumes:
|
||||
- name: certs
|
||||
configMap:
|
||||
name: certifi
|
||||
items:
|
||||
- key: cacert.pem
|
||||
path: cacert.pem
|
||||
|
||||
docSpec:
|
||||
enabled: true
|
||||
replicas: 1
|
||||
@@ -218,7 +257,7 @@ ingressCollaborationWS:
|
||||
host: docs.127.0.0.1.nip.io
|
||||
|
||||
ingressCollaborationApi:
|
||||
enabled: true
|
||||
enabled: false
|
||||
host: docs.127.0.0.1.nip.io
|
||||
|
||||
ingressAdmin:
|
||||
|
||||
@@ -71,7 +71,10 @@ backend:
|
||||
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||
DOCSPEC_API_URL: http://impress-docs-docspec:4000/conversion
|
||||
USER_RECONCILIATION_FORM_URL: https://{{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider-converter:443/api/
|
||||
# the collaboration server, reached in-cluster: the backend reads and
|
||||
# writes document content there, and fetches its JWKS from the same host
|
||||
YHUB_API_BASE_URL: http://impress-docs-yhub:443
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-docs-y-provider:443/api/
|
||||
Y_PROVIDER_API_KEY: my-secret
|
||||
CACHES_KEY_PREFIX: "{{ now | unixEpoch }}"
|
||||
migrate:
|
||||
@@ -137,11 +140,6 @@ frontend:
|
||||
tag: *tag
|
||||
|
||||
yProvider:
|
||||
|
||||
converter:
|
||||
enabled: true
|
||||
replicas: 1
|
||||
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
@@ -155,6 +153,30 @@ yProvider:
|
||||
COLLABORATION_SERVER_ORIGIN: https://{{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
NODE_OPTIONS: "--max-old-space-size=1024"
|
||||
|
||||
# The keys the backend and the collaboration server sign the calls they make to
|
||||
# each other with, generated on the cluster by a job into a secret both mount
|
||||
# read-only.
|
||||
jwtKeys:
|
||||
enabled: true
|
||||
|
||||
yhub:
|
||||
replicas: 1
|
||||
|
||||
image:
|
||||
repository: lasuite/impress-yhub
|
||||
pullPolicy: Always
|
||||
tag: *tag
|
||||
|
||||
envVars:
|
||||
# its own logical database on the dev-backend postgres, created by the
|
||||
# init-db job; redis /2, the backend cache and celery live in /1
|
||||
POSTGRES: postgres://dinum:pass@dev-backend-postgres:5432/yhub
|
||||
REDIS: redis://user:pass@dev-backend-redis:6379/2
|
||||
REDIS_PREFIX: yhub
|
||||
COLLABORATION_BACKEND_BASE_URL: https://{{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
COLLABORATION_SERVER_ORIGIN: https://{{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
NODE_OPTIONS: "--max-old-space-size=1024"
|
||||
|
||||
docSpec:
|
||||
enabled: true
|
||||
replicas: 1
|
||||
@@ -182,7 +204,7 @@ ingressCollaborationWS:
|
||||
host: {{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
|
||||
ingressCollaborationApi:
|
||||
enabled: true
|
||||
enabled: false
|
||||
host: {{ .Values.feature }}-docs.{{ .Values.domain }}
|
||||
|
||||
ingressAdmin:
|
||||
|
||||
+111
-3
@@ -38,7 +38,6 @@
|
||||
| `ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/enable-websocket` | | `true` |
|
||||
| `ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-read-timeout` | | `86400` |
|
||||
| `ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-send-timeout` | | `86400` |
|
||||
| `ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/upstream-hash-by` | | `$arg_room` |
|
||||
| `ingressRedirects.enabled` | whether to enable the Ingress Redirects or not | `false` |
|
||||
| `ingressRedirects.className` | IngressClass to use for the Ingress Redirects | `nil` |
|
||||
| `ingressRedirects.host` | Host for the Ingress Redirects | `impress.example.com` |
|
||||
@@ -51,13 +50,13 @@
|
||||
| `ingressCollaborationApi.className` | IngressClass to use for the Ingress | `nil` |
|
||||
| `ingressCollaborationApi.host` | Host for the Ingress | `impress.example.com` |
|
||||
| `ingressCollaborationApi.path` | Path to use for the Ingress | `/collaboration/api/` |
|
||||
| `ingressCollaborationApi.paths` | Paths to route to the collaboration server, one rule each | `["/collaboration/ydoc/","/collaboration/jwks/"]` |
|
||||
| `ingressCollaborationApi.hosts` | Additional host to configure for the Ingress | `[]` |
|
||||
| `ingressCollaborationApi.tls.enabled` | Whether to enable TLS for the Ingress | `true` |
|
||||
| `ingressCollaborationApi.tls.secretName` | Secret name for TLS config | `nil` |
|
||||
| `ingressCollaborationApi.tls.additional[].secretName` | Secret name for additional TLS config | |
|
||||
| `ingressCollaborationApi.tls.additional[].hosts[]` | Hosts for additional TLS config | |
|
||||
| `ingressCollaborationApi.customBackends` | Add custom backends to ingress | `[]` |
|
||||
| `ingressCollaborationApi.annotations.nginx.ingress.kubernetes.io/upstream-hash-by` | | `$arg_room` |
|
||||
| `ingressAdmin.enabled` | whether to enable the Ingress or not | `false` |
|
||||
| `ingressAdmin.className` | IngressClass to use for the Ingress | `nil` |
|
||||
| `ingressAdmin.host` | Host for the Ingress | `impress.example.com` |
|
||||
@@ -301,13 +300,122 @@
|
||||
| `yProvider.pdb.enabled` | Enable pdb on yProvider | `true` |
|
||||
| `yProvider.serviceAccountName` | Optional service account name to use for yProvider pods | `nil` |
|
||||
|
||||
### JWT signing keys
|
||||
|
||||
| Name | Description | Value |
|
||||
| ------------------------------------------------------ | ------------------------------------------------------------------------------------ | -------------------- |
|
||||
| `jwtKeys.enabled` | Generate the JWT signing keys of the services on the cluster | `false` |
|
||||
| `jwtKeys.existingSecret` | Secret already holding the keys, generated in a secret of the chart's own when empty | `nil` |
|
||||
| `jwtKeys.mountPath` | Path the keys are mounted at, in every service reading them | `/data/jwt` |
|
||||
| `jwtKeys.backendKeyFilename` | Name of the key signing the tokens the backend issues | `private.pem` |
|
||||
| `jwtKeys.yhubKeyFilename` | Name of the key signing the calls the collaboration server makes to the backend | `yhub-private.pem` |
|
||||
| `jwtKeys.keySize` | Size, in bits, of the generated RSA keys | `2048` |
|
||||
| `jwtKeys.rbac.create` | Create the service account and the role the job needs to create the secret | `true` |
|
||||
| `jwtKeys.image.repository` | Repository to use to pull the image generating the keys | `alpine/openssl` |
|
||||
| `jwtKeys.image.tag` | Tag of the image generating the keys | `3.5.7` |
|
||||
| `jwtKeys.image.pullPolicy` | Pull policy of the image generating the keys | `IfNotPresent` |
|
||||
| `jwtKeys.kubectlImage.repository` | Repository to use to pull the image handing the keys to the secret | `dtzar/helm-kubectl` |
|
||||
| `jwtKeys.kubectlImage.tag` | Tag of the image handing the keys to the secret | `3.16.2` |
|
||||
| `jwtKeys.kubectlImage.pullPolicy` | Pull policy of the image handing the keys to the secret | `IfNotPresent` |
|
||||
| `jwtKeys.job.podSecurityContext` | Pod security context of the generating job | `{}` |
|
||||
| `jwtKeys.job.securityContext.allowPrivilegeEscalation` | Whether to allow privilege escalation for the job containers | `false` |
|
||||
| `jwtKeys.job.securityContext.capabilities.drop` | List of capabilities to drop for the job containers | `["ALL"]` |
|
||||
| `jwtKeys.job.securityContext.runAsNonRoot` | Whether to run the job containers as a non-root user | `true` |
|
||||
| `jwtKeys.job.securityContext.runAsUser` | User the job containers run as, their images declaring none | `1000` |
|
||||
| `jwtKeys.job.securityContext.runAsGroup` | Group the job containers run as | `1000` |
|
||||
| `jwtKeys.job.securityContext.seccompProfile.type` | Seccomp profile type for the job containers | `RuntimeDefault` |
|
||||
| `jwtKeys.job.restartPolicy` | Restart policy of the generating job | `Never` |
|
||||
| `jwtKeys.job.backoffLimit` | Numbers of generating job retries | `2` |
|
||||
| `jwtKeys.job.ttlSecondsAfterFinished` | Period to wait before removing the generating job | `30` |
|
||||
| `jwtKeys.job.generateCommand` | Override the command generating the keys | `[]` |
|
||||
| `jwtKeys.job.publishCommand` | Override the command creating the secret from the generated keys | `[]` |
|
||||
| `jwtKeys.job.annotations` | Annotations to add to the generating job | `{}` |
|
||||
| `jwtKeys.job.podAnnotations` | Annotations to add to the generating job Pod | `{}` |
|
||||
| `jwtKeys.job.resources` | Resource requirements for the job containers | `{}` |
|
||||
| `jwtKeys.job.nodeSelector` | Node selector for the generating job Pod | `{}` |
|
||||
| `jwtKeys.job.tolerations` | Tolerations for the generating job Pod | `[]` |
|
||||
| `jwtKeys.job.affinity` | Affinity for the generating job Pod | `{}` |
|
||||
| `jwtKeys.job.serviceAccountName` | Service account of the generating job Pod, the one created above when empty | `nil` |
|
||||
|
||||
### yhub
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| `yhub.enabled` | Enable the yhub collaboration server, its service and its init-db job | `true` |
|
||||
| `yhub.image.repository` | Repository to use to pull the yhub container image | `lasuite/impress-yhub` |
|
||||
| `yhub.image.tag` | yhub container tag | `latest` |
|
||||
| `yhub.image.pullPolicy` | yhub container image pull policy | `IfNotPresent` |
|
||||
| `yhub.command` | Override the yhub container command | `[]` |
|
||||
| `yhub.args` | Override the yhub container args | `[]` |
|
||||
| `yhub.replicas` | Amount of yhub replicas | `3` |
|
||||
| `yhub.shareProcessNamespace` | Enable share process namespace between containers | `false` |
|
||||
| `yhub.sidecars` | Add sidecars containers to yhub deployment | `[]` |
|
||||
| `yhub.terminationGracePeriodSeconds` | Grace period given to a yhub pod to drain before it is killed | `60` |
|
||||
| `yhub.securityContext.allowPrivilegeEscalation` | Whether to allow privilege escalation for the yhub container | `false` |
|
||||
| `yhub.securityContext.capabilities.drop` | List of capabilities to drop for the yhub container | `["ALL"]` |
|
||||
| `yhub.securityContext.runAsNonRoot` | Whether to run the yhub container as a non-root user | `true` |
|
||||
| `yhub.securityContext.runAsUser` | User the yhub container runs as | `1000` |
|
||||
| `yhub.securityContext.runAsGroup` | Group the yhub container runs as | `1000` |
|
||||
| `yhub.securityContext.seccompProfile.type` | Seccomp profile type for the yhub container | `RuntimeDefault` |
|
||||
| `yhub.envVars` | Configure yhub container environment variables | `undefined` |
|
||||
| `yhub.envVars.REDIS` | Required, redis/valkey url holding the live document state (e.g. redis://valkey:6379/0) | |
|
||||
| `yhub.envVars.POSTGRES` | Required, url of the yhub database, created by the init-db job (e.g. postgres://user:pass@postgres:5432/yhub) | |
|
||||
| `yhub.envVars.REDIS_PREFIX` | Namespace of the redis keys, when the instance is shared (default: yhub) | |
|
||||
| `yhub.envVars.COLLABORATION_BACKEND_BASE_URL` | Base url of the Docs backend, which yhub asks about users and document access rights | |
|
||||
| `yhub.envVars.COLLABORATION_SERVER_ORIGIN` | Comma separated list of the origins allowed to open a websocket | |
|
||||
| `yhub.envVars.YHUB_JWT_PRIVATE_KEY_FILE` | Path to the RSA private key (PEM) yhub signs its calls to the backend with, mounted from a secret | |
|
||||
| `yhub.envVars.SOFT_MIGRATION` | Set to "true" to seed rooms from the legacy Django/S3 document store on first access | |
|
||||
| `yhub.envVars.BY_VALUE` | Example environment variable by setting value directly | |
|
||||
| `yhub.envVars.FROM_CONFIGMAP.configMapKeyRef.name` | Name of a ConfigMap when configuring env vars from a ConfigMap | |
|
||||
| `yhub.envVars.FROM_CONFIGMAP.configMapKeyRef.key` | Key within a ConfigMap when configuring env vars from a ConfigMap | |
|
||||
| `yhub.envVars.FROM_SECRET.secretKeyRef.name` | Name of a Secret when configuring env vars from a Secret | |
|
||||
| `yhub.envVars.FROM_SECRET.secretKeyRef.key` | Key within a Secret when configuring env vars from a Secret | |
|
||||
| `yhub.podAnnotations` | Annotations to add to the yhub Pod | `{}` |
|
||||
| `yhub.dpAnnotations` | Annotations to add to the yhub Deployment | `{}` |
|
||||
| `yhub.initDbJobAnnotations` | Annotations for the yhub init-db job | `{}` |
|
||||
| `yhub.jobs.ttlSecondsAfterFinished` | Period to wait before removing the init-db job | `30` |
|
||||
| `yhub.jobs.backoffLimit` | Numbers of init-db job retries | `2` |
|
||||
| `yhub.initDb.enabled` | Run the job creating and upgrading the yhub schema | `true` |
|
||||
| `yhub.initDb.command` | Override the command creating and upgrading the yhub schema | `[]` |
|
||||
| `yhub.initDb.retries` | How many times the schema script is retried while the postgres server does not answer | `60` |
|
||||
| `yhub.initDb.retryDelaySeconds` | Seconds between two attempts | `5` |
|
||||
| `yhub.initDb.restartPolicy` | Restart policy of the init-db job | `Never` |
|
||||
| `yhub.service.type` | yhub Service type | `ClusterIP` |
|
||||
| `yhub.service.port` | yhub Service listening port | `443` |
|
||||
| `yhub.service.targetPort` | yhub container listening port | `3002` |
|
||||
| `yhub.service.annotations` | Annotations to add to the yhub Service | `{}` |
|
||||
| `yhub.probes.liveness.path` | Configure path for yhub HTTP liveness probe | `/collaboration/jwks/v1` |
|
||||
| `yhub.probes.liveness.initialDelaySeconds` | Configure initial delay for yhub liveness probe | `10` |
|
||||
| `yhub.probes.readiness.path` | Configure path for yhub HTTP readiness probe | `/collaboration/jwks/v1` |
|
||||
| `yhub.probes.readiness.initialDelaySeconds` | Configure initial delay for yhub readiness probe | `5` |
|
||||
| `yhub.probes.liveness.targetPort` | Configure port for yhub HTTP liveness probe | |
|
||||
| `yhub.probes.liveness.timeoutSeconds` | Configure timeout for yhub liveness probe | |
|
||||
| `yhub.probes.readiness.targetPort` | Configure port for yhub HTTP readiness probe | |
|
||||
| `yhub.probes.readiness.timeoutSeconds` | Configure timeout for yhub readiness probe | |
|
||||
| `yhub.probes.startup.path` | Configure path for yhub HTTP startup probe | |
|
||||
| `yhub.probes.startup.targetPort` | Configure port for yhub HTTP startup probe | |
|
||||
| `yhub.probes.startup.initialDelaySeconds` | Configure initial delay for yhub startup probe | |
|
||||
| `yhub.probes.startup.timeoutSeconds` | Configure timeout for yhub startup probe | |
|
||||
| `yhub.resources` | Resource requirements for the yhub container | `{}` |
|
||||
| `yhub.nodeSelector` | Node selector for the yhub Pod | `{}` |
|
||||
| `yhub.tolerations` | Tolerations for the yhub Pod | `[]` |
|
||||
| `yhub.affinity` | Affinity for the yhub Pod | `{}` |
|
||||
| `yhub.persistence` | Additional volumes to create and mount on the yhub. Used for debugging purposes | `{}` |
|
||||
| `yhub.persistence.volume-name.size` | Size of the additional volume | |
|
||||
| `yhub.persistence.volume-name.type` | Type of the additional volume, persistentVolumeClaim or emptyDir | |
|
||||
| `yhub.persistence.volume-name.mountPath` | Path where the volume should be mounted to | |
|
||||
| `yhub.extraVolumeMounts` | Additional volumes to mount on the yhub. Mounted on the init-db job too | `[]` |
|
||||
| `yhub.extraVolumes` | Additional volumes to mount on the yhub. Mounted on the init-db job too | `[]` |
|
||||
| `yhub.pdb.enabled` | Enable pdb on yhub | `true` |
|
||||
| `yhub.serviceAccountName` | Optional service account name to use for yhub pods | `nil` |
|
||||
|
||||
### docSpec
|
||||
|
||||
| Name | Description | Value |
|
||||
| -------------------------------------------------- | --------------------------------------------------------------- | ----------------------- |
|
||||
| `docSpec.enabled` | Enable docSpec deployment | `false` |
|
||||
| `docSpec.image.repository` | Repository to use to pull docSpec container image | `ghcr.io/docspecio/api` |
|
||||
| `docSpec.image.tag` | docSpec container tag | `2.6.3` |
|
||||
| `docSpec.image.tag` | docSpec container tag | `3.0.1` |
|
||||
| `docSpec.image.pullPolicy` | docSpec container image pull policy | `IfNotPresent` |
|
||||
| `docSpec.command` | Override the docSpec container command | `[]` |
|
||||
| `docSpec.args` | Override the docSpec container args | `[]` |
|
||||
|
||||
@@ -186,16 +186,6 @@ Requires top level scope
|
||||
{{ include "impress.fullname" . }}-y-provider
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Full name for the yProvider converter
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.yProvider.converter.fullname" -}}
|
||||
{{ include "impress.yProvider.fullname" . }}-converter
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{/*
|
||||
Full name for the docSpec
|
||||
|
||||
@@ -205,6 +195,81 @@ Requires top level scope
|
||||
{{ include "impress.fullname" . }}-docspec
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Full name for the yhub collaboration server
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.yhub.fullname" -}}
|
||||
{{ include "impress.fullname" . }}-yhub
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
JWT signing keys — the RSA keys the services sign the calls they make to each
|
||||
other with. The jwt-keys job generates them once into a secret every service
|
||||
mounts read-only, so no key is ever templated into a manifest, written in a
|
||||
values file, or kept anywhere the services themselves can write.
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.jwtKeys.secretName" -}}
|
||||
{{- .Values.jwtKeys.existingSecret | default (printf "%s-jwt-keys" (include "impress.fullname" .)) -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "impress.jwtKeys.serviceAccountName" -}}
|
||||
{{- .Values.jwtKeys.job.serviceAccountName | default (printf "%s-jwt-keys" (include "impress.fullname" .)) -}}
|
||||
{{- end }}
|
||||
|
||||
{{- define "impress.jwtKeys.backendPath" -}}
|
||||
{{ .Values.jwtKeys.mountPath }}/{{ .Values.jwtKeys.backendKeyFilename }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "impress.jwtKeys.yhubPath" -}}
|
||||
{{ .Values.jwtKeys.mountPath }}/{{ .Values.jwtKeys.yhubKeyFilename }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
The volume holding the keys. A pod referencing a secret that does not exist yet
|
||||
stays in ContainerCreating and mounts it as soon as the job creates it, so
|
||||
nothing else is needed to order the two.
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.jwtKeys.volume" -}}
|
||||
- name: jwt-keys
|
||||
secret:
|
||||
secretName: {{ include "impress.jwtKeys.secretName" . }}
|
||||
# read-only for everyone, as the files the job generates are
|
||||
defaultMode: 0444
|
||||
{{- end }}
|
||||
|
||||
{{- define "impress.jwtKeys.volumeMount" -}}
|
||||
- name: jwt-keys
|
||||
mountPath: {{ .Values.jwtKeys.mountPath }}
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
`*_FILE` environment variables pointing at the keys, added only when the
|
||||
deployment did not set them by hand — configuring a key of your own stays
|
||||
possible, and wins.
|
||||
|
||||
Requires top level scope
|
||||
*/}}
|
||||
{{- define "impress.jwtKeys.backendEnv" -}}
|
||||
{{- if not (hasKey (.Values.backend.envVars | default dict) "JWT_PRIVATE_KEY_FILE") }}
|
||||
- name: "JWT_PRIVATE_KEY_FILE"
|
||||
value: {{ include "impress.jwtKeys.backendPath" . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- define "impress.jwtKeys.yhubEnv" -}}
|
||||
{{- if not (hasKey (.Values.yhub.envVars | default dict) "YHUB_JWT_PRIVATE_KEY_FILE") }}
|
||||
- name: "YHUB_JWT_PRIVATE_KEY_FILE"
|
||||
value: {{ include "impress.jwtKeys.yhubPath" . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
{{/*
|
||||
Full name for the Celery Worker
|
||||
|
||||
@@ -38,9 +38,12 @@ items:
|
||||
imagePullPolicy: {{ ($.Values.backend.image | default dict).pullPolicy | default $.Values.image.pullPolicy }}
|
||||
args:
|
||||
{{- toYaml .command | nindent 22 }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars $.Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 22 }}
|
||||
{{- if $.Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" $ | nindent 22 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $.Values.backend.envFrom }}
|
||||
envFrom:
|
||||
@@ -55,6 +58,9 @@ items:
|
||||
{{- toYaml . | nindent 22 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if $.Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" $ | nindent 20 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := $.Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -72,6 +78,9 @@ items:
|
||||
{{- end }}
|
||||
restartPolicy: {{ .restartPolicy | default "Never" }}
|
||||
volumes:
|
||||
{{- if $.Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" $ | nindent 16 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := $.Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -49,9 +49,12 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $envFrom := concat (.Values.backend.envFrom | default list) ((.Values.backend.django | default dict).envFrom | default list) }}
|
||||
{{- if $envFrom }}
|
||||
@@ -83,6 +86,9 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -116,6 +122,9 @@ spec:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -44,9 +44,12 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.backend.envFrom }}
|
||||
envFrom:
|
||||
@@ -61,6 +64,9 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -90,6 +96,9 @@ spec:
|
||||
{{- end }}
|
||||
restartPolicy: {{ .Values.backend.job.restartPolicy }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -48,9 +48,12 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.backend.envFrom }}
|
||||
envFrom:
|
||||
@@ -65,6 +68,9 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -94,6 +100,9 @@ spec:
|
||||
{{- end }}
|
||||
restartPolicy: {{ .Values.backend.createsuperuser.restartPolicy }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -48,9 +48,12 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.backend.envFrom }}
|
||||
envFrom:
|
||||
@@ -65,6 +68,9 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -94,6 +100,9 @@ spec:
|
||||
{{- end }}
|
||||
restartPolicy: {{ .Values.backend.migrate.restartPolicy }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -49,9 +49,12 @@ spec:
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.backendEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $envFrom := concat (.Values.backend.envFrom | default list) (.Values.backend.celery.envFrom | default list) }}
|
||||
{{- if $envFrom }}
|
||||
@@ -83,6 +86,9 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
@@ -116,6 +122,9 @@ spec:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
|
||||
@@ -46,20 +46,26 @@ spec:
|
||||
- host: {{ .Values.ingressCollaborationApi.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
- path: {{ .Values.ingressCollaborationApi.path | quote }}
|
||||
{{- /* one rule per route: what is not listed here is not reachable
|
||||
from the outside, which is how the backend-internal routes
|
||||
(reset-connections, migrate, restore-ydoc, reset-ydoc) stay
|
||||
in-cluster */}}
|
||||
{{- range .Values.ingressCollaborationApi.paths | default (list .Values.ingressCollaborationApi.path) }}
|
||||
- path: {{ . | quote }}
|
||||
{{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
pathType: ImplementationSpecific
|
||||
{{- end }}
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ include "impress.yProvider.fullname" . }}
|
||||
name: {{ include "impress.yhub.fullname" $ }}
|
||||
port:
|
||||
number: {{ .Values.yProvider.service.port }}
|
||||
number: {{ $.Values.yhub.service.port }}
|
||||
{{- else }}
|
||||
serviceName: {{ include "impress.yProvider.fullname" . }}
|
||||
servicePort: {{ .Values.yProvider.service.port }}
|
||||
serviceName: {{ include "impress.yhub.fullname" $ }}
|
||||
servicePort: {{ $.Values.yhub.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingressCollaborationApi.customBackends }}
|
||||
{{- toYaml . | nindent 10 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -53,12 +53,12 @@ spec:
|
||||
backend:
|
||||
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
|
||||
service:
|
||||
name: {{ include "impress.yProvider.fullname" . }}
|
||||
name: {{ include "impress.yhub.fullname" . }}
|
||||
port:
|
||||
number: {{ .Values.yProvider.service.port }}
|
||||
number: {{ .Values.yhub.service.port }}
|
||||
{{- else }}
|
||||
serviceName: {{ include "impress.yProvider.fullname" . }}
|
||||
servicePort: {{ .Values.yProvider.service.port }}
|
||||
serviceName: {{ include "impress.yhub.fullname" . }}
|
||||
servicePort: {{ .Values.yhub.service.port }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingressCollaborationWS.customBackends }}
|
||||
{{- toYaml . | nindent 10 }}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
{{- if and .Values.jwtKeys.enabled (not .Values.jwtKeys.existingSecret) -}}
|
||||
{{- $fullName := include "impress.fullname" . -}}
|
||||
{{- $component := "jwt-keys" -}}
|
||||
{{- $secretName := include "impress.jwtKeys.secretName" . -}}
|
||||
# Generates the RSA keys the services sign the calls they make to each other
|
||||
# with: one for the backend (the tokens Django issues to the collaboration
|
||||
# server and the converter), one for the collaboration server (the calls it
|
||||
# makes back to Django). Only the private halves are written — each service
|
||||
# publishes the public half of its own key on its JWKS endpoint, where the
|
||||
# other one reads it, so no key is ever copied from one side to the other.
|
||||
#
|
||||
# Two steps, two images: openssl writes the keys in a volume the pod throws
|
||||
# away, then kubectl hands them to the secret the services mount. They only
|
||||
# ever exist in that pod and in the secret.
|
||||
#
|
||||
# Idempotent, and deliberately so: the secret is left alone when it is already
|
||||
# there, which is what makes it safe to re-run on every sync. Rolling the keys
|
||||
# is deleting the secret and letting the next run create it again — both
|
||||
# services follow, they pick the verification key by its "kid" and re-fetch the
|
||||
# set when they meet one they do not know.
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ $fullName }}-jwt-keys
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-options: Replace=true,Force=true
|
||||
# after the service account it runs as, before anything mounting the secret
|
||||
argocd.argoproj.io/sync-wave: "-2"
|
||||
{{- with .Values.jwtKeys.job.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
spec:
|
||||
ttlSecondsAfterFinished: {{ .Values.jwtKeys.job.ttlSecondsAfterFinished }}
|
||||
backoffLimit: {{ .Values.jwtKeys.job.backoffLimit }}
|
||||
template:
|
||||
metadata:
|
||||
{{- with .Values.jwtKeys.job.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
|
||||
spec:
|
||||
{{- if $.Values.image.credentials }}
|
||||
imagePullSecrets:
|
||||
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
|
||||
{{- end}}
|
||||
serviceAccountName: {{ include "impress.jwtKeys.serviceAccountName" . }}
|
||||
{{- with .Values.jwtKeys.job.podSecurityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
restartPolicy: {{ .Values.jwtKeys.job.restartPolicy }}
|
||||
initContainers:
|
||||
- name: generate
|
||||
image: "{{ .Values.jwtKeys.image.repository }}:{{ .Values.jwtKeys.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.jwtKeys.image.pullPolicy }}
|
||||
{{- if .Values.jwtKeys.job.generateCommand }}
|
||||
command:
|
||||
{{- toYaml .Values.jwtKeys.job.generateCommand | nindent 12 }}
|
||||
{{- else }}
|
||||
# `command` rather than `args`: the image entrypoint is openssl
|
||||
# itself. The keys are the ones `bin/generate-jwt-private-key.sh`
|
||||
# writes for the compose stack, same command — PKCS#8 RSA, the format
|
||||
# both the backend and the collaboration server read.
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
|
||||
for name in {{ .Values.jwtKeys.backendKeyFilename | quote }} {{ .Values.jwtKeys.yhubKeyFilename | quote }}; do
|
||||
openssl genpkey -algorithm RSA \
|
||||
-pkeyopt rsa_keygen_bits:{{ .Values.jwtKeys.keySize }} \
|
||||
-out "/keys/$name"
|
||||
echo "$name generated"
|
||||
done
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: keys
|
||||
mountPath: /keys
|
||||
containers:
|
||||
- name: publish
|
||||
image: "{{ .Values.jwtKeys.kubectlImage.repository }}:{{ .Values.jwtKeys.kubectlImage.tag }}"
|
||||
imagePullPolicy: {{ .Values.jwtKeys.kubectlImage.pullPolicy }}
|
||||
{{- if .Values.jwtKeys.job.publishCommand }}
|
||||
command:
|
||||
{{- toYaml .Values.jwtKeys.job.publishCommand | nindent 12 }}
|
||||
{{- else }}
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
|
||||
# the keys generated above are dropped on the floor when the
|
||||
# secret is already there: they are new ones, and replacing the
|
||||
# live pair is a decision, never a side effect of a sync
|
||||
if kubectl get secret {{ $secretName | quote }} >/dev/null 2>&1; then
|
||||
echo "secret {{ $secretName }} already exists, keeping the keys it holds"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
kubectl create secret generic {{ $secretName | quote }} \
|
||||
--from-file={{ .Values.jwtKeys.backendKeyFilename }}=/keys/{{ .Values.jwtKeys.backendKeyFilename }} \
|
||||
--from-file={{ .Values.jwtKeys.yhubKeyFilename }}=/keys/{{ .Values.jwtKeys.yhubKeyFilename }}
|
||||
echo "secret {{ $secretName }} created"
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.env }}
|
||||
env:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
- name: keys
|
||||
mountPath: /keys
|
||||
readOnly: true
|
||||
{{- with .Values.jwtKeys.job.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.jwtKeys.job.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
# the keys live here for the lifetime of this pod and nowhere else
|
||||
- name: keys
|
||||
emptyDir:
|
||||
medium: Memory
|
||||
{{- end }}
|
||||
@@ -0,0 +1,63 @@
|
||||
{{- if and .Values.jwtKeys.enabled .Values.jwtKeys.rbac.create (not .Values.jwtKeys.existingSecret) -}}
|
||||
{{- $component := "jwt-keys" -}}
|
||||
{{- $name := include "impress.jwtKeys.serviceAccountName" . -}}
|
||||
# The generating job is the only thing in this release allowed to touch the
|
||||
# secret holding the keys, and all it is allowed to do is read whether it
|
||||
# exists and create it — not read its content back, not replace it, not delete
|
||||
# it. The services themselves get the keys through a volume, so they need no
|
||||
# access to the kubernetes API at all.
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
# The same wave as the job that runs under it. An earlier wave looks safer
|
||||
# and is not: argocd only moves to the next wave once the current one is
|
||||
# healthy, and a ServiceAccount has no health of its own to report. Within
|
||||
# a wave it applies by kind, and accounts, roles and bindings all come
|
||||
# before jobs — which is the ordering actually needed here.
|
||||
argocd.argoproj.io/sync-wave: "-2"
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-2"
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
rules:
|
||||
# creating cannot be restricted to a name, kubernetes has no such rule
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
verbs: ["create"]
|
||||
# reading can, and is restricted to the one secret — to its existence really,
|
||||
# the job never looks at what it holds
|
||||
- apiGroups: [""]
|
||||
resources: ["secrets"]
|
||||
resourceNames:
|
||||
- {{ include "impress.jwtKeys.secretName" . | quote }}
|
||||
verbs: ["get"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "-2"
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: {{ $name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ $name }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,178 @@
|
||||
{{- if .Values.yhub.enabled -}}
|
||||
{{- $envVars := include "impress.common.env" (list . .Values.yhub) -}}
|
||||
{{- $fullName := include "impress.yhub.fullname" . -}}
|
||||
{{- $component := "yhub" -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
{{- with .Values.yhub.dpAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.yhub.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.yhub.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
|
||||
spec:
|
||||
{{- if $.Values.image.credentials }}
|
||||
imagePullSecrets:
|
||||
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
|
||||
{{- end}}
|
||||
{{- if .Values.yhub.serviceAccountName }}
|
||||
serviceAccountName: {{ .Values.yhub.serviceAccountName }}
|
||||
{{- end }}
|
||||
shareProcessNamespace: {{ .Values.yhub.shareProcessNamespace }}
|
||||
# a websocket connection is dropped when the pod goes away, and the client
|
||||
# reconnects to another one — but the updates it sent are only in redis
|
||||
# until a worker persists them, so leave the embedded worker time to drain
|
||||
terminationGracePeriodSeconds: {{ .Values.yhub.terminationGracePeriodSeconds }}
|
||||
containers:
|
||||
{{- with .Values.yhub.sidecars }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ (.Values.yhub.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.yhub.image | default dict).tag | default .Values.image.tag }}"
|
||||
imagePullPolicy: {{ (.Values.yhub.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
|
||||
{{- with .Values.yhub.command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if or $envVars .Values.jwtKeys.enabled }}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.yhubEnv" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.yhub.envFrom }}
|
||||
envFrom:
|
||||
{{- toYaml .Values.yhub.envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.yhub.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- if .Values.yhub.probes.liveness }}
|
||||
livenessProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.yhub.probes.liveness (dict "targetPort" .Values.yhub.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.yhub.probes.readiness }}
|
||||
readinessProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.yhub.probes.readiness (dict "targetPort" .Values.yhub.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.yhub.probes.startup }}
|
||||
startupProbe:
|
||||
{{- include "impress.probes.abstract" (merge .Values.yhub.probes.startup (dict "targetPort" .Values.yhub.service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volumeMount" . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
subPath: content
|
||||
{{- end }}
|
||||
{{- range $name, $volume := .Values.yhub.persistence }}
|
||||
- name: "{{ $name }}"
|
||||
mountPath: "{{ $volume.mountPath }}"
|
||||
{{- end }}
|
||||
{{- range .Values.yhub.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- if .Values.jwtKeys.enabled }}
|
||||
{{- include "impress.jwtKeys.volume" . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
|
||||
{{- end }}
|
||||
{{- range $name, $volume := .Values.yhub.persistence }}
|
||||
- name: "{{ $name }}"
|
||||
{{- if eq $volume.type "emptyDir" }}
|
||||
emptyDir: {}
|
||||
{{- else }}
|
||||
persistentVolumeClaim:
|
||||
claimName: "{{ $fullName }}-{{ $name }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range .Values.yhub.extraVolumes }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .existingClaim }}
|
||||
{{- else if .secret }}
|
||||
secret:
|
||||
{{ toYaml .secret | nindent 12 }}
|
||||
{{- else if .hostPath }}
|
||||
hostPath:
|
||||
{{ toYaml .hostPath | nindent 12 }}
|
||||
{{- else if .csi }}
|
||||
csi:
|
||||
{{- toYaml .csi | nindent 12 }}
|
||||
{{- else if .configMap }}
|
||||
configMap:
|
||||
{{- toYaml .configMap | nindent 12 }}
|
||||
{{- else if .emptyDir }}
|
||||
emptyDir:
|
||||
{{- toYaml .emptyDir | nindent 12 }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if .Values.yhub.pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,148 @@
|
||||
{{- if and .Values.yhub.enabled .Values.yhub.initDb.enabled -}}
|
||||
{{- $envVars := include "impress.common.env" (list . .Values.yhub) -}}
|
||||
{{- $fullName := include "impress.yhub.fullname" . -}}
|
||||
{{- $component := "yhub" -}}
|
||||
# yhub never runs DDL from the server or the worker: the schema is created by
|
||||
# the script it ships, which creates the database when it is missing and every
|
||||
# table the installed version needs. It is idempotent, and it has to run again
|
||||
# on every yhub upgrade that adds a table — the counterpart of the backend
|
||||
# migrate job, hence the same Replace=true so a re-sync re-runs it.
|
||||
#
|
||||
# No sync wave, again like the backend migrate job: it runs in the default one,
|
||||
# alongside it, and waits for its database the way that one waits for Django's.
|
||||
# An earlier wave only moved it ahead of the postgres it needs.
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ $fullName }}-init-db
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-options: Replace=true,Force=true
|
||||
{{- with .Values.yhub.initDbJobAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
spec:
|
||||
ttlSecondsAfterFinished: {{ .Values.yhub.jobs.ttlSecondsAfterFinished }}
|
||||
backoffLimit: {{ .Values.yhub.jobs.backoffLimit }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.yhub.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
|
||||
spec:
|
||||
{{- if $.Values.image.credentials }}
|
||||
imagePullSecrets:
|
||||
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
|
||||
{{- end}}
|
||||
{{- if .Values.yhub.serviceAccountName }}
|
||||
serviceAccountName: {{ .Values.yhub.serviceAccountName }}
|
||||
{{- end }}
|
||||
shareProcessNamespace: {{ .Values.yhub.shareProcessNamespace }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ (.Values.yhub.image | default dict).repository | default .Values.image.repository }}:{{ (.Values.yhub.image | default dict).tag | default .Values.image.tag }}"
|
||||
imagePullPolicy: {{ (.Values.yhub.image | default dict).pullPolicy | default .Values.image.pullPolicy }}
|
||||
{{- if .Values.yhub.initDb.command }}
|
||||
command:
|
||||
{{- toYaml .Values.yhub.initDb.command | nindent 12 }}
|
||||
{{- else }}
|
||||
# The script yhub ships, wrapped as `npm run init-db`, retried until
|
||||
# the postgres server answers: nothing here creates it, and a chart
|
||||
# sync does not wait for whatever does. Retrying the whole script
|
||||
# rather than probing the port first — it is idempotent, so a run
|
||||
# against a database that is up but incomplete is a no-op, and no
|
||||
# postgres client has to be present in the image to ask.
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
set -u
|
||||
|
||||
attempt=1
|
||||
until node node_modules/@y/hub/bin/init-db.js; do
|
||||
if [ "$attempt" -ge {{ .Values.yhub.initDb.retries }} ]; then
|
||||
echo "database still unreachable after $attempt attempts, giving up"
|
||||
exit 1
|
||||
fi
|
||||
echo "database not ready, retrying in {{ .Values.yhub.initDb.retryDelaySeconds }}s ($attempt/{{ .Values.yhub.initDb.retries }})"
|
||||
attempt=$((attempt + 1))
|
||||
sleep {{ .Values.yhub.initDb.retryDelaySeconds }}
|
||||
done
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.yhub.envFrom }}
|
||||
envFrom:
|
||||
{{- toYaml .Values.yhub.envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.initDb.resources | default .Values.yhub.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
subPath: content
|
||||
{{- end }}
|
||||
{{- range .Values.yhub.extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.yhub.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
restartPolicy: {{ .Values.yhub.initDb.restartPolicy }}
|
||||
volumes:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
|
||||
{{- end }}
|
||||
{{- range .Values.yhub.extraVolumes }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .existingClaim }}
|
||||
{{- else if .secret }}
|
||||
secret:
|
||||
{{ toYaml .secret | nindent 12 }}
|
||||
{{- else if .hostPath }}
|
||||
hostPath:
|
||||
{{ toYaml .hostPath | nindent 12 }}
|
||||
{{- else if .csi }}
|
||||
csi:
|
||||
{{- toYaml .csi | nindent 12 }}
|
||||
{{- else if .configMap }}
|
||||
configMap:
|
||||
{{- toYaml .configMap | nindent 12 }}
|
||||
{{- else if .emptyDir }}
|
||||
emptyDir:
|
||||
{{- toYaml .emptyDir | nindent 12 }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,22 @@
|
||||
{{- if .Values.yhub.enabled -}}
|
||||
{{- $fullName := include "impress.yhub.fullname" . -}}
|
||||
{{- $component := "yhub" -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
annotations:
|
||||
{{- toYaml $.Values.yhub.service.annotations | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.yhub.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.yhub.service.port }}
|
||||
targetPort: {{ .Values.yhub.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
{{- with .Values.backend.dpAnnotations }}
|
||||
{{- with .Values.yProvider.dpAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
{{ if .Values.yProvider.converter.enabled -}}
|
||||
{{- $yProvider := .Values.yProvider -}}
|
||||
{{- $converter := .Values.yProvider.converter -}}
|
||||
{{- $service := mergeOverwrite (dict) (default dict $yProvider.service) (default dict $converter.service) -}}
|
||||
{{- $image := mergeOverwrite (dict) (default dict $yProvider.image) (default dict $converter.image) -}}
|
||||
{{- $probes := mergeOverwrite (dict) (default dict $yProvider.probes) (default dict $converter.probes) -}}
|
||||
{{- $pdb := mergeOverwrite (dict) (default dict $yProvider.pdb) (default dict $converter.pdb) -}}
|
||||
{{- $dpAnnotations := mergeOverwrite (dict) (default dict $yProvider.dpAnnotations) (default dict $converter.dpAnnotations) -}}
|
||||
{{- $podAnnotations := mergeOverwrite (dict) (default dict $yProvider.podAnnotations) (default dict $converter.podAnnotations) -}}
|
||||
{{- $replicas := default $yProvider.replicas $converter.replicas -}}
|
||||
{{- $serviceAccountName := default $yProvider.serviceAccountName $converter.serviceAccountName -}}
|
||||
{{- $shareProcessNamespace := default $yProvider.shareProcessNamespace $converter.shareProcessNamespace -}}
|
||||
{{- $sidecars := default $yProvider.sidecars $converter.sidecars -}}
|
||||
{{- $command := default $yProvider.command $converter.command -}}
|
||||
{{- $args := default $yProvider.args $converter.args -}}
|
||||
{{- $envFrom := default $yProvider.envFrom $converter.envFrom -}}
|
||||
{{- $securityContext := mergeOverwrite (dict) (default dict $yProvider.securityContext) (default dict $converter.securityContext) -}}
|
||||
{{- $resources := mergeOverwrite (dict) (default dict $yProvider.resources) (default dict $converter.resources) -}}
|
||||
{{- $nodeSelector := mergeOverwrite (dict) (default dict $yProvider.nodeSelector) (default dict $converter.nodeSelector) -}}
|
||||
{{- $affinity := mergeOverwrite (dict) (default dict $yProvider.affinity) (default dict $converter.affinity) -}}
|
||||
{{- $tolerations := default $yProvider.tolerations $converter.tolerations -}}
|
||||
{{- $persistence := mergeOverwrite (dict) (default dict $yProvider.persistence) (default dict $converter.persistence) -}}
|
||||
{{- $extraVolumeMounts := default $yProvider.extraVolumeMounts $converter.extraVolumeMounts -}}
|
||||
{{- $extraVolumes := default $yProvider.extraVolumes $converter.extraVolumes -}}
|
||||
{{- $envVarsScope := dict "envVars" (mergeOverwrite (dict) (default dict $yProvider.envVars) (default dict $converter.envVars)) -}}
|
||||
{{- $envVars := include "impress.common.env" (list . $envVarsScope) -}}
|
||||
{{- $fullName := include "impress.yProvider.converter.fullname" . -}}
|
||||
{{- $component := "yProvider-converter" -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
annotations:
|
||||
{{- with $dpAnnotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ $replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with $podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 8 }}
|
||||
spec:
|
||||
{{- if $.Values.image.credentials }}
|
||||
imagePullSecrets:
|
||||
- name: {{ include "impress.secret.dockerconfigjson.name" (dict "fullname" (include "impress.fullname" .) "imageCredentials" $.Values.image.credentials) }}
|
||||
{{- end}}
|
||||
{{- if $serviceAccountName }}
|
||||
serviceAccountName: {{ $serviceAccountName }}
|
||||
{{- end }}
|
||||
shareProcessNamespace: {{ $shareProcessNamespace }}
|
||||
containers:
|
||||
{{- with $sidecars }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ $image.repository | default $.Values.image.repository }}:{{ $image.tag | default $.Values.image.tag }}"
|
||||
imagePullPolicy: {{ $image.pullPolicy | default $.Values.image.pullPolicy }}
|
||||
{{- with $command }}
|
||||
command:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $args }}
|
||||
args:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envVars}}
|
||||
env:
|
||||
{{- $envVars | indent 12 }}
|
||||
{{- end }}
|
||||
{{- if $envFrom }}
|
||||
envFrom:
|
||||
{{- toYaml $envFrom | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ $service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- if $probes.liveness }}
|
||||
livenessProbe:
|
||||
{{- include "impress.probes.abstract" (merge $probes.liveness (dict "targetPort" $service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $probes.readiness }}
|
||||
readinessProbe:
|
||||
{{- include "impress.probes.abstract" (merge $probes.readiness (dict "targetPort" $service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if $probes.startup }}
|
||||
startupProbe:
|
||||
{{- include "impress.probes.abstract" (merge $probes.startup (dict "targetPort" $service.targetPort )) | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
mountPath: {{ $value.path }}
|
||||
subPath: content
|
||||
{{- end }}
|
||||
{{- range $name, $volume := $persistence }}
|
||||
- name: "{{ $name }}"
|
||||
mountPath: "{{ $volume.mountPath }}"
|
||||
{{- end }}
|
||||
{{- range $extraVolumeMounts }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
subPath: {{ .subPath | default "" }}
|
||||
readOnly: {{ .readOnly }}
|
||||
{{- end }}
|
||||
{{- with $nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
{{- range $index, $value := .Values.mountFiles }}
|
||||
- name: "files-{{ $index }}"
|
||||
configMap:
|
||||
name: "{{ include "impress.fullname" $ }}-files-{{ $index }}"
|
||||
{{- end }}
|
||||
{{- range $name, $volume := $persistence }}
|
||||
- name: "{{ $name }}"
|
||||
{{- if eq $volume.type "emptyDir" }}
|
||||
emptyDir: {}
|
||||
{{- else }}
|
||||
persistentVolumeClaim:
|
||||
claimName: "{{ $fullName }}-{{ $name }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $extraVolumes }}
|
||||
- name: {{ .name }}
|
||||
{{- if .existingClaim }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .existingClaim }}
|
||||
{{- else if .secret }}
|
||||
secret:
|
||||
{{ toYaml .secret | nindent 12 }}
|
||||
{{- else if .hostPath }}
|
||||
hostPath:
|
||||
{{ toYaml .hostPath | nindent 12 }}
|
||||
{{- else if .csi }}
|
||||
csi:
|
||||
{{- toYaml .csi | nindent 12 }}
|
||||
{{- else if .configMap }}
|
||||
configMap:
|
||||
{{- toYaml .configMap | nindent 12 }}
|
||||
{{- else if .emptyDir }}
|
||||
emptyDir:
|
||||
{{- toYaml .emptyDir | nindent 12 }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{ if $pdb.enabled }}
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
spec:
|
||||
maxUnavailable: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 6 }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
@@ -1,25 +0,0 @@
|
||||
{{ if .Values.yProvider.converter.enabled -}}
|
||||
{{- $yProvider := .Values.yProvider -}}
|
||||
{{- $converter := .Values.yProvider.converter -}}
|
||||
{{- $service := mergeOverwrite (dict) (default dict $yProvider.service) (default dict $converter.service) -}}
|
||||
{{- $fullName := include "impress.yProvider.converter.fullname" . -}}
|
||||
{{- $component := "yProvider-converter" -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
namespace: {{ .Release.Namespace | quote }}
|
||||
labels:
|
||||
{{- include "impress.common.labels" (list . $component) | nindent 4 }}
|
||||
annotations:
|
||||
{{- toYaml $service.annotations | nindent 4 }}
|
||||
spec:
|
||||
type: {{ $service.type }}
|
||||
ports:
|
||||
- port: {{ $service.port }}
|
||||
targetPort: {{ $service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "impress.common.selectorLabels" (list . $component) | nindent 4 }}
|
||||
{{ end -}}
|
||||
+332
-77
@@ -78,12 +78,14 @@ ingressCollaborationWS:
|
||||
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/enable-websocket
|
||||
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-read-timeout
|
||||
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/proxy-send-timeout
|
||||
## @param ingressCollaborationWS.annotations.nginx.ingress.kubernetes.io/upstream-hash-by
|
||||
##
|
||||
## No upstream-hash-by: yhub passes updates between its replicas through
|
||||
## redis, so two clients editing the same document may land on different
|
||||
## pods — where the y-provider it replaces needed a room to stay on one.
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/enable-websocket: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
|
||||
nginx.ingress.kubernetes.io/upstream-hash-by: $arg_room
|
||||
|
||||
## @param ingressRedirects.enabled whether to enable the Ingress Redirects or not
|
||||
## @param ingressRedirects.className IngressClass to use for the Ingress Redirects
|
||||
@@ -112,7 +114,22 @@ ingressCollaborationApi:
|
||||
enabled: false
|
||||
className: null
|
||||
host: impress.example.com
|
||||
## Only used when `paths` below is empty
|
||||
path: /collaboration/api/
|
||||
## @param ingressCollaborationApi.paths Paths to route to the collaboration server, one rule each
|
||||
##
|
||||
## The routes yhub serves to browsers, guarded by the same document
|
||||
## authorization as the websocket. Everything it serves that is not listed
|
||||
## here stays in-cluster — `create-ydoc`, `reset-connections`, `migrate`,
|
||||
## `restore-ydoc` and `reset-ydoc` are called by the backend only, and
|
||||
## publishing them would put document deletion and the legacy migration one
|
||||
## request away from the internet.
|
||||
##
|
||||
## `jwks` is public on purpose: it carries the public halves of the keys
|
||||
## yhub signs with, and nothing else.
|
||||
paths:
|
||||
- /collaboration/ydoc/
|
||||
- /collaboration/jwks/
|
||||
## @param ingressCollaborationApi.hosts Additional host to configure for the Ingress
|
||||
hosts: []
|
||||
# - chart-example.local
|
||||
@@ -129,9 +146,10 @@ ingressCollaborationApi:
|
||||
## @param ingressCollaborationApi.customBackends Add custom backends to ingress
|
||||
customBackends: []
|
||||
|
||||
## @param ingressCollaborationApi.annotations.nginx.ingress.kubernetes.io/upstream-hash-by
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/upstream-hash-by: $arg_room
|
||||
## @skip ingressCollaborationApi.annotations
|
||||
## Same as ingressCollaborationWS: no upstream-hash-by, any yhub replica
|
||||
## answers for any document.
|
||||
annotations: {}
|
||||
|
||||
## @param ingressAdmin.enabled whether to enable the Ingress or not
|
||||
## @param ingressAdmin.className IngressClass to use for the Ingress
|
||||
@@ -643,7 +661,11 @@ posthog:
|
||||
annotations: {}
|
||||
|
||||
## @section yProvider
|
||||
|
||||
##
|
||||
## The conversion service, and nothing else since the collaboration moved to
|
||||
## yhub: this deployment *is* the converter the backend calls on
|
||||
## `Y_PROVIDER_API_BASE_URL`, so there is no separate converter release to
|
||||
## enable anymore.
|
||||
yProvider:
|
||||
## @param yProvider.image.repository Repository to use to pull impress's yProvider container image
|
||||
## @param yProvider.image.tag impress's yProvider container tag
|
||||
@@ -653,77 +675,6 @@ yProvider:
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "latest"
|
||||
|
||||
converter:
|
||||
## @param yProvider.converter.enabled Enable the yProvider converter deployment and service
|
||||
enabled: false
|
||||
|
||||
## @param yProvider.converter.replicas Amount of yProvider replicas
|
||||
replicas: 3
|
||||
|
||||
## @param yProvider.converter.resources Resource requirements for the yProvider container
|
||||
resources: {}
|
||||
|
||||
## @param yProvider.converter.service.type yProvider converter Service type
|
||||
## @param yProvider.converter.service.port yProvider converter Service listening port
|
||||
## @param yProvider.converter.service.targetPort yProvider converter container listening port
|
||||
## @param yProvider.converter.service.annotations Annotations to add to the yProvider converter Service
|
||||
service: {}
|
||||
|
||||
## @param yProvider.converter.command Override the yProvider converter container command
|
||||
command: []
|
||||
|
||||
## @param yProvider.converter.args Override the yProvider converter container args
|
||||
args: []
|
||||
|
||||
## @param yProvider.converter.shareProcessNamespace Enable share process namespace between containers
|
||||
shareProcessNamespace: false
|
||||
|
||||
## @param yProvider.converter.sidecars Add sidecars containers to yProvider converter deployment
|
||||
sidecars: []
|
||||
|
||||
## @skip yProvider.converter.securityContext
|
||||
securityContext: {}
|
||||
|
||||
## @skip yProvider.converter.envVars
|
||||
envVars: {}
|
||||
|
||||
## @skip yProvider.converter.envFrom
|
||||
envFrom: []
|
||||
|
||||
## @param yProvider.converter.podAnnotations Annotations to add to the yProvider converter Pod
|
||||
podAnnotations: {}
|
||||
|
||||
## @param yProvider.converter.dpAnnotations Annotations to add to the yProvider converter Deployment
|
||||
dpAnnotations: {}
|
||||
|
||||
## @skip yProvider.converter.probes
|
||||
probes: {}
|
||||
|
||||
## @param yProvider.converter.nodeSelector Node selector for the yProvider converter Pod
|
||||
nodeSelector: {}
|
||||
|
||||
## @param yProvider.converter.tolerations Tolerations for the yProvider converter Pod
|
||||
tolerations: []
|
||||
|
||||
## @param yProvider.converter.affinity Affinity for the yProvider converter Pod
|
||||
affinity: {}
|
||||
|
||||
## @param yProvider.converter.persistence Additional volumes to create and mount on the yProvider converter
|
||||
persistence: {}
|
||||
|
||||
## @param yProvider.converter.extraVolumeMounts Additional volumes to mount on the yProvider converter
|
||||
extraVolumeMounts: []
|
||||
|
||||
## @param yProvider.converter.extraVolumes Additional volumes to mount on the yProvider converter
|
||||
extraVolumes: []
|
||||
|
||||
## @param yProvider.converter.pdb.enabled Enable pdb on yProvider converter
|
||||
pdb:
|
||||
enabled: true
|
||||
|
||||
## @param yProvider.converter.serviceAccountName Optional service account name to use for yProvider converter pods
|
||||
serviceAccountName: null
|
||||
|
||||
## @param yProvider.command Override the yProvider container command
|
||||
command: []
|
||||
|
||||
@@ -834,6 +785,310 @@ yProvider:
|
||||
## @param yProvider.serviceAccountName Optional service account name to use for yProvider pods
|
||||
serviceAccountName: null
|
||||
|
||||
## @section JWT signing keys
|
||||
##
|
||||
## The services do not share a secret: each signs the calls it makes to the
|
||||
## others with an RSA key of its own and publishes the public half on its JWKS
|
||||
## endpoint, where the others read it. Enabling this generates those keys on
|
||||
## the cluster — a job creates them once in a secret every service mounts
|
||||
## read-only, and leaves them alone on the next run — and points the backend
|
||||
## and the collaboration server at them. No key is ever templated into a
|
||||
## manifest or written in a values file, and only that job may create the
|
||||
## secret: nothing in the release can read it back through the api.
|
||||
##
|
||||
## Leave it disabled to keep providing the keys yourself, through
|
||||
## `backend.envVars.JWT_PRIVATE_KEY_FILE` and
|
||||
## `yhub.envVars.YHUB_JWT_PRIVATE_KEY_FILE` and volumes of your own — both are
|
||||
## left untouched when they are set by hand, enabled or not.
|
||||
jwtKeys:
|
||||
## @param jwtKeys.enabled Generate the JWT signing keys of the services on the cluster
|
||||
enabled: false
|
||||
|
||||
## @param jwtKeys.existingSecret Secret already holding the keys, generated in a secret of the chart's own when empty
|
||||
##
|
||||
## It has to hold the two filenames below. Naming one skips the job and the
|
||||
## rights it needs, the services only mount what is there.
|
||||
existingSecret: null
|
||||
|
||||
## @param jwtKeys.mountPath Path the keys are mounted at, in every service reading them
|
||||
mountPath: /data/jwt
|
||||
|
||||
## @param jwtKeys.backendKeyFilename Name of the key signing the tokens the backend issues
|
||||
backendKeyFilename: private.pem
|
||||
|
||||
## @param jwtKeys.yhubKeyFilename Name of the key signing the calls the collaboration server makes to the backend
|
||||
yhubKeyFilename: yhub-private.pem
|
||||
|
||||
## @param jwtKeys.keySize Size, in bits, of the generated RSA keys
|
||||
keySize: 2048
|
||||
|
||||
## @param jwtKeys.rbac.create Create the service account and the role the job needs to create the secret
|
||||
##
|
||||
## Turning it off means providing `jwtKeys.job.serviceAccountName` with an
|
||||
## account allowed to `create` secrets and to `get` the one named above.
|
||||
rbac:
|
||||
create: true
|
||||
|
||||
## @param jwtKeys.image.repository Repository to use to pull the image generating the keys
|
||||
## @param jwtKeys.image.tag Tag of the image generating the keys
|
||||
## @param jwtKeys.image.pullPolicy Pull policy of the image generating the keys
|
||||
##
|
||||
## openssl and a shell, nothing else. Its entrypoint is openssl itself, which
|
||||
## the job replaces by the script generating both keys.
|
||||
image:
|
||||
repository: alpine/openssl
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "3.5.7"
|
||||
|
||||
## @param jwtKeys.kubectlImage.repository Repository to use to pull the image handing the keys to the secret
|
||||
## @param jwtKeys.kubectlImage.tag Tag of the image handing the keys to the secret
|
||||
## @param jwtKeys.kubectlImage.pullPolicy Pull policy of the image handing the keys to the secret
|
||||
##
|
||||
## A second image because the openssl one carries no kubectl, and reaching
|
||||
## the api with what it does carry (busybox wget, which cannot be told about
|
||||
## the cluster ca) would mean sending the token over an unverified
|
||||
## connection.
|
||||
kubectlImage:
|
||||
repository: dtzar/helm-kubectl
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "3.16.2"
|
||||
|
||||
## @param jwtKeys.job.podSecurityContext Pod security context of the generating job
|
||||
## @param jwtKeys.job.securityContext.allowPrivilegeEscalation Whether to allow privilege escalation for the job containers
|
||||
## @param jwtKeys.job.securityContext.capabilities.drop List of capabilities to drop for the job containers
|
||||
## @param jwtKeys.job.securityContext.runAsNonRoot Whether to run the job containers as a non-root user
|
||||
## @param jwtKeys.job.securityContext.runAsUser User the job containers run as, their images declaring none
|
||||
## @param jwtKeys.job.securityContext.runAsGroup Group the job containers run as
|
||||
## @param jwtKeys.job.securityContext.seccompProfile.type Seccomp profile type for the job containers
|
||||
## @param jwtKeys.job.restartPolicy Restart policy of the generating job
|
||||
## @param jwtKeys.job.backoffLimit Numbers of generating job retries
|
||||
## @param jwtKeys.job.ttlSecondsAfterFinished Period to wait before removing the generating job
|
||||
## @param jwtKeys.job.generateCommand Override the command generating the keys
|
||||
## @param jwtKeys.job.publishCommand Override the command creating the secret from the generated keys
|
||||
## @param jwtKeys.job.annotations Annotations to add to the generating job
|
||||
## @param jwtKeys.job.podAnnotations Annotations to add to the generating job Pod
|
||||
## @param jwtKeys.job.resources Resource requirements for the job containers
|
||||
## @param jwtKeys.job.nodeSelector Node selector for the generating job Pod
|
||||
## @param jwtKeys.job.tolerations Tolerations for the generating job Pod
|
||||
## @param jwtKeys.job.affinity Affinity for the generating job Pod
|
||||
## @param jwtKeys.job.serviceAccountName Service account of the generating job Pod, the one created above when empty
|
||||
## @skip jwtKeys.job.env
|
||||
job:
|
||||
podSecurityContext: {}
|
||||
# neither image declares a user of its own, and kubernetes refuses to start
|
||||
# a container asking for runAsNonRoot without knowing which user to run as
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- "ALL"
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
restartPolicy: Never
|
||||
backoffLimit: 2
|
||||
ttlSecondsAfterFinished: 30
|
||||
generateCommand: []
|
||||
publishCommand: []
|
||||
annotations: {}
|
||||
podAnnotations: {}
|
||||
resources: {}
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
serviceAccountName: null
|
||||
env: []
|
||||
|
||||
## @section yhub
|
||||
##
|
||||
## The collaboration server: it serves the whole /collaboration/ prefix, the
|
||||
## websocket included, and replaces the y-provider on that role. It keeps the
|
||||
## live state of a document in redis/valkey and persists it to its own
|
||||
## PostgreSQL database, so it needs both — set `yhub.envVars.REDIS` and
|
||||
## `yhub.envVars.POSTGRES`, there is nothing sensible to default them to.
|
||||
## Disabling it sends the /collaboration/ ingresses back to the y-provider.
|
||||
yhub:
|
||||
## @param yhub.enabled Enable the yhub collaboration server, its service and its init-db job
|
||||
enabled: true
|
||||
|
||||
## @param yhub.image.repository Repository to use to pull the yhub container image
|
||||
## @param yhub.image.tag yhub container tag
|
||||
## @param yhub.image.pullPolicy yhub container image pull policy
|
||||
image:
|
||||
repository: lasuite/impress-yhub
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "latest"
|
||||
|
||||
## @param yhub.command Override the yhub container command
|
||||
command: []
|
||||
|
||||
## @param yhub.args Override the yhub container args
|
||||
args: []
|
||||
|
||||
## @param yhub.replicas Amount of yhub replicas
|
||||
## Every replica also runs a worker (redis consumer groups hand each task to
|
||||
## one of them), and clients editing the same document need not land on the
|
||||
## same pod: updates travel through redis.
|
||||
replicas: 3
|
||||
|
||||
## @param yhub.shareProcessNamespace Enable share process namespace between containers
|
||||
shareProcessNamespace: false
|
||||
|
||||
## @param yhub.sidecars Add sidecars containers to yhub deployment
|
||||
sidecars: []
|
||||
|
||||
## @param yhub.terminationGracePeriodSeconds Grace period given to a yhub pod to drain before it is killed
|
||||
terminationGracePeriodSeconds: 60
|
||||
|
||||
## @param yhub.securityContext.allowPrivilegeEscalation Whether to allow privilege escalation for the yhub container
|
||||
## @param yhub.securityContext.capabilities.drop List of capabilities to drop for the yhub container
|
||||
## @param yhub.securityContext.runAsNonRoot Whether to run the yhub container as a non-root user
|
||||
## @param yhub.securityContext.runAsUser User the yhub container runs as
|
||||
## @param yhub.securityContext.runAsGroup Group the yhub container runs as
|
||||
## @param yhub.securityContext.seccompProfile.type Seccomp profile type for the yhub container
|
||||
##
|
||||
## The user is named rather than left to the image: asking for runAsNonRoot
|
||||
## without it is refused outright by kubernetes ("container has runAsNonRoot
|
||||
## and image will run as root") on any image that declares none — which every
|
||||
## yhub image built before the un-privileged user was added to its Dockerfile
|
||||
## does. 1000 is the `node` user the base image already carries.
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- "ALL"
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
## @param yhub.envVars Configure yhub container environment variables
|
||||
## @extra yhub.envVars.REDIS Required, redis/valkey url holding the live document state (e.g. redis://valkey:6379/0)
|
||||
## @extra yhub.envVars.POSTGRES Required, url of the yhub database, created by the init-db job (e.g. postgres://user:pass@postgres:5432/yhub)
|
||||
## @extra yhub.envVars.REDIS_PREFIX Namespace of the redis keys, when the instance is shared (default: yhub)
|
||||
## @extra yhub.envVars.COLLABORATION_BACKEND_BASE_URL Base url of the Docs backend, which yhub asks about users and document access rights
|
||||
## @extra yhub.envVars.COLLABORATION_SERVER_ORIGIN Comma separated list of the origins allowed to open a websocket
|
||||
## @extra yhub.envVars.YHUB_JWT_PRIVATE_KEY_FILE Path to the RSA private key (PEM) yhub signs its calls to the backend with, mounted from a secret
|
||||
## @extra yhub.envVars.SOFT_MIGRATION Set to "true" to seed rooms from the legacy Django/S3 document store on first access
|
||||
## @extra yhub.envVars.BY_VALUE Example environment variable by setting value directly
|
||||
## @extra yhub.envVars.FROM_CONFIGMAP.configMapKeyRef.name Name of a ConfigMap when configuring env vars from a ConfigMap
|
||||
## @extra yhub.envVars.FROM_CONFIGMAP.configMapKeyRef.key Key within a ConfigMap when configuring env vars from a ConfigMap
|
||||
## @extra yhub.envVars.FROM_SECRET.secretKeyRef.name Name of a Secret when configuring env vars from a Secret
|
||||
## @extra yhub.envVars.FROM_SECRET.secretKeyRef.key Key within a Secret when configuring env vars from a Secret
|
||||
## @skip yhub.envVars
|
||||
envVars:
|
||||
<<: *commonEnvVars
|
||||
|
||||
## @skip yhub.envFrom List of environment variables taken from Secrets or configMaps
|
||||
envFrom: []
|
||||
# envFrom:
|
||||
# - secret:
|
||||
# name: super-secret-user-credentials
|
||||
# - configMapRef:
|
||||
# name: my-environment-variables
|
||||
|
||||
## @param yhub.podAnnotations Annotations to add to the yhub Pod
|
||||
podAnnotations: {}
|
||||
|
||||
## @param yhub.dpAnnotations Annotations to add to the yhub Deployment
|
||||
dpAnnotations: {}
|
||||
|
||||
## @param yhub.initDbJobAnnotations Annotations for the yhub init-db job
|
||||
initDbJobAnnotations: {}
|
||||
|
||||
## @param yhub.jobs.ttlSecondsAfterFinished Period to wait before removing the init-db job
|
||||
## @param yhub.jobs.backoffLimit Numbers of init-db job retries
|
||||
jobs:
|
||||
ttlSecondsAfterFinished: 30
|
||||
backoffLimit: 2
|
||||
|
||||
## @param yhub.initDb.enabled Run the job creating and upgrading the yhub schema
|
||||
## @param yhub.initDb.command Override the command creating and upgrading the yhub schema
|
||||
## @param yhub.initDb.retries How many times the schema script is retried while the postgres server does not answer
|
||||
## @param yhub.initDb.retryDelaySeconds Seconds between two attempts
|
||||
## @param yhub.initDb.restartPolicy Restart policy of the init-db job
|
||||
## @skip yhub.initDb.resources Resource requirements for the init-db container, defaults to yhub.resources
|
||||
##
|
||||
## The job runs in the default sync wave, next to the backend migrate job,
|
||||
## and waits for its database the same way that one waits for Django's:
|
||||
## nothing in this chart creates the postgres server, so it has to be given
|
||||
## the time whatever does takes. The defaults below wait five minutes.
|
||||
initDb:
|
||||
enabled: true
|
||||
command: []
|
||||
retries: 60
|
||||
retryDelaySeconds: 5
|
||||
restartPolicy: Never
|
||||
resources: {}
|
||||
|
||||
## @param yhub.service.type yhub Service type
|
||||
## @param yhub.service.port yhub Service listening port
|
||||
## @param yhub.service.targetPort yhub container listening port
|
||||
## @param yhub.service.annotations Annotations to add to the yhub Service
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 443
|
||||
targetPort: 3002
|
||||
annotations: {}
|
||||
|
||||
## @param yhub.probes.liveness.path Configure path for yhub HTTP liveness probe
|
||||
## @param yhub.probes.liveness.initialDelaySeconds Configure initial delay for yhub liveness probe
|
||||
## @param yhub.probes.readiness.path Configure path for yhub HTTP readiness probe
|
||||
## @param yhub.probes.readiness.initialDelaySeconds Configure initial delay for yhub readiness probe
|
||||
## @extra yhub.probes.liveness.targetPort Configure port for yhub HTTP liveness probe
|
||||
## @extra yhub.probes.liveness.timeoutSeconds Configure timeout for yhub liveness probe
|
||||
## @extra yhub.probes.readiness.targetPort Configure port for yhub HTTP readiness probe
|
||||
## @extra yhub.probes.readiness.timeoutSeconds Configure timeout for yhub readiness probe
|
||||
## @extra yhub.probes.startup.path Configure path for yhub HTTP startup probe
|
||||
## @extra yhub.probes.startup.targetPort Configure port for yhub HTTP startup probe
|
||||
## @extra yhub.probes.startup.initialDelaySeconds Configure initial delay for yhub startup probe
|
||||
## @extra yhub.probes.startup.timeoutSeconds Configure timeout for yhub startup probe
|
||||
##
|
||||
## The JWKS route is the only one yhub serves unauthenticated: it answers 200
|
||||
## with the public keys it signs its calls to the backend with (an empty set
|
||||
## when no key is configured), and reads neither redis nor postgres.
|
||||
probes:
|
||||
liveness:
|
||||
path: /collaboration/jwks/v1
|
||||
initialDelaySeconds: 10
|
||||
readiness:
|
||||
path: /collaboration/jwks/v1
|
||||
initialDelaySeconds: 5
|
||||
|
||||
## @param yhub.resources Resource requirements for the yhub container
|
||||
resources: {}
|
||||
|
||||
## @param yhub.nodeSelector Node selector for the yhub Pod
|
||||
nodeSelector: {}
|
||||
|
||||
## @param yhub.tolerations Tolerations for the yhub Pod
|
||||
tolerations: []
|
||||
|
||||
## @param yhub.affinity Affinity for the yhub Pod
|
||||
affinity: {}
|
||||
|
||||
## @param yhub.persistence Additional volumes to create and mount on the yhub. Used for debugging purposes
|
||||
## @extra yhub.persistence.volume-name.size Size of the additional volume
|
||||
## @extra yhub.persistence.volume-name.type Type of the additional volume, persistentVolumeClaim or emptyDir
|
||||
## @extra yhub.persistence.volume-name.mountPath Path where the volume should be mounted to
|
||||
persistence: {}
|
||||
|
||||
## @param yhub.extraVolumeMounts Additional volumes to mount on the yhub. Mounted on the init-db job too
|
||||
extraVolumeMounts: []
|
||||
|
||||
## @param yhub.extraVolumes Additional volumes to mount on the yhub. Mounted on the init-db job too
|
||||
extraVolumes: []
|
||||
|
||||
## @param yhub.pdb.enabled Enable pdb on yhub
|
||||
pdb:
|
||||
enabled: true
|
||||
|
||||
## @param yhub.serviceAccountName Optional service account name to use for yhub pods
|
||||
serviceAccountName: null
|
||||
|
||||
## @section docSpec
|
||||
docSpec:
|
||||
## @param docSpec.enabled Enable docSpec deployment
|
||||
|
||||
@@ -3,7 +3,9 @@ FROM node:22-trixie AS base
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
# built from the repository root, like every other image here — the entrypoint
|
||||
# below lives outside this directory
|
||||
COPY ./src/yhub-server/package.json ./src/yhub-server/package-lock.json ./
|
||||
|
||||
|
||||
# ---- Development image ----
|
||||
@@ -16,7 +18,7 @@ RUN npm ci
|
||||
# server.js, migration.js, env.js — glob so a new module cannot be forgotten.
|
||||
# compose bind-mounts the sources over /app on top of this copy, so an edit on
|
||||
# the host is seen immediately; the copy keeps the image usable on its own.
|
||||
COPY *.js ./
|
||||
COPY ./src/yhub-server/*.js ./
|
||||
|
||||
EXPOSE 3002
|
||||
|
||||
@@ -32,8 +34,24 @@ FROM base AS yhub
|
||||
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
COPY *.js ./
|
||||
COPY ./src/yhub-server/*.js ./
|
||||
|
||||
EXPOSE 3002
|
||||
|
||||
# Same entrypoint as the other services: it gives the container user an entry in
|
||||
# /etc/passwd, which an arbitrary uid (kubernetes runAsUser) does not have. The
|
||||
# group needs the same rights as the owner on /etc/passwd for it to write there.
|
||||
COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint
|
||||
RUN chmod g=u /etc/passwd
|
||||
|
||||
# Un-privileged user running the application. The server writes nothing outside
|
||||
# stdout, so it needs no home and no writable path. Defaulted, unlike the other
|
||||
# images of this repository: the helm chart runs the pod with runAsNonRoot, and
|
||||
# a build that forgot the argument would produce an image kubernetes refuses to
|
||||
# start.
|
||||
ARG DOCKER_USER=1000
|
||||
USER ${DOCKER_USER}
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -85,7 +85,15 @@ repository:
|
||||
`app crashed - waiting for file changes` and the next save starts the server
|
||||
again,
|
||||
- `yhub` — the production image: production dependencies only, `node
|
||||
server.js`, sources baked in.
|
||||
server.js`, sources baked in, and the un-privileged user and the entrypoint
|
||||
the other services use (kubernetes runs the pod with `runAsNonRoot`).
|
||||
|
||||
Both are built **from the repository root**, like every other image here — the
|
||||
entrypoint they share lives outside this directory:
|
||||
|
||||
```
|
||||
docker build -f src/yhub-server/Dockerfile --target yhub .
|
||||
```
|
||||
|
||||
nodemon rather than node's own `--watch`: the latter watches inodes, so it
|
||||
stops seeing a file as soon as it is replaced by a rename — which is what `git
|
||||
|
||||
Reference in New Issue
Block a user