gitops: public-safe values, docs; remove legacy app/resources

- Sanitize placeholders, centralize values under gitops/values/
- Argo Application placeholder repoURL; env-example + observability.yaml
- Remove Swarm app/, resources/, install.sh; add root README

Made-with: Cursor
This commit is contained in:
timotheereausanofi
2026-03-20 12:25:01 +01:00
parent 3e5dfaa1cb
commit 5e120c4d74
87 changed files with 397 additions and 3263 deletions

View File

@@ -1,33 +1,89 @@
# OneLab GitOps (Argo CD)
This directory is the **declarative source** for OneLab on Kubernetes. Argo CD applies two **Helm-based sources** from Git (Argo invokes Helm internally; you do not run a separate Helm install workflow).
This directory is the **declarative source** for OneLab on Kubernetes. [Argo CD](https://argo-cd.readthedocs.io/) applies **two Helm-based sources** from Git (Argo invokes Helm; you do not use Helm CLI as the primary install path for the cluster).
Legacy Swarm install lives under [`app/`](../app/) (`docker-compose.yml`); this tree replaces `docker stack deploy` for k3s/Kubernetes.
This repository is **GitOps-only**: everything required to deploy OneLab on Kubernetes lives under **`gitops/`**.
## What gets deployed
| Helm release | Chart path | Namespace | Role |
|--------------|------------|-----------|------|
| `onelab` | [`charts/onelab`](charts/onelab) | `onelab` | Application workloads, Postgres, Redis, RabbitMQ, revproxy, ingress hooks |
| `onelab-obs` | [`observability/`](observability/) | `onelab` | Loki, Promtail, Grafana (logs) |
Both are wired by a single Argo CD [`Application`](argocd/application.yaml) using **`spec.sources`** (requires **Argo CD 2.6+**).
## Architecture
```mermaid
flowchart LR
subgraph git [Git repository]
V[gitops/values]
C[charts/onelab]
O[observability]
end
subgraph argo [Argo CD]
App[Application onelab]
end
subgraph cluster [Kubernetes cluster]
NS[namespace onelab]
end
V --> App
C --> App
O --> App
App --> NS
```
1. You commit changes under **`gitops/values/`** (and optionally edit `repoURL` / `targetRevision` in the Application).
2. Argo reconciles: Helm renders `onelab` + `onelab-obs` into namespace **`onelab`**.
3. Sync waves order StatefulSets and app Deployments (Postgres → Redis/Rabbit/config → apps).
## Layout
| Path | Purpose |
|------|---------|
| [`charts/onelab`](charts/onelab) | OneLab chart (StatefulSets, Deployments, Services, ConfigMaps, Secrets)**Argo source 1** |
| [`values/`](values/) | Environment values (e.g. [`values/k3s-example.yaml`](values/k3s-example.yaml)); reference from `helm.valueFiles` |
| [`charts/onelab`](charts/onelab) | OneLab Helm chart — **Argo source 1** |
| [`values/`](values/) | **Operator entry point**: [`values/env-example.yaml`](values/env-example.yaml), [`values/observability.yaml`](values/observability.yaml), templates — see [`values/README.md`](values/README.md) |
| [`observability/`](observability/) | Loki / Promtail / Grafana umbrella chart — **Argo source 2** (`releaseName: onelab-obs`) |
| [`argocd/application.yaml`](argocd/application.yaml) | `Application` manifest (`spec.sources`, namespace `onelab`) |
| [`argocd/jsonpatch-multisource.json`](argocd/jsonpatch-multisource.json) | One-time JSON patch if the live `Application` stuck on `spec.source` |
| [`argocd/application.yaml`](argocd/application.yaml) | `Application` manifest (`spec.sources`, destination namespace `onelab`) |
| [`argocd/jsonpatch-multisource.json`](argocd/jsonpatch-multisource.json) | One-time JSON patch if a live `Application` still has legacy `spec.source` only |
## Prerequisites
1. **Kubernetes** (e.g. k3s) with a default **StorageClass** for Postgres/Rabbit PVCs (e.g. `local-path`).
2. **Image pull** to `hub.andrewalliance.com` registry Secret + `imagePullSecrets` (see [`values/k3s-example.yaml`](values/k3s-example.yaml) and [Private registry credentials](#private-registry-credentials)).
3. **RabbitMQ TLS** Secret `onelab-rabbit-tls` (or `rabbitmq.tls.embed` in a private values file) — [RabbitMQ TLS](#rabbitmq-tls).
4. **Host paths** when using `persistence.mode: hostPath`: `/opt/onelab/data` and `/opt/onelab/logs` on nodes that run those pods, or use RWX storage for multi-node.
1. **Kubernetes** (e.g. k3s) with a default **StorageClass** for Postgres/Rabbit/Loki/Grafana PVCs (e.g. `local-path`).
2. **Container images** from `hub.andrewalliance.com` (or your mirror): registry credentials via Helm values or a pre-created `docker-registry` Secret — see [Private registry credentials](#private-registry-credentials).
3. **RabbitMQ TLS** before RabbitMQ starts: Kubernetes Secret `onelab-rabbit-tls`, or `rabbitmq.tls.embed` in private values — see [RabbitMQ TLS](#rabbitmq-tls).
4. **Host paths** when using `persistence.mode: hostPath`: `/opt/onelab/data` and `/opt/onelab/logs` on nodes that run those pods (aligned with Promtail in [`values/observability.yaml`](values/observability.yaml)), or use RWX storage for multi-node.
## Bootstrap (registry, Argo repo, TLS)
## Configuration (single place to edit)
### Private registry credentials
- **OneLab app / ingress / DB / tokens / registry**: [`values/env-example.yaml`](values/env-example.yaml) — copy patterns, replace **`REPLACE_*`** placeholders, or overlay a gitignored file; see [`values/secrets.example.yaml`](values/secrets.example.yaml) and [`values/README.md`](values/README.md).
- **Observability**: [`values/observability.yaml`](values/observability.yaml) — Grafana password (**`REPLACE_GRAFANA_ADMIN_PASSWORD`**), ingress host, Promtail log hostPath.
- **Argo Git coordinates**: [`argocd/application.yaml`](argocd/application.yaml) — set `repoURL`, `targetRevision`, and `helm.valueFiles` if you add e.g. `secrets.local.yaml`.
By default, `gitops/values/k3s-example.yaml` matches the Swarm installer (`app/playbooks/tasks/manage-images.yml`): user **`public`**, password **`Andrew01..Release`**, and the chart creates Secret **`hub-andrewalliance`** when `registry.createPullSecret: true`.
The chart default [`charts/onelab/values.yaml`](charts/onelab/values.yaml) holds non-secret structure and safe placeholders only; **do not rely on it for production secrets**.
To use other credentials, override `registry.username` / `registry.password` or create the secret manually:
## Bootstrap checklist
1. Fork or clone this repository and push it to a Git remote your cluster can reach.
2. Edit [`argocd/application.yaml`](argocd/application.yaml): **`repoURL`** → your remote, **`targetRevision`** → your branch/tag.
3. Edit [`values/env-example.yaml`](values/env-example.yaml): DNS hostnames, TLS secret names, cert-manager issuer, and all **`REPLACE_*`** values (or use a gitignored overlay).
4. Edit [`values/observability.yaml`](values/observability.yaml): Grafana host/password aligned with your DNS and TLS.
5. If the Git repo is **private**, register it in Argo CD (see below).
6. Ensure **RabbitMQ TLS** Secret exists (or use embedded TLS in private values).
7. Apply the Application:
```bash
kubectl apply -f gitops/argocd/application.yaml
```
8. In Argo UI or CLI, confirm sync to namespace **`onelab`** and fix any `ImagePullBackOff` / TLS issues using the sections below.
**Single controller:** Use **only** this Argo CD `Application` for `onelab` / `onelab-obs`. Do not manage the same namespace with a parallel **Helm CLI** release.
## Private registry credentials
Set `registry.username` / `registry.password` in values (prefer a **gitignored** file merged last), or create the Secret manually:
```bash
kubectl create secret docker-registry hub-andrewalliance -n onelab \
@@ -36,72 +92,50 @@ kubectl create secret docker-registry hub-andrewalliance -n onelab \
--docker-password='YOUR_PASSWORD'
```
…and set `registry.createPullSecret: false` plus `imagePullSecrets: [{ name: hub-andrewalliance }]`.
…then set `registry.createPullSecret: false` and keep `imagePullSecrets: [{ name: hub-andrewalliance }]` in values.
#### StatefulSet pods still get `401 Unauthorized` / `ImagePullBackOff` after enabling registry auth
### StatefulSet pods still get `401 Unauthorized` / `ImagePullBackOff` after enabling registry auth
If `db-0` / `rabbitmq-0` were created **before** `imagePullSecrets` existed, their **Pod** spec can still use anonymous pulls until they are recreated:
If `db-0` / `rabbitmq-0` were created **before** `imagePullSecrets` existed, delete those pods once so they pick up the new Pod spec:
```bash
kubectl delete pod -n onelab db-0 rabbitmq-0
```
The chart adds a pod-template checksum so after you change registry settings in Git and **Argo syncs**, workloads normally roll; a one-time delete is enough if pods were created before pull secrets existed.
## Argo CD private Git repository
### Argo CD private Git repository
If the Application shows `authentication required: Unauthorized`, register the repo in Argo CD (CLI or UI):
If the Application shows `authentication required: Unauthorized`, register the repo (use a deploy token or PAT with read access):
```bash
# Example; use a deploy token or PAT with repo read access
argocd repo add https://git.luneski.fr/luneski/onelab-k8s.git \
argocd repo add https://github.com/YOUR_ORG/YOUR_REPO.git \
--username git \
--password YOUR_TOKEN
```
Then apply the Application:
## RabbitMQ TLS
Secret **`onelab-rabbit-tls`** must exist in namespace **`onelab`** before RabbitMQ starts (keys: typically `tls.crt`, `tls.key`, and optionally chain). **PEM material is not shipped in this GitOps tree** — generate certs or use your PKI, then:
```bash
kubectl apply -f gitops/argocd/application.yaml
kubectl create secret tls onelab-rabbit-tls -n onelab \
--cert=path/to/fullchain.pem \
--key=path/to/key.pem
```
**Single controller:** Use **only** this Argo CD `Application` for `onelab` / `onelab-obs`. Do not manage the same namespace with a separate **Helm CLI** release.
Alternatively, set `rabbitmq.tls.embed: true` and supply `rabbitmq.tls.crt` / `rabbitmq.tls.key` / `rabbitmq.tls.fullchain` via a **private** values file (never commit real keys).
### RabbitMQ TLS
Secret `onelab-rabbit-tls` must exist before RabbitMQ starts (created once from `app/rabbit/ssl/` or your own PEMs).
### Argo CD version and observability stack
[`argocd/application.yaml`](argocd/application.yaml) uses **`spec.sources`** (two Helm charts in one Application). Use **Argo CD 2.6 or newer**.
If the `onelab` Application was created earlier with **`spec.source` only**, Argo will **not** show the observability resources until you remove `source` and set `sources` — see [Migrating `spec.source` → `spec.sources`](#migrating-specsource--specsources) below.
The second source installs Loki/Promtail/Grafana from [`observability/`](observability/) (`releaseName: onelab-obs`). Set a strong **`grafana.adminPassword`** in [`observability/values.yaml`](observability/values.yaml) before production — details in [Observability](#observability-loki--promtail--grafana).
## Deploy with Argo CD
1. Push this repo to a Git remote Argo CD can read.
2. Register the repo in Argo CD (CLI or UI) if it is private — [Argo CD private Git repository](#argo-cd-private-git-repository).
3. Edit [`argocd/application.yaml`](argocd/application.yaml): `repoURL`, `targetRevision`, and per-source `helm.valueFiles` if needed.
4. Apply the Application:
```bash
kubectl apply -f gitops/argocd/application.yaml
```
## Deploy with Argo CD (details)
**Requirements:** Argo CD **2.6+** (`spec.sources`).
Each entry under `spec.sources` has its own `helm.releaseName` and `helm.valueFiles` (paths are **relative to that sources `path`**):
- Source `gitops/charts/onelab` → e.g. `../../values/k3s-example.yaml`
- Source `gitops/observability` → e.g. `values.yaml`
Both targets deploy into namespace **`onelab`**. Sync waves order: Postgres → Redis/Rabbit/config → application workloads.
- Source `gitops/charts/onelab` → e.g. `../../values/env-example.yaml`, optionally `../../values/secrets.local.yaml`
- Source `gitops/observability` → e.g. `../../values/observability.yaml`
### Migrating `spec.source` → `spec.sources`
If the `onelab` `Application` was created earlier with **`spec.source` only**, a plain `kubectl apply` of the new file may **not** remove `spec.source`, and Argo will never reconcile the observability chart.
If the `onelab` `Application` was created earlier with **`spec.source` only**, a plain `kubectl apply` may **not** remove `spec.source`, and Argo will not reconcile the observability chart.
Check:
@@ -109,66 +143,41 @@ Check:
kubectl get application onelab -n argocd -o jsonpath='{.spec.source}{"\n"}{.spec.sources}{"\n"}'
```
If `source` is set and `sources` is empty, patch once (adjust `repoURL` in the patch file if needed):
If `source` is set and `sources` is empty, patch once (edit `repoURL` in the patch file to match your remote):
```bash
kubectl patch application onelab -n argocd --type json --patch-file gitops/argocd/jsonpatch-multisource.json
```
Then sync in Argo (or wait for auto-sync).
### Single controller
Manage these workloads **only** through this Argo CD `Application`. Do not drive the same resources with a parallel **Helm CLI** release.
### Logs / Grafana
See [Observability (Loki / Promtail / Grafana)](#observability-loki--promtail--grafana) — set a strong `grafana.adminPassword` in [`observability/values.yaml`](observability/values.yaml) before production.
## Observability (Loki / Promtail / Grafana)
The umbrella chart under [`observability/`](observability/) deploys:
- **Loki** — log storage (SingleBinary, filesystem PVC, 7-day retention by default).
- **Promtail** — DaemonSet: Kubernetes pod logs (`/var/log/pods`) plus **OneLab file logs** from the same host path the app chart uses (`/opt/onelab/logs` by default).
- **Grafana** — explore logs; datasource points at this releases Loki gateway.
It is synced by the **same** Argo CD Application as the OneLab chart ([`argocd/application.yaml`](argocd/application.yaml)): second `sources` entry, Argo **`helm.releaseName`** **`onelab-obs`** (so services are like `onelab-obs-loki-gateway`).
- **Loki** — log storage (SingleBinary, filesystem PVC; retention from [`values/observability.yaml`](values/observability.yaml)).
- **Promtail** — DaemonSet: Kubernetes pod logs plus **OneLab file logs** from the host path configured in [`values/observability.yaml`](values/observability.yaml) (keep in sync with OneLab `persistence.hostPath.logs`).
- **Grafana** — Explore; datasource points at this releases Loki gateway.
### First-time setup
1. **Change the Grafana admin password** in [`observability/values.yaml`](observability/values.yaml) (`grafana.adminPassword`) or switch to `admin.existingSecret` per the upstream Grafana chart.
2. **Align host paths** — if you change `persistence.hostPath.logs` for OneLab, update `promtail.extraVolumes` / `extraVolumeMounts` in the same `values.yaml` so Promtail still reads the shared log directory.
3. **Multi-node** — with `hostPath` logs, each node only sees its own files; Promtail runs on every node, so you still get coverage when pods move.
1. Set a strong **`grafana.adminPassword`** in [`values/observability.yaml`](values/observability.yaml) (or use `admin.existingSecret` per the upstream Grafana chart).
2. Align **Grafana ingress host** with `grafana.ini.server.domain` / `root_url` in the same file.
3. **Multi-node** — with `hostPath` logs, each node only sees its own files; Promtail runs on every node.
### OneLab-only ingestion
Promtail adds **`extraRelabelConfigs`** so the **kubernetes-pods** job **keeps only** pods in namespace **`onelab`**. Other namespaces no longer reach Loki (Explore only sees OneLab). Host file logs under `/opt/onelab/logs` are tagged with **`namespace: onelab`** and **`component: host-logs`** so they appear in the same queries.
Existing Loki data from before this change may still show non-`onelab` streams until **retention** drops them; for a clean index you would need to wipe the Loki PVC (destructive).
Promtail **`extraRelabelConfigs`** keep only pods in namespace **`onelab`**. Host file logs are tagged **`namespace: onelab`**, **`component: host-logs`**.
### Dashboard: **OneLab logs**
Grafanas **dashboard sidecar** loads ConfigMap **`…-dashboard-onelab-logs`** (JSON: `observability/dashboards/onelab-logs.json`). Open **Dashboards → OneLab logs** (`uid` `onelab-logs`):
- **Component** — multi-select from `label_values({namespace="onelab"}, component)` (includes **`host-logs`** for file logs).
- **Line filter** — regex applied to log line content (`.*` = all).
- Stat panels: total lines, heuristic **error** / **warning** counts (tuned for typical text logs, not strict JSON parsing).
Grafana sidecar loads the dashboard from `observability/dashboards/onelab-logs.json` (`uid` `onelab-logs`).
#### Grafana pod: `init-chown-data` CrashLoopBackOff
The upstream chart runs an init container as **root** to `chown` `/var/lib/grafana`. Clusters with **Pod Security Admission** (often on k3s) commonly block that. This repo sets **`grafana.initChownData.enabled: false`**; the Grafana pod keeps **`fsGroup: 472`** so the PVC is usually group-writable. If Grafana still cannot write to disk, delete the Grafana PVC once after the change or relax PSA for namespace `onelab`.
This repo sets **`grafana.initChownData.enabled: false`** with **`fsGroup: 472`** for Pod Securityfriendly clusters. If Grafana cannot write to the PVC, delete the Grafana PVC once after changing values or adjust Pod Security for namespace `onelab`.
### Access Grafana
An **Ingress** named **`grafana-onelab`** is created by the umbrella chart (`observability/templates/ingress-grafana-onelab.yaml`), Traefik + cert-manager, matching the OneLab web UI pattern in `gitops/values/k3s-example.yaml`:
- Host: **`grafana.k8s.selair.it`** — edit `grafanaOnelabIngress` and `grafana.ini.server` in `gitops/observability/values.yaml` together.
- TLS Secret: **`grafana-tls-k8s-selair`** (cert-manager with `letsencrypt-prod`).
Point DNS at your ingress, sync the app, then open `https://<grafana-host>/` (user `admin` until you change values).
For debugging without DNS:
Ingress **`grafana-onelab`** is defined in `observability/templates/ingress-grafana-onelab.yaml`. Defaults use example hosts in [`values/observability.yaml`](values/observability.yaml) (`grafana.onelab.example.com`); change to your DNS and TLS Secret name.
```bash
kubectl -n onelab port-forward svc/onelab-obs-grafana 3000:80
@@ -176,42 +185,39 @@ kubectl -n onelab port-forward svc/onelab-obs-grafana 3000:80
### Maintainers: vendored chart dependencies
The observability umbrella vendors upstream charts under `gitops/observability/charts/*.tgz` so **Argo CD** can render without relying on live Helm repo access at sync time.
When bumping Loki / Promtail / Grafana versions, from `gitops/observability/` run:
From `gitops/observability/`:
```bash
helm dependency update
```
Commit the updated `Chart.lock` and `charts/*.tgz` with your Git change. This is **repository packaging**, not an alternative install path — deploy still happens only via Argo CD.
### OneLab `logs.path`
The OneLab chart sets `onelab.logs.path: "/logs"` in the generated configuration so application file logs match the `/logs` volume mount (see Enterprise guide §7.2).
## kubectl / credentials
If `kubectl` reports *You must be logged in*, refresh your kubeconfig (e.g. k3s `/etc/rancher/k3s/k3s.yaml` on the server or your auth plugin) before applying manifests.
Commit updated `Chart.lock` and `charts/*.tgz` so Argo can render without live Helm repo access at sync time.
## Application configuration (`configurations.yml`)
You do not need to edit [`app/configurations.yml`](../app/configurations.yml) in Git for Kubernetes. The chart renders `configurations.yml` from [`charts/onelab/files/configurations.gotmpl`](charts/onelab/files/configurations.gotmpl) into Secret **`onelab-configurations`**.
For Kubernetes you do **not** need a separate `configurations.yml` in Git. The OneLab chart renders it from [`charts/onelab/files/configurations.gotmpl`](charts/onelab/files/configurations.gotmpl) into Secret **`onelab-configurations`**.
1. **Values (recommended)** — set `onelab.compliance`, `onelab.ldap`, etc. See [`values/instance-overrides.example.yaml`](values/instance-overrides.example.yaml). Add extra paths under **`spec.sources[].helm.valueFiles`** for the `gitops/charts/onelab` source (paths relative to `gitops/charts/onelab`).
1. **Values (recommended)** — set `onelab.compliance`, `onelab.ldap`, etc. See [`values/instance-overrides.example.yaml`](values/instance-overrides.example.yaml) and add paths under **`spec.sources[].helm.valueFiles`** for the `gitops/charts/onelab` source.
2. **Bring your own Secret** — set `configuration.existingSecretName`; the Secret must contain key **`configurations.yml`**.
LDAP TLS paths in values are container paths; mount PEMs on `ldap-worker` if required.
## Ingress (web UI)
Set `ingress.enabled`, `ingress.host`, and optional TLS in values. Traffic goes to Service **`revproxy`**. On k3s, `ingress.className: traefik` matches the default controller. For cert-manager, set `ingress.tls`, `ingress.tlsSecretName`, and `ingress.certManager.clusterIssuer`; DNS for `ingress.host` must resolve before ACME runs.
Set `ingress.enabled`, `ingress.host`, and optional TLS in [`values/env-example.yaml`](values/env-example.yaml). Traffic goes to Service **`revproxy`**. On k3s, `ingress.className: traefik` matches the default controller. For cert-manager, set `ingress.certManager.clusterIssuer` and TLS secret name; DNS for `ingress.host` must resolve before ACME completes.
## Security notes for public repositories
- Never commit real passwords, tokens, or TLS private keys. Use **`REPLACE_*`** in tracked files and a **`*.local.yaml`** overlay (ignored at repo root) for secrets.
- If this repo ever contained real credentials, **rotate** them after sanitizing Git history or publishing a clean fork.
## kubectl / credentials
If `kubectl` reports *You must be logged in*, refresh your kubeconfig before applying manifests.
## Developer note (local render)
Running **`helm template` on Windows** against some paths can return empty `.Files.Get` content; the OneLab chart uses `fromYaml (.Files.AsConfig)` where needed. **Argo CD runs on Linux** and renders the same charts in-cluster — this is a local-tooling caveat, not a second deploy path.
Running **`helm template` on Windows** against some paths can return empty `.Files.Get` content; the OneLab chart uses `fromYaml (.Files.AsConfig)` where needed. **Argo CD runs on Linux** and renders the same charts in-cluster.
## Not migrated in this chart
## Not covered by this chart
- **Edge proxy stack** (`app/proxy/docker-compose.yml`, host 80/443 Swarm) — use **Ingress** + `revproxy` and optional cert-manager.
- **Swarm-only secrets** (e.g. `ssl_passphrase`) — use Kubernetes Secrets or external operators.
- **Edge proxy** in front of the cluster — use **Ingress** + `revproxy` and optional cert-manager.
- **Non-Kubernetes** install paths — not included; use Kubernetes Secrets or external secret operators as needed.

View File

@@ -13,20 +13,20 @@ metadata:
spec:
project: default
sources:
- repoURL: https://git.luneski.fr/luneski/onelab-k8s.git
- repoURL: https://github.com/YOUR_ORG/YOUR_REPO.git
targetRevision: main
path: gitops/charts/onelab
helm:
releaseName: onelab
valueFiles:
- ../../values/k3s-example.yaml
- repoURL: https://git.luneski.fr/luneski/onelab-k8s.git
- ../../values/env-example.yaml
- repoURL: https://github.com/YOUR_ORG/YOUR_REPO.git
targetRevision: main
path: gitops/observability
helm:
releaseName: onelab-obs
valueFiles:
- values.yaml
- ../../values/observability.yaml
destination:
server: https://kubernetes.default.svc
namespace: onelab

View File

@@ -2,21 +2,21 @@
{"op": "remove", "path": "/spec/source"},
{"op": "add", "path": "/spec/sources", "value": [
{
"repoURL": "https://git.luneski.fr/luneski/onelab-k8s.git",
"repoURL": "https://github.com/YOUR_ORG/YOUR_REPO.git",
"targetRevision": "main",
"path": "gitops/charts/onelab",
"helm": {
"releaseName": "onelab",
"valueFiles": ["../../values/k3s-example.yaml"]
"valueFiles": ["../../values/env-example.yaml"]
}
},
{
"repoURL": "https://git.luneski.fr/luneski/onelab-k8s.git",
"repoURL": "https://github.com/YOUR_ORG/YOUR_REPO.git",
"targetRevision": "main",
"path": "gitops/observability",
"helm": {
"releaseName": "onelab-obs",
"valueFiles": ["values.yaml"]
"valueFiles": ["../../values/observability.yaml"]
}
}
]}

View File

@@ -23,13 +23,13 @@ images:
imagePullSecrets: []
# - name: hub-andrewalliance
# Same defaults as app/playbooks/tasks/manage-images.yml (docker login before pull).
# Override registry credentials in gitops/values/ (see gitops/values/secrets.example.yaml).
registry:
createPullSecret: false
pullSecretName: hub-andrewalliance
server: hub.andrewalliance.com
username: public
password: Andrew01..Release
password: "REPLACE_REGISTRY_PASSWORD"
# hostPath: matches typical single-node Swarm-style install (shared /data and /logs).
# Use persistence.mode: pvc + a ReadWriteMany class for multi-node shared storage.
@@ -71,12 +71,12 @@ syncWaves:
onelab:
domain: "https://localhost"
mailer:
noreply: "no-reply@andrewalliance.com"
noreply: "no-reply@example.com"
secrets:
authTokenKey: "TokenAuthPlaceholder"
monitoringToken: "TokenMonitoringPlaceholder"
rabbitToken: "TokenRabbitPlaceholder"
# Mirrors app/configurations.yml params.compliance (enable without editing app/).
# Mirrors legacy OneLab configurations.yml params.compliance (templated from charts/onelab/files/configurations.gotmpl).
compliance:
enabled: false
requireElectronicSignature: true
@@ -97,8 +97,8 @@ onelab:
tlsCiphers: ""
tlsSslVersion: ""
intercom:
appid: "zxvgsagz"
secret: "QUw2jEV8utIpe9DeYjOqBjhBY9VxjXddKUCISUNu"
appid: "REPLACE_INTERCOM_APP_ID"
secret: "REPLACE_INTERCOM_SECRET"
features:
# Deprecated for LDAP: prefer onelab.ldap.enabled (either enables ldap-worker + ldap.enabled in config).

View File

@@ -1,149 +1,3 @@
# Umbrella chart: Loki (SingleBinary + filesystem) + Promtail + Grafana.
# Keep hostPath below in sync with persistence.hostPath.logs in gitops/values/k3s-example.yaml.
loki:
deploymentMode: SingleBinary
loki:
auth_enabled: false
commonConfig:
replication_factor: 1
storage:
type: filesystem
schemaConfig:
configs:
- from: "2024-04-01"
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
retention_period: 168h
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
singleBinary:
replicas: 1
persistence:
enabled: true
size: 10Gi
backend:
replicas: 0
read:
replicas: 0
write:
replicas: 0
ingester:
replicas: 0
querier:
replicas: 0
queryFrontend:
replicas: 0
queryScheduler:
replicas: 0
distributor:
replicas: 0
compactor:
replicas: 0
indexGateway:
replicas: 0
bloomCompactor:
replicas: 0
bloomGateway:
replicas: 0
ruler:
replicas: 0
minio:
enabled: false
lokiCanary:
enabled: false
test:
enabled: false
chunksCache:
enabled: false
resultsCache:
enabled: false
promtail:
config:
clients:
- url: http://{{ .Release.Name }}-loki-gateway.{{ .Release.Namespace }}.svc.cluster.local/loki/api/v1/push
snippets:
# Only ingest pod logs from namespace onelab (Explore / Loki stay focused on OneLab).
extraRelabelConfigs:
- action: keep
source_labels:
- __meta_kubernetes_namespace
regex: onelab
extraScrapeConfigs: |
- job_name: onelab-host-log-files
static_configs:
- targets:
- localhost
labels:
job: onelab-files
namespace: onelab
component: host-logs
__path__: /onelab-host-logs/**/*
extraVolumes:
- name: onelab-host-logs
hostPath:
path: /opt/onelab/logs
type: DirectoryOrCreate
extraVolumeMounts:
- name: onelab-host-logs
mountPath: /onelab-host-logs
readOnly: true
# Named Ingress grafana-onelab (templates/ingress-grafana-onelab.yaml). Grafana subchart ingress is disabled.
grafanaOnelabIngress:
enabled: true
className: traefik
host: grafana.k8s.selair.it
tls: true
tlsSecretName: grafana-tls-k8s-selair
clusterIssuer: letsencrypt-prod
servicePort: 80
annotations: {}
grafana:
adminUser: admin
adminPassword: changeme
# Root+CHOWN init breaks under Pod Security / restricted policies (k3s). fsGroup:472 on the pod is enough for most PVCs.
initChownData:
enabled: false
# Load dashboards from ConfigMaps labeled grafana_dashboard (see templates/configmap-dashboard-onelab-logs.yaml).
sidecar:
dashboards:
enabled: true
label: grafana_dashboard
folder: /tmp/dashboards
provider:
foldersFromFilesStructure: false
allowUiUpdates: true
datasources:
enabled: false
persistence:
enabled: true
size: 2Gi
service:
type: ClusterIP
# Required when served behind Ingress (redirects, OAuth callbacks).
grafana.ini:
server:
domain: grafana.k8s.selair.it
root_url: https://grafana.k8s.selair.it/
ingress:
enabled: false
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Loki
type: loki
uid: loki
url: http://{{ .Release.Name }}-loki-gateway.{{ .Release.Namespace }}.svc.cluster.local
access: proxy
isDefault: true
jsonData:
maxLines: 1000
# Operator-facing overrides live in gitops/values/observability.yaml (see gitops/argocd/application.yaml helm.valueFiles).
# This file is kept minimal on purpose.
{}

31
gitops/values/README.md Normal file
View File

@@ -0,0 +1,31 @@
# GitOps values (operator entry point)
All environment-specific Helm input for the Argo CD `Application` should live here (plus `repoURL` / `targetRevision` in [`../argocd/application.yaml`](../argocd/application.yaml)).
## Files
| File | Purpose |
|------|---------|
| [`env-example.yaml`](env-example.yaml) | Tracked example for OneLab chart: ingress, persistence, registry pull secret wiring, **placeholder** secrets. Fork and edit hostnames/TLS names, then replace placeholders or overlay `secrets.local.yaml`. |
| [`observability.yaml`](observability.yaml) | Loki / Promtail / Grafana: retention, Promtail host paths, Grafana ingress host, **placeholder** admin password. Edit hosts/TLS together with `grafana.ini.server`. |
| [`secrets.example.yaml`](secrets.example.yaml) | Template of secret-shaped keys only — copy to `*.local.yaml` (gitignored) and reference from Argo. |
| [`instance-overrides.example.yaml`](instance-overrides.example.yaml) | Optional features (compliance, LDAP) — merge or add as another value file. |
## Argo `helm.valueFiles` (path rules)
Paths are **relative to each sources `path`** in the Application:
- Source `gitops/charts/onelab` → e.g. `../../values/env-example.yaml`, then optionally `../../values/secrets.local.yaml`.
- Source `gitops/observability` → e.g. `../../values/observability.yaml`, then optionally `../../values/observability.local.yaml`.
Later files in the list **override** earlier ones.
## Private secrets without committing them
1. Copy `secrets.example.yaml` to `secrets.local.yaml` (ignored by `*.local.yaml` at repo root).
2. Fill in real registry password, Postgres password, app tokens, Intercom, etc.
3. Add `- ../../values/secrets.local.yaml` under the onelab sources `helm.valueFiles` in your **local** Application manifest or a private overlay — or keep that change only on a private branch.
For Grafana, set `grafana.adminPassword` in a gitignored file merged with [`observability.yaml`](observability.yaml), or edit `observability.yaml` in a private fork.
See the full bootstrap narrative in [`../README.md`](../README.md).

View File

@@ -0,0 +1,48 @@
# Example environment overrides — copy patterns to a gitignored file (e.g. secrets.local.yaml)
# and add it to Argo helm.valueFiles after this file so secrets stay out of Git.
# See gitops/values/README.md and gitops/values/secrets.example.yaml.
registry:
createPullSecret: true
pullSecretName: hub-andrewalliance
server: hub.andrewalliance.com
username: public
password: "REPLACE_REGISTRY_PASSWORD"
imagePullSecrets:
- name: hub-andrewalliance
persistence:
mode: hostPath
hostPath:
data: /opt/onelab/data
logs: /opt/onelab/logs
postgresql:
auth:
password: "REPLACE_POSTGRES_PASSWORD"
onelab:
domain: "https://onelab.example.com"
secrets:
authTokenKey: "REPLACE_AUTH_TOKEN_KEY"
monitoringToken: "REPLACE_MONITORING_TOKEN"
rabbitToken: "REPLACE_RABBIT_TOKEN"
intercom:
appid: "REPLACE_INTERCOM_APP_ID"
secret: "REPLACE_INTERCOM_SECRET"
revproxy:
serviceType: ClusterIP
ingress:
enabled: true
className: traefik
host: onelab.example.com
path: /
pathType: Prefix
tls: true
tlsSecretName: onelab-tls
certManager:
clusterIssuer: letsencrypt-prod
annotations: {}

View File

@@ -1,9 +1,10 @@
# Copy to a private file (e.g. gitops/values/private-k3s.yaml, gitignored) or merge into gitops/values/k3s-example.yaml.
# Copy to a private file (e.g. gitops/values/overrides.local.yaml, gitignored) or merge into gitops/values/env-example.yaml.
#
# Argo CD: under spec.sources, for the source with path gitops/charts/onelab, add another path to helm.valueFiles
# (paths are relative to that chart directory), e.g.:
# - ../../values/k3s-example.yaml
# - ../../values/private-k3s.yaml
# - ../../values/env-example.yaml
# - ../../values/secrets.local.yaml
# - ../../values/overrides.local.yaml
onelab:
compliance:

View File

@@ -1,51 +0,0 @@
# Aligned with Swarm installer defaults:
# - Registry: app/playbooks/tasks/manage-images.yml (user public, password Andrew01..Release)
# - App config sample: app/configurations.yml (placeholders + intercom block)
registry:
createPullSecret: true
pullSecretName: hub-andrewalliance
server: hub.andrewalliance.com
username: public
password: Andrew01..Release
imagePullSecrets:
- name: hub-andrewalliance
persistence:
mode: hostPath
hostPath:
data: /opt/onelab/data
logs: /opt/onelab/logs
postgresql:
auth:
password: "DBPasswordPlaceholder"
onelab:
# Public URL (must match ingress host + scheme).
domain: "https://onelab.k8s.selair.it"
secrets:
authTokenKey: "TokenAuthPlaceholder"
monitoringToken: "TokenMonitoringPlaceholder"
rabbitToken: "TokenRabbitPlaceholder"
intercom:
appid: "zxvgsagz"
secret: "QUw2jEV8utIpe9DeYjOqBjhBY9VxjXddKUCISUNu"
# ClusterIP keeps traffic via Ingress only; use NodePort instead if you need direct node:port access.
revproxy:
serviceType: ClusterIP
ingress:
enabled: true
className: traefik
host: onelab.k8s.selair.it
path: /
pathType: Prefix
tls: true
# cert-manager writes the certificate into this Secret in the release namespace
tlsSecretName: onelab-tls-k8s-selair
certManager:
clusterIssuer: letsencrypt-prod
annotations: {}

View File

@@ -0,0 +1,144 @@
# Umbrella chart: Loki (SingleBinary + filesystem) + Promtail + Grafana.
# Keep promtail hostPath below in sync with persistence.hostPath.logs in gitops/values/env-example.yaml.
loki:
deploymentMode: SingleBinary
loki:
auth_enabled: false
commonConfig:
replication_factor: 1
storage:
type: filesystem
schemaConfig:
configs:
- from: "2024-04-01"
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: loki_index_
period: 24h
limits_config:
retention_period: 168h
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
singleBinary:
replicas: 1
persistence:
enabled: true
size: 10Gi
backend:
replicas: 0
read:
replicas: 0
write:
replicas: 0
ingester:
replicas: 0
querier:
replicas: 0
queryFrontend:
replicas: 0
queryScheduler:
replicas: 0
distributor:
replicas: 0
compactor:
replicas: 0
indexGateway:
replicas: 0
bloomCompactor:
replicas: 0
bloomGateway:
replicas: 0
ruler:
replicas: 0
minio:
enabled: false
lokiCanary:
enabled: false
test:
enabled: false
chunksCache:
enabled: false
resultsCache:
enabled: false
promtail:
config:
clients:
- url: http://{{ .Release.Name }}-loki-gateway.{{ .Release.Namespace }}.svc.cluster.local/loki/api/v1/push
snippets:
extraRelabelConfigs:
- action: keep
source_labels:
- __meta_kubernetes_namespace
regex: onelab
extraScrapeConfigs: |
- job_name: onelab-host-log-files
static_configs:
- targets:
- localhost
labels:
job: onelab-files
namespace: onelab
component: host-logs
__path__: /onelab-host-logs/**/*
extraVolumes:
- name: onelab-host-logs
hostPath:
path: /opt/onelab/logs
type: DirectoryOrCreate
extraVolumeMounts:
- name: onelab-host-logs
mountPath: /onelab-host-logs
readOnly: true
grafanaOnelabIngress:
enabled: true
className: traefik
host: grafana.onelab.example.com
tls: true
tlsSecretName: grafana-onelab-tls
clusterIssuer: letsencrypt-prod
servicePort: 80
annotations: {}
grafana:
adminUser: admin
adminPassword: "REPLACE_GRAFANA_ADMIN_PASSWORD"
initChownData:
enabled: false
sidecar:
dashboards:
enabled: true
label: grafana_dashboard
folder: /tmp/dashboards
provider:
foldersFromFilesStructure: false
allowUiUpdates: true
datasources:
enabled: false
persistence:
enabled: true
size: 2Gi
service:
type: ClusterIP
grafana.ini:
server:
domain: grafana.onelab.example.com
root_url: https://grafana.onelab.example.com/
ingress:
enabled: false
datasources:
datasources.yaml:
apiVersion: 1
datasources:
- name: Loki
type: loki
uid: loki
url: http://{{ .Release.Name }}-loki-gateway.{{ .Release.Namespace }}.svc.cluster.local
access: proxy
isDefault: true
jsonData:
maxLines: 1000

View File

@@ -0,0 +1,26 @@
# Copy to a gitignored file (e.g. gitops/values/secrets.local.yaml — match *.local.yaml in repo .gitignore).
# Add it as the LAST entry in spec.sources[].helm.valueFiles for the onelab chart so these values win.
#
# Do not commit real values.
registry:
username: public
password: "YOUR_REGISTRY_PASSWORD"
postgresql:
auth:
password: "YOUR_POSTGRES_PASSWORD"
onelab:
secrets:
authTokenKey: "YOUR_AUTH_TOKEN_KEY"
monitoringToken: "YOUR_MONITORING_TOKEN"
rabbitToken: "YOUR_RABBIT_TOKEN"
intercom:
appid: "YOUR_INTERCOM_APP_ID"
secret: "YOUR_INTERCOM_SECRET"
# Optional: Grafana admin password is normally set in gitops/values/observability.yaml;
# override there or add a second gitignored value file for the observability source.
# grafana:
# adminPassword: "YOUR_GRAFANA_PASSWORD"