-
Notifications
You must be signed in to change notification settings - Fork 0
docs: unorphan seven pages, write the four placeholders, add admin guides #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # Docusaurus fails a build on a sidebar entry with no page, but publishes a page | ||
| # with no sidebar entry and says nothing. Seven instructor pages sat live and | ||
| # unreachable that way, including the two that set expectations honestly. | ||
|
|
||
| name: CI | ||
|
|
||
| on: | ||
| pull_request: | ||
| push: | ||
| branches: [main] | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| structure: | ||
| name: Pages are reachable and links resolve | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - run: ./scripts/check-docs.sh | ||
|
|
||
| build: | ||
| name: Site builds | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 20 | ||
| cache: npm | ||
| - run: npm ci | ||
| - run: npm run build |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| --- | ||
| title: Adding an Installation | ||
| description: Standing up a new EduIDE installation for a course, department or university. | ||
| --- | ||
|
|
||
| # Adding an Installation | ||
|
|
||
| An installation is one namespace on one cluster, with its own hostnames, | ||
| branding and identity provider. Adding one is a file, a GitHub Environment and | ||
| an approval — not a bespoke deployment. | ||
|
|
||
| ## 1. Describe it | ||
|
|
||
| Two files under `environments/<name>/` in the deployment repository. They are | ||
| split by who reads them: `env.yaml` configures the **deploy** and Helm never | ||
| sees it; `values.yaml` configures the **chart** and the workflow never | ||
| interprets it. | ||
|
|
||
| `env.yaml` is deploy metadata only: | ||
|
|
||
| ```yaml | ||
| apiVersion: eduide.dev/v1 | ||
| kind: Environment | ||
| metadata: | ||
| name: bonn | ||
| displayName: EduIDE Bonn | ||
| tier: production # test | staging | production | ||
| spec: | ||
| cluster: eduide # must match a file in clusters/ | ||
| namespace: eduide-bonn # every namespace carries the eduide- prefix | ||
| platform: | ||
| chartVersion: 2.0.0 | ||
| channel: release # release | main | ||
| ``` | ||
|
|
||
| `values.yaml` is a plain Helm values file: hosts, Gateway `parentRefs`, Keycloak | ||
| and branding. Nothing else — image tags, app definitions, the preload list and | ||
| the storage class are all derived or come from the cluster. | ||
|
|
||
| ## 2. Create the GitHub Environment | ||
|
|
||
| Named exactly as the directory, holding: | ||
|
|
||
| | Secret | What | | ||
| |---|---| | ||
| | `KUBECONFIG` | the cluster's kubeconfig | | ||
| | `THEIA_KEYCLOAK_COOKIE_SECRET` | `dd if=/dev/urandom bs=32 count=1 \| base64 \| tr -d -- '\n' \| tr -- '+/' '-_'` | | ||
|
|
||
| The admin API token is a repository secret and is inherited. | ||
|
|
||
| Add required reviewers for anything `tier: production` or `staging`. **Do not** | ||
| add them to an environment that deploys automatically — the approval gate blocks | ||
| the automation outright and the run waits forever. | ||
|
|
||
| ## 3. Bootstrap the cluster | ||
|
|
||
| ``` | ||
| Actions -> Bootstrap cluster -> cluster: <name>, dry_run: true | ||
| ``` | ||
|
|
||
| This derives the Gateway's listeners, the certificate's hostnames and the | ||
| monitored namespaces from every environment that claims the cluster. Adding an | ||
| installation therefore needs no second file edited — and cannot end up with a | ||
| certificate that omits it, which is exactly how one environment ran for six | ||
| months on a certificate covering only its neighbours. | ||
|
|
||
| Read the diff, then run it again with `dry_run: false`. | ||
|
|
||
| ## 4. Outside the repositories | ||
|
|
||
| - **DNS** for all four hostnames. | ||
| - **Keycloak**: a client matching `clientId`, with redirect URIs for all four | ||
| hosts. A wrong realm or client fails at login, not at deploy, so nothing in CI | ||
| catches it. | ||
| - **The webview wildcard certificate**, which cert-manager cannot issue over | ||
| HTTP-01. It goes in the cluster's bootstrap environment as | ||
| `THEIA_WILDCARD_CERTIFICATE_CERT` and `_KEY`. | ||
|
|
||
| ## 5. Deploy | ||
|
|
||
| ``` | ||
| Actions -> Deploy (dispatch) -> environment: <name> | ||
| ``` | ||
|
|
||
| The deploy asserts which cluster it reached before touching anything, shows a | ||
| `helm diff` before applying, runs `--wait --atomic`, and prints a summary read | ||
| back from the cluster rather than echoed from its inputs. | ||
|
|
||
| ## A note on identity | ||
|
|
||
| An installation with no identity provider configured yet must say so explicitly | ||
| with `keycloak.allowUnauthenticated: true`. The chart otherwise refuses to | ||
| render. | ||
|
|
||
| That flag exists because the oauth2-proxy configuration is emitted regardless of | ||
| whether Keycloak is enabled — the operator mounts it into every session pod by | ||
| literal name, so it cannot be conditional. Left at the chart's defaults it points | ||
| the proxy at a host that does not exist, and sessions fail at the proxy rather | ||
| than running unauthenticated. That is the worst of both outcomes, so the chart | ||
| makes you choose deliberately. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| --- | ||
| title: Installing EduIDE | ||
| description: Installing the platform on a cluster from the published charts. | ||
| --- | ||
|
|
||
| # Installing EduIDE | ||
|
|
||
| EduIDE ships as two Helm charts, published as OCI artifacts to | ||
| `ghcr.io/eduide/charts`. They always carry the same version, and that version | ||
| is the platform version. | ||
|
|
||
| | Chart | Installed | Owns | | ||
| |---|---|---| | ||
| | `eduide-cluster` | once per **cluster** | CRDs, the conversion webhook, ClusterRoles, cert-manager issuers, the shared Gateway, PodMonitors and dashboards | | ||
| | `eduide` | once per **environment** | operator, REST service, landing page, routes, app definitions, image preloading | | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| The split exists because the two halves have different cardinality. CRDs and a | ||
| Gateway must exist once on a cluster; a tenant install exists once per namespace, | ||
| and there may be several on the same cluster. Installing cluster-scoped | ||
| resources from every tenant deploy is what previously made concurrent deploys | ||
| race each other. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| The cluster must already have: | ||
|
|
||
| - **cert-manager**, for the conversion webhook's certificate and for issuing | ||
| hostname certificates | ||
| - **Gateway API CRDs** and a Gateway controller. EduIDE is tested with Envoy | ||
| Gateway | ||
| - a **storage class** for session volumes | ||
|
|
||
| ## Cluster half | ||
|
|
||
| These two commands are the manual path. Day to day, `bootstrap-cluster.yml` and | ||
| `deploy.yml` run them for you — see | ||
| [Provisioning](../platform/provisioning.md). | ||
|
Comment on lines
+35
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
command -v helm >/dev/null
command -v kubectl >/dev/null
tmp="$(mktemp -d)"
namespace="docs-review-${RANDOM}-${RANDOM}"
cleanup() {
helm uninstall docs-review-release -n "$namespace" >/dev/null 2>&1 || true
kubectl delete namespace "$namespace" --wait=false >/dev/null 2>&1 || true
rm -rf "$tmp"
}
trap cleanup EXIT
helm create "$tmp/chart" >/dev/null
helm install docs-review-release "$tmp/chart" \
--namespace "$namespace" --create-namespace >/dev/null
if helm install docs-review-release "$tmp/chart" \
--namespace "$namespace" >/dev/null 2>&1; then
echo "Unexpected: helm install reused an existing release"
exit 1
fi
helm upgrade --install docs-review-release "$tmp/chart" \
--namespace "$namespace" >/dev/nullRepository: EduIDE/Docs Length of output: 149 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- documented commands ---'
sed -n '1,125p' docs/admins/install/installing.md
printf '%s\n' '--- Helm references and version pins ---'
rg -n -i --glob '!node_modules' --glob '!dist' 'helm(Version| version| install| upgrade)|azure/setup-helm|helm/kind-action' .github docs . 2>/dev/null | head -200Repository: EduIDE/Docs Length of output: 6571 🌐 Web query:
💡 Result: To handle a release that may or may not already exist, you should use the command: helm upgrade --install [flags] The --install (or -i) flag makes the helm upgrade command idempotent [1]. When this flag is provided, Helm checks if a release with the specified name already exists in the target namespace [1]. 1. If the release does not exist, Helm will perform an install [2][1]. 2. If the release already exists, Helm will perform an upgrade [1]. This approach is the standard, recommended practice for automation and CI/CD pipelines because it eliminates the need to manually check for a release's existence before deploying [1]. Important Note on Failed Initial Installs: If a first-time installation fails (leaving the release in a 'failed' or 'pending-install' status), subsequent runs of helm upgrade --install may encounter errors, as the release technically exists in the Helm history [1][3]. In such cases, you may need to manually uninstall or purge the failed release before the command will function correctly again [3]. Citations:
Support existing releases in the manual path. If the pipeline is unavailable after a release exists, 🤖 Prompt for AI Agents |
||
|
|
||
| ```bash | ||
| helm install eduide-cluster oci://ghcr.io/eduide/charts/eduide-cluster \ | ||
| --version 2.0.0 -n eduide-system --create-namespace \ | ||
| -f cluster-values.yaml | ||
| ``` | ||
|
|
||
| `cluster-values.yaml` supplies the Gateway's listeners and the certificate | ||
| names. In the TUM installations this file is not written by hand — the | ||
| `Bootstrap cluster` workflow derives it from the environment manifests, so | ||
| adding an environment does not mean remembering to edit a second file. | ||
|
|
||
| ## Tenant half | ||
|
|
||
| ```bash | ||
| helm install eduide oci://ghcr.io/eduide/charts/eduide \ | ||
| --version 2.0.0 -n eduide-test1 --create-namespace \ | ||
| -f values.yaml -f secrets.yaml | ||
| ``` | ||
|
|
||
| The chart refuses to install if the cluster chart is absent, rather than letting | ||
| the operator crash-loop on a missing CRD. | ||
|
|
||
| ## What one version pins | ||
|
|
||
| A bare install with no overrides pins every image. Nothing floats. | ||
|
|
||
| | Value | Source repository | Default | | ||
| |---|---|---| | ||
| | `versions.ide` | EduIDE — the IDE images | empty, meaning the chart's `appVersion` | | ||
| | `versions.cloud` | EduIDE-Cloud — operator and REST service | set by the release | | ||
| | `versions.landingPage` | EduIDE-Landing-Page | set by the release | | ||
|
|
||
| They are separate because the three repositories release on different cadences, | ||
| and a one-line landing-page fix should not rebuild fifteen multi-gigabyte IDE | ||
| images. | ||
|
|
||
| **Never set a single tag for everything.** A pull request only builds the images | ||
| of the repository it came from, so pointing all three at `pr-451` puts most of | ||
| the namespace into `ImagePullBackOff`. | ||
|
|
||
| ## Minimum values | ||
|
|
||
| ```yaml | ||
| hosts: | ||
| configuration: | ||
| baseHost: eduide.example.edu | ||
| landing: eduide | ||
| service: service.eduide | ||
| instance: instance.eduide | ||
| allWildcardInstances: ["*.webview."] | ||
|
|
||
| keycloak: | ||
| enable: true | ||
| authUrl: https://sso.example.edu/ | ||
| realm: your-realm | ||
| clientId: eduide | ||
|
|
||
| gateway: | ||
| parentRefs: | ||
| - { name: theia-shared-gateway, namespace: eduide-system, sectionName: prod-landing } | ||
| - { name: theia-shared-gateway, namespace: eduide-system, sectionName: prod-service } | ||
| - { name: theia-shared-gateway, namespace: eduide-system, sectionName: prod-instances } | ||
| - { name: theia-shared-gateway, namespace: eduide-system, sectionName: prod-webview } | ||
| ``` | ||
|
|
||
| Secrets — the Keycloak cookie secret and the admin API token — go in a second | ||
| values file, never on the command line. `--set` puts them in the process list | ||
| and in Actions debug logs. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| **In normal operation you do not write that file.** The deploy workflow | ||
| generates it on the runner from the environment's GitHub Environment secrets and | ||
| it never reaches the repository. The commands on this page are for a first | ||
| install on a new cluster, or for manual intervention when the pipeline is | ||
| unavailable — in which case write `secrets.yaml` yourself, keep it out of git, | ||
| and delete it afterwards. Everything non-secret belongs in `values.yaml`. | ||
|
|
||
| ## Four hostnames, not one | ||
|
|
||
| Each installation serves: | ||
|
|
||
| ``` | ||
| <landing> the landing page | ||
| service.<landing> the REST service | ||
| instance.<landing> session ingress | ||
| *.webview.instance.<landing> per-session webviews | ||
| ``` | ||
|
|
||
| All four need DNS and all four need to be on a certificate. The webview host is | ||
| two labels below the instance host, so a wildcard covering the others does not | ||
| cover it — it needs its own certificate, and because it is a wildcard, | ||
| cert-manager cannot issue it over HTTP-01. | ||
|
|
||
| **A certificate that omits a hostname fails silently.** The Gateway reports the | ||
| listener healthy — Gateway API never compares a certificate's names against a | ||
| listener's hostname — so the first symptom is a browser warning, and the second | ||
| is the landing page being unable to call its own REST service, because the | ||
| browser blocks that cross-origin request over an invalid certificate. | ||
|
|
||
| ## Verifying | ||
|
|
||
| ```bash | ||
| kubectl -n <namespace> get deploy # operator, service, landing-page, garbage-collector | ||
| kubectl -n <namespace> get appdefinitions.theia.cloud | ||
| kubectl -n <namespace> get httproute -o wide | ||
| curl -sI https://<landing>/ # 200, and TLS must validate without -k | ||
| ``` | ||
|
|
||
| Then start a real session from the landing page. Everything above can be healthy | ||
| while sessions do not start. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| --- | ||
| title: Release and Version Policy | ||
| description: What a version number means here, and how a release is cut. | ||
| --- | ||
|
|
||
| # Release and Version Policy | ||
|
|
||
| ## One version, one meaning | ||
|
|
||
| | Thing | Form | Example | | ||
| |---|---|---| | ||
| | git tag | `vX.Y.Z` | `v2.0.0` | | ||
| | chart `version` | `X.Y.Z` | `2.0.0` | | ||
| | image tag | `X.Y.Z` | `1.2.0` | | ||
| | chart `appVersion` | the EduIDE IDE image version | `1.2.0` | | ||
|
|
||
| The chart version is the **platform** version and is what an installation pins. | ||
| `appVersion` is the tag of the IDE images, so a chart states exactly which IDEs | ||
| it runs. | ||
|
|
||
| The operator, REST service and landing page carry their own versions in | ||
| `versions.cloud` and `versions.landingPage`, because they release on a different | ||
| cadence. A one-line landing-page fix should not rebuild fifteen multi-gigabyte | ||
| IDE images. | ||
|
|
||
| Three spellings of a git tag existed historically — `1.1.0`, `v1.1.0` and | ||
| `v.1.1.1` — which is why nothing could reliably answer "which release produced | ||
| this image". A shared CI check now rejects anything that is not `vX.Y.Z`. Old | ||
| tags are not retagged. | ||
|
|
||
| ## Cutting a release | ||
|
|
||
| The release train in EduIDE-Helm does it, and defaults to `dry_run: true`. | ||
|
|
||
| 1. **Validate** the version is semver and the tag is unused. | ||
| 2. **Build every component at that tag** — but tag nothing yet. Building fifteen | ||
| large images is the flakiest step in the pipeline; tagging afterwards means a | ||
| flake costs a re-run rather than stranding immutable tags on repositories | ||
| whose images were never published. | ||
| 3. **Verify every expected image exists**, for both architectures. The IDE image | ||
| list is read from EduIDE's build matrix at run time, not kept by hand — a | ||
| hand-kept copy went stale within days and would have let a release verify ten | ||
| of twelve images and pass. | ||
| 4. **Only now tag and release** the component repositories. | ||
| 5. **Publish both charts** at the same version. | ||
| 6. **Open a bump pull request** against each production installation. Production | ||
| is never deployed automatically. | ||
|
|
||
| ## Channels | ||
|
|
||
| An installation is `release` or `main`. | ||
|
|
||
| - `release` pins whatever its values file says. Nothing that happens on `main` | ||
| can move a production image. | ||
| - `main` resolves an immutable `latest-<sha>` tag. Never a floating tag: with a | ||
| floating tag the pod template does not change between upgrades, so Helm sees | ||
| no difference, reports success without pulling, and `--atomic` has nothing to | ||
| roll back. | ||
|
|
||
| ## Upgrading an installation | ||
|
|
||
| Change `chartVersion` in that environment's `env.yaml` and open a pull request. | ||
| CI renders the change; the diff shows what will happen before anyone approves | ||
| it. Production environments require a reviewer on the GitHub Environment, so the | ||
| approval is recorded on the run. |
Uh oh!
There was an error while loading. Please reload this page.