diff --git a/.github/workflows/deploy-theia.yml b/.github/workflows/deploy-theia.yml index b868832..8d6e809 100644 --- a/.github/workflows/deploy-theia.yml +++ b/.github/workflows/deploy-theia.yml @@ -261,6 +261,15 @@ jobs: # This is installed once per cluster, not per environment helm upgrade theia-monitoring ./charts/theia-monitoring --install -n default + - name: Install internal TLS infrastructure + env: + KUBECONFIG: ${{ github.workspace }}/kubeconfig + run: | + + # Install cluster-scoped internal CA and trust bundle (once per cluster) + # Distributes the trust bundle ConfigMap to all namespaces + helm upgrade --install theia-internal-tls ./charts/theia-internal-tls -n cert-manager + # Step 5: Install shared Gateway (optional, cluster-level) - name: Install Shared Gateway (optional) if: inputs.deploy_shared_gateway && inputs.shared_gateway_values_file != '' diff --git a/README.md b/README.md index ff2f57a..4b700cd 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,9 @@ This repository serves as the infrastructure-as-code for deploying and managing ├── charts/ # Custom Helm charts │ ├── theia-cloud-combined/ # Combined chart with all components │ ├── theia-shared-gateway/ # Shared Gateway API entrypoint +│ ├── theia-internal-tls/ # Cluster-scoped internal CA + trust bundle │ ├── theia-appdefinitions/ # Custom IDE environments (images/configs) -│ ├── theia-certificates/ # SSL certificate management +│ ├── theia-certificates/ # SSL certificate management (per-namespace) │ └── theia-metrics/ # Prometheus/Grafana dashboards │ ├── value-reference-files/ # Reference Helm values for different setups @@ -147,7 +148,16 @@ Configuration files for each environment are located in the [deployments/](deplo For the dedicated production cluster, use: `deployments/shared-gateway-prod/values.yaml`. -4. **Install the combined Theia Cloud chart**: +4. **Install the internal TLS infrastructure (once per cluster)**: + ```bash + helm upgrade --install theia-internal-tls ./charts/theia-internal-tls \ + --namespace cert-manager + ``` + This deploys the cluster-scoped internal CA and trust bundle used for TLS + between internal services (e.g., shared cache and workspaces). The trust + bundle ConfigMap is automatically distributed to all namespaces. + +5. **Install the combined Theia Cloud chart**: ```bash helm registry login ghcr.io helm upgrade --install theia-cloud-combined ./charts/theia-cloud-combined \ diff --git a/charts/theia-certificates/templates/cache-internal-certificate.yml b/charts/theia-certificates/templates/cache-internal-certificate.yml new file mode 100644 index 0000000..228b174 --- /dev/null +++ b/charts/theia-certificates/templates/cache-internal-certificate.yml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: cache-internal-cert +spec: + secretName: cache-internal-cert-secret + issuerRef: + name: theia-internal-ca-issuer + kind: ClusterIssuer + commonName: "theia-shared-cache" + dnsNames: + - theia-cloud-combined-cache + - theia-cloud-combined-cache.{{ .Release.Namespace }}.svc.cluster.local + privateKey: + rotationPolicy: Never diff --git a/charts/theia-cloud-combined/Chart.yaml b/charts/theia-cloud-combined/Chart.yaml index 16a0d47..de73f64 100644 --- a/charts/theia-cloud-combined/Chart.yaml +++ b/charts/theia-cloud-combined/Chart.yaml @@ -21,6 +21,6 @@ dependencies: version: 0.1.0 repository: "oci://ghcr.io/eduide/charts" - - name: theia-shared-cache - version: "0.3.1" + - name: eduide-shared-cache + version: 0.5.0 repository: "oci://ghcr.io/eduide/charts" diff --git a/charts/theia-cloud-combined/values.yaml b/charts/theia-cloud-combined/values.yaml index 4b29b11..5859156 100644 --- a/charts/theia-cloud-combined/values.yaml +++ b/charts/theia-cloud-combined/values.yaml @@ -6,6 +6,9 @@ hosts: landing: theia instance: instance.theia +theia-shared-cache: + enabled: false + theia-certificates: hosts: configuration: *hostsConfig @@ -49,6 +52,11 @@ theia-cloud: sessionsPerUser: 10 storageClassName: csi-rbd-sc eagerStart: true + enableBuildCaching: false + buildCacheUrl: "" + enableBuildCachePush: false + enableDependencyCaching: false + dependencyCacheUrl: "" service: image: ghcr.io/eduide/eduide-cloud/service:latest diff --git a/charts/theia-internal-tls/Chart.yaml b/charts/theia-internal-tls/Chart.yaml new file mode 100644 index 0000000..12894f9 --- /dev/null +++ b/charts/theia-internal-tls/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: theia-internal-tls +description: Cluster-scoped trust infrastructure for internal tls (internal CA + trust bundle) +version: 0.1.0 +appVersion: 1.0.0 \ No newline at end of file diff --git a/charts/theia-internal-tls/templates/internal-ca.yml b/charts/theia-internal-tls/templates/internal-ca.yml new file mode 100644 index 0000000..4385b2e --- /dev/null +++ b/charts/theia-internal-tls/templates/internal-ca.yml @@ -0,0 +1,24 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: theia-internal-ca +spec: + isCA: true + commonName: theia-internal-ca + secretName: theia-internal-ca-secret + issuerRef: + name: theia-cloud-selfsigned-issuer + kind: ClusterIssuer + privateKey: + algorithm: ECDSA + size: 256 + duration: 87600h # 10 years + renewBefore: 8760h # renew 1 year before expiry +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: theia-internal-ca-issuer +spec: + ca: + secretName: theia-internal-ca-secret \ No newline at end of file diff --git a/charts/theia-internal-tls/templates/trust-bundle.yml b/charts/theia-internal-tls/templates/trust-bundle.yml new file mode 100644 index 0000000..5f5fa51 --- /dev/null +++ b/charts/theia-internal-tls/templates/trust-bundle.yml @@ -0,0 +1,24 @@ +apiVersion: trust.cert-manager.io/v1alpha1 +kind: Bundle +metadata: + name: theia-internal-trust +spec: + sources: + # Include the default public CAs (Let's Encrypt, etc.) + - useDefaultCAs: true + + # Internal CA certificate from cert-manager + - secret: + name: "theia-internal-ca-secret" + key: "ca.crt" + + target: + # trust-manager creates a ConfigMap with this name in target namespaces + configMap: + key: "trust-bundle.pem" + + # Also generate a JKS truststore (Java KeyStore) + # This is what Java/Gradle will use directly + additionalFormats: + jks: + key: "truststore.jks" \ No newline at end of file diff --git a/charts/theia-monitoring/templates/dashboard-cache.yaml b/charts/theia-monitoring/templates/dashboard-cache.yaml new file mode 100644 index 0000000..f5e17d4 --- /dev/null +++ b/charts/theia-monitoring/templates/dashboard-cache.yaml @@ -0,0 +1,538 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + grafana_dashboard: "1" + name: theia-cloud-dashboard-shared-cache + namespace: {{ .Values.dashboardNamespace }} +data: + shared-cache.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { "type": "grafana", "uid": "-- Grafana --" }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Monitoring dashboard for the Theia Shared Cache (Gradle Build Cache)", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, + "id": 100, + "panels": [], + "title": "Cache Performance", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Rate of cache hits vs cache misses per second", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 1 }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_cache_hits_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Hits", + "range": true, + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_cache_misses_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Misses", + "range": true, + "refId": "B" + } + ], + "title": "Cache Hits vs Misses (rate/s)", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Percentage of cache requests that resulted in a hit", + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "red", "value": null }, + { "color": "yellow", "value": 50 }, + { "color": "green", "value": 80 } + ] + }, + "unit": "percentunit", + "min": 0, + "max": 1 + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 1 }, + "id": 2, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_cache_hits_total{namespace=\"$namespace\"}[5m]) / rate(gradle_cache_requests_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Hit Rate", + "range": true, + "refId": "A" + } + ], + "title": "Cache Hit Rate", + "type": "gauge" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 9 }, + "id": 101, + "panels": [], + "title": "HTTP Requests", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Rate of HTTP requests per second to the cache server", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 10 }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_requests_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Requests/s", + "range": true, + "refId": "A" + } + ], + "title": "Request Rate", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Average request duration to the cache server", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 10 }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_request_duration_seconds_sum{namespace=\"$namespace\"}[5m]) / rate(gradle_cache_request_duration_seconds_count{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Avg Duration", + "range": true, + "refId": "A" + } + ], + "title": "Average Request Duration", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 18 }, + "id": 102, + "panels": [], + "title": "Cache Entry Size", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Average size of cache entries being stored", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 19 }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(gradle_cache_entry_size_bytes_sum{namespace=\"$namespace\"}[5m]) / rate(gradle_cache_entry_size_bytes_count{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Avg Entry Size", + "range": true, + "refId": "A" + } + ], + "title": "Average Cache Entry Size", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 27 }, + "id": 103, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "CPU usage of the cache server and Redis containers", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 28 }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"POD\", container!=\"\", job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=~\".*cache.*|.*redis.*\"}[1m])) by (pod)", + "instant": false, + "legendFormat": "{{ "{{" }}pod{{ "}}" }}", + "range": true, + "refId": "A" + } + ], + "title": "Cache CPU Usage", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Memory usage of the cache server and Redis containers", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 28 }, + "id": 7, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "container_memory_working_set_bytes{namespace=\"$namespace\", pod=~\".*cache.*|.*redis.*\", container!=\"POD\", container!=\"\"}", + "instant": false, + "legendFormat": "{{ "{{" }}pod{{ "}}" }}", + "range": true, + "refId": "A" + } + ], + "title": "Cache Memory Usage", + "type": "timeseries" + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "definition": "label_values(gradle_cache_cache_hits_total, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(gradle_cache_cache_hits_total, namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { "from": "now-3h", "to": "now" }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "Theia Shared Cache", + "uid": "theia-shared-cache-dash", + "version": 1, + "weekStart": "" + } diff --git a/charts/theia-monitoring/templates/dashboard-reposilite.yaml b/charts/theia-monitoring/templates/dashboard-reposilite.yaml new file mode 100644 index 0000000..45ae992 --- /dev/null +++ b/charts/theia-monitoring/templates/dashboard-reposilite.yaml @@ -0,0 +1,807 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + grafana_dashboard: "1" + name: theia-cloud-dashboard-reposilite + namespace: {{ .Values.dashboardNamespace }} +data: + reposilite.json: |- + { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { "type": "grafana", "uid": "-- Grafana --" }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Monitoring dashboard for the Reposilite Maven Proxy", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, + "id": 100, + "panels": [], + "title": "HTTP Requests", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Rate of HTTP requests per second", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 1 }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_requests_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Requests/s", + "range": true, + "refId": "A" + } + ], + "title": "Request Rate", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Currently active requests being handled", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 1 }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_requests_active{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Active Requests", + "range": true, + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_requests_active_max{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Peak Active", + "range": true, + "refId": "B" + } + ], + "title": "Active Requests", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 9 }, + "id": 101, + "panels": [], + "title": "Response Codes", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Rate of HTTP responses by status code class", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "normal" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [ + { + "matcher": { "id": "byName", "options": "2xx" }, + "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] + }, + { + "matcher": { "id": "byName", "options": "3xx" }, + "properties": [{ "id": "color", "value": { "fixedColor": "blue", "mode": "fixed" } }] + }, + { + "matcher": { "id": "byName", "options": "4xx" }, + "properties": [{ "id": "color", "value": { "fixedColor": "yellow", "mode": "fixed" } }] + }, + { + "matcher": { "id": "byName", "options": "5xx" }, + "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] + } + ] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 10 }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_responses_total{namespace=\"$namespace\", code=\"2xx\"}[5m])", + "instant": false, + "legendFormat": "2xx", + "range": true, + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_responses_total{namespace=\"$namespace\", code=\"3xx\"}[5m])", + "instant": false, + "legendFormat": "3xx", + "range": true, + "refId": "B" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_responses_total{namespace=\"$namespace\", code=\"4xx\"}[5m])", + "instant": false, + "legendFormat": "4xx", + "range": true, + "refId": "C" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_responses_total{namespace=\"$namespace\", code=\"5xx\"}[5m])", + "instant": false, + "legendFormat": "5xx", + "range": true, + "refId": "D" + } + ], + "title": "Response Codes (rate/s)", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Total bytes sent in responses", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 10 }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_responses_bytes_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Bytes/s", + "range": true, + "refId": "A" + } + ], + "title": "Response Throughput", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 18 }, + "id": 102, + "panels": [], + "title": "Request Timing", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Average request handling time", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 19 }, + "id": 5, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_request_time_seconds_total{namespace=\"$namespace\"}[5m]) / rate(jetty_requests_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Avg Request Time", + "range": true, + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_request_time_max_seconds{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Max Request Time", + "range": true, + "refId": "B" + } + ], + "title": "Request Duration", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Average dispatch handling time", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 19 }, + "id": 6, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "rate(jetty_dispatched_time_seconds_total{namespace=\"$namespace\"}[5m]) / rate(jetty_dispatched_total{namespace=\"$namespace\"}[5m])", + "instant": false, + "legendFormat": "Avg Dispatch Time", + "range": true, + "refId": "A" + } + ], + "title": "Dispatch Duration", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 27 }, + "id": 103, + "panels": [], + "title": "Thread Pool", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Thread pool utilization percentage", + "fieldConfig": { + "defaults": { + "color": { "mode": "thresholds" }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "yellow", "value": 60 }, + { "color": "red", "value": 85 } + ] + }, + "unit": "percentunit", + "min": 0, + "max": 1 + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 8, "x": 0, "y": 28 }, + "id": 7, + "options": { + "orientation": "auto", + "reduceOptions": { + "calcs": ["lastNotNull"], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "sizing": "auto" + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_queued_thread_pool_utilization{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Utilization", + "range": true, + "refId": "A" + } + ], + "title": "Thread Pool Utilization", + "type": "gauge" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Thread pool threads: total, idle, and queued jobs", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 16, "x": 8, "y": 28 }, + "id": 8, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_queued_thread_pool_threads{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Total Threads", + "range": true, + "refId": "A" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_queued_thread_pool_threads_idle{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Idle Threads", + "range": true, + "refId": "B" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "jetty_queued_thread_pool_jobs{namespace=\"$namespace\"}", + "instant": false, + "legendFormat": "Queued Jobs", + "range": true, + "refId": "C" + } + ], + "title": "Thread Pool Details", + "type": "timeseries" + }, + { + "collapsed": false, + "gridPos": { "h": 1, "w": 24, "x": 0, "y": 36 }, + "id": 104, + "panels": [], + "title": "Resource Usage", + "type": "row" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "CPU usage of the Reposilite pod", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + } + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 37 }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "sum(rate(container_cpu_usage_seconds_total{container!=\"POD\", container!=\"\", job=\"kubelet\", metrics_path=\"/metrics/cadvisor\", namespace=\"$namespace\", pod=~\".*reposilite.*\"}[1m])) by (pod)", + "instant": false, + "legendFormat": "{{ "{{" }}pod{{ "}}" }}", + "range": true, + "refId": "A" + } + ], + "title": "Reposilite CPU Usage", + "type": "timeseries" + }, + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "description": "Memory usage of the Reposilite pod", + "fieldConfig": { + "defaults": { + "color": { "mode": "palette-classic" }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { "legend": false, "tooltip": false, "viz": false }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { "type": "linear" }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { "group": "A", "mode": "none" }, + "thresholdsStyle": { "mode": "off" } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { "color": "green", "value": null }, + { "color": "red", "value": 80 } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 37 }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { "maxHeight": 600, "mode": "single", "sort": "none" } + }, + "targets": [ + { + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "editorMode": "code", + "expr": "container_memory_working_set_bytes{namespace=\"$namespace\", pod=~\".*reposilite.*\", container!=\"POD\", container!=\"\"}", + "instant": false, + "legendFormat": "{{ "{{" }}pod{{ "}}" }}", + "range": true, + "refId": "A" + } + ], + "title": "Reposilite Memory Usage", + "type": "timeseries" + } + ], + "refresh": "30s", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "datasource": { "type": "prometheus", "uid": "prometheus" }, + "definition": "label_values(jetty_requests_total, namespace)", + "hide": 0, + "includeAll": false, + "label": "Namespace", + "multi": false, + "name": "namespace", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(jetty_requests_total, namespace)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { "from": "now-3h", "to": "now" }, + "timeRangeUpdatedDuringEditOrView": false, + "timepicker": {}, + "timezone": "browser", + "title": "Reposilite Maven Proxy", + "uid": "reposilite-dash", + "version": 1, + "weekStart": "" + } diff --git a/charts/theia-monitoring/values.yaml b/charts/theia-monitoring/values.yaml index f8287c6..bfd0bf2 100644 --- a/charts/theia-monitoring/values.yaml +++ b/charts/theia-monitoring/values.yaml @@ -22,4 +22,3 @@ sessionNamespaces: - test1 - test2 - test3 - diff --git a/deployments/test2.theia-test.artemis.cit.tum.de/values.yaml b/deployments/test2.theia-test.artemis.cit.tum.de/values.yaml index 1e9218a..1226e56 100644 --- a/deployments/test2.theia-test.artemis.cit.tum.de/values.yaml +++ b/deployments/test2.theia-test.artemis.cit.tum.de/values.yaml @@ -10,6 +10,39 @@ theia-certificates: hosts: configuration: *hostsConfig +eduide-shared-cache: + + +enabled: true + +auth: + enabled: true + reader: + username: "reader" + password: "changeme-reader" + writer: + username: "writer" + password: "changeme-writer" + +cache: + maxEntrySizeMB: 100 + verifyCASHash: true + +tls: + enabled: true + secretName: cache-internal-cert-secret + +resources: + requests: + memory: "256Mi" + cpu: "100m" + limits: + memory: "1Gi" + cpu: "500m" + + enabled: true + + theia-cloud: app: id: nJV3nKZmpxTD4wu2 @@ -48,6 +81,14 @@ theia-cloud: replicas: 1 sessionsPerUser: 10 storageClassName: csi-rbd-sc + buildCache: + enabled: true + push: true + url: "https://theia-cloud-combined-cache:8080/cache/" + secretName: "" + dependencyCache: + enabled: false + url: "http://theia-cloud-combined-reposilite:8080/releases/" # service: # image: ghcr.io/eduide/eduide-cloud/service:latest @@ -81,13 +122,18 @@ theia-cloud: landingPage: # We use the try now page as landing page since the default does not support multiple apps -> https://github.com/eclipsesource/theia-cloud/discussions/301 - image: ghcr.io/eduide/eduidec-landing-page + image: ghcr.io/eduide/eduidec-landing-page:pr-14 # We can define a default blueprint appDefinition: "java-17-latest" ephemeralStorage: true additionalApps: java-17-latest: label: Java 17 + buildSystems: + - id: gradle + label: Gradle + - id: maven + label: Maven c-latest: label: C javascript-latest: diff --git a/docs/adding-environments.md b/docs/adding-environments.md index 4fcb98c..798ca28 100644 --- a/docs/adding-environments.md +++ b/docs/adding-environments.md @@ -93,6 +93,10 @@ issuer: Typically no changes needed for this file. +### 1.4 Internal TLS + +The internal TLS infrastructure (internal CA + trust bundle) is deployed once per cluster via `charts/theia-internal-tls`. The trust bundle ConfigMap (`theia-internal-trust`) is automatically distributed to all namespaces, so no additional configuration is needed when adding a new environment. + ## Step 2: Create GitHub Environment ### 2.1 Create the Environment diff --git a/value-reference-files/theia-cloud-helm-values.yml b/value-reference-files/theia-cloud-helm-values.yml index b1f5dcc..374c261 100644 --- a/value-reference-files/theia-cloud-helm-values.yml +++ b/value-reference-files/theia-cloud-helm-values.yml @@ -31,11 +31,16 @@ monitor: interval: 3 operator: - image: theiacloud/theia-cloud-operator:1.1.0-next + image: ghcr.io/ls1intum/theia/operator:pr-41 eagerStart: false replicas: 1 sessionsPerUser: 10 storageClassName: csi-rbd-sc + enableBuildCaching: false + buildCacheUrl: "" + enableBuildCachePush: false + enableDependencyCaching: false + dependencyCacheUrl: "" service: adminApiTokenSecret: