feat(tracktor): add Tracktor with its own volume and pocket-id login #288

Merged
grachevko merged 1 commit from feat/tracktor into main 2026-09-29 17:25:44 +00:00
Collaborator

What was wrong

The car logbook of the house is LubeLogger, and the owner wants Tracktor instead: the cluster has no
place for it. Nothing is migrated — the instance starts on an empty volume, LubeLogger stays where it
is, and the two run side by side until the records are moved by hand. The project warns in its own
README that it is under active development and not stable for production; that is said here so this
PR is not read as a promise of a stable service. Overlooked details: the application has no OIDC of
its own (a local user database with sessions), and it has no server database at all (SQLite).

What this fixes

  • kubernetes/apps/tracktor/{namespace.yaml,kustomization.yaml} — a namespace of its own
    (prune: disabled: the namespace outlives an application directory removed from git) plus the
    sops component as in every other namespace. There is no database Kustomization: the project
    keeps every record in SQLite, so the CNPG cluster of LubeLogger, Mealie or Tandoor has no
    counterpart here.
  • tracktor/ks.yaml — the application Kustomization: postBuild substitution of
    ${SECRET_DOMAIN}, wait with a health check on the HelmRelease, and dependsOn on
    tracktor-config (the pod reads the client Secret the operator creates from the CR there; the
    generators of the application are pulled in behind that Kustomization).
  • tracktor/app/helmrelease.yaml — app-template (the project publishes no chart of its own), image
    ghcr.io/javedh-dev/tracktor:2.1.0@sha256:edb43955…66292138:
    • the image starts as root (Dockerfile sets no USER), but the only uid it defines is 1000 — the
      node account of node:22-alpine — and every path the process writes lies under /data
      (DB_PATH, UPLOADS_DIR, LOG_DIR are set by the image itself), so the pod runs as 1000 with
      readOnlyRootFilesystem.
    • APP_SECRET from a Secret born in a generator of ESO: without a value the application refuses to
      store or read the credentials of a notification provider (requireAppSecret in
      src/server/services/crypto.service.ts of the tag), and the reminders are part of what the
      instance is installed for — the key is therefore created with the deployment, not on the day the
      first provider is configured.
    • HTTP_MODE: https (the session cookie gets the secure flag under TLS) and CORS_ORIGINS set
      to the one origin of the instance instead of the default * (getCorsOrigin in
      src/server/middlewares/cors.ts).
    • probes: httpGet /api/health as readiness and as liveness. The path is the one the middleware
      leaves without a session (BYPASS_PATHS in src/server/middlewares/auth.ts) and it is served by
      a static handler, while every request still awaits the initialization of the database
      (handleInit in src/hooks.server.ts runs the migrations) — a passing probe also says that the
      migrations ran and the volume is writable. The neighbouring applications carry no liveness
      because their /health answers from the database; this one touches no database once the
      initialization is done, and the single replica has nothing to take over a hung process.
    • BODY_SIZE_LIMIT stays Infinity as in the image, and the memory limit is what actually caps an
      upload: adapter-node collects the request body in memory (get_raw_body in @sveltejs/kit), not
      in a file.
    • the claim is mounted at /data, /tmp is an emptyDir (the root filesystem is read-only).
  • tracktor/app/pvc.yaml — 10Gi on proxmox-local-zfs: one volume for the database, the uploaded
    photographs and documents and the logs of the application, a separate object so that it survives
    the recreation of the release.
  • tracktor/app/httproute.yaml — tracktor.${SECRET_DOMAIN} through the envoy-internal gateway:
    the wildcard SAN of the certificate of the gateway already covers the name.
  • tracktor/app/backend.yaml, tracktor/app/securitypolicy.yaml, tracktor/config/**,
    tracktor/secrets/** — the login: OIDC at the gateway through pocket-id (a Backend sso of this
    namespace pointing at the provider in-cluster, and a SecurityPolicy on the route), the client CR
    the operator turns into the Secret tracktor-oidc-client, and two values born in generators of ESO
    (CreatedOnce, immutable, Orphan): the client secret and APP_SECRET. Tracktor has no OIDC,
    so its own username/password login stays as the emergency door behind the policy.
  • vpa/** — the object for the recommender, updateMode: "Off" as in the other namespaces.
  • homepage/homepage/app/configmap.yaml — the entry of the new service in the dashboard.

Verified

  • flate test all -p ./kubernetes/flux/cluster — 222 passed, including Kustomization tracktor/{tracktor,tracktor-config,tracktor-secrets,tracktor-vpa} and HelmRelease tracktor/tracktor; flate build ks renders the namespace directory, and the new Kustomization
    appears in the output with its path and its dependsOn.
  • The values of the HelmRelease against values.schema.json of app-template 5.2.1 (the chart the
    OCIRepository points at, layer digest sha256:1cf49aeb…): zero violations.
  • A full render of the chart with these values (helm template, v4.3.0): ServiceAccount, Service
    and Deployment are all named tracktor, so the backendRef of the HTTPRoute and the targetRef
    of the VPA point at objects that really appear; the pod mounts the claim at /data and an
    emptyDir at /tmp, and the environment, the probes and the security context are what the
    manifest declares.
  • The SecurityPolicy against the CRD of the INSTALLED Envoy Gateway
    (gateway.envoyproxy.io_securitypolicies.yaml of the gateway-helm chart 1.9.2, the tag of our
    OCIRepository): zero violations. clientIDRef/clientSecret expect the keys client-id and
    client-secret in that Secret, which is exactly what the client CR renames them to.
  • The PocketIDOIDCClient against the CRD of the installed operator (chart 0.14.3): zero violations;
    its callback address equals redirectURL of the policy to the letter.
  • The Backend against the CRD of the same chart: zero violations.
  • The facts about the image are read from the registry and not from memory: the config blob of
    ghcr.io/javedh-dev/tracktor:2.1.0 (no USER, WorkingDir /app, CMD node build, the three
    paths under /data, RUNTIME=docker) and its build history (docker-entrypoint.sh belongs to
    node:22-alpine, uid 1000 is its node account). The tag is pinned by the index digest
    sha256:edb43955… of that manifest.
  • The facts about the application are read from the sources of tag 2.1.0: the environment variables
    and their defaults (docs/environment.md), the initialization and the migrations
    (src/server/db/init.ts with handleInit), the open path and the session guard, CORS, the refusal
    without APP_SECRET, the upload route writing into UPLOADS_DIR, and the body handling of the
    adapter.
  • tracktor.grachevko.ru answers NXDOMAIN today, while the neighbouring internal names
    (lubelogger, vikunja) resolve to 192.168.40.11: the k8s-gateway answers the names that
    exist in the cluster, so the record is not a step of this PR — the check in the section below is
    what confirms it.

After the merge

  1. Flux creates the namespace and the release; the first visit passes pocket-id, and the instance
    then shows its registration page while no user exists (docs/authentication.md) — the account
    created there is also the emergency door behind the policy.
  2. Check the name: tracktor.grachevko.ru answers with 192.168.40.11, the address of the internal
    gateway. If it stays unknown, the record is a step of its own (the neighbouring internal names
    carry one).
  3. The websockets of the UI behind the OIDC filter: nothing in the sources suggests them, but this is
    the first thing a policy like that can break silently.
  4. LubeLogger is not touched by this PR: it keeps serving under its own name.

Rollback

  • The whole PR: git revert — the namespace, the volume and the secrets are pruned with it; once
    records live on the volume, take a copy of it first (the revert deletes the PVC).
  • If the login does not come up, remove the SecurityPolicy: the route keeps serving the local login
    of the application. A mismatch between the callback address of the client CR and the redirectURL
    of the policy is the other candidate — the provider refuses an address it does not know.
## What was wrong The car logbook of the house is LubeLogger, and the owner wants Tracktor instead: the cluster has no place for it. Nothing is migrated — the instance starts on an empty volume, LubeLogger stays where it is, and the two run side by side until the records are moved by hand. The project warns in its own README that it is under active development and not stable for production; that is said here so this PR is not read as a promise of a stable service. Overlooked details: the application has no OIDC of its own (a local user database with sessions), and it has no server database at all (SQLite). ## What this fixes - `kubernetes/apps/tracktor/{namespace.yaml,kustomization.yaml}` — a namespace of its own (`prune: disabled`: the namespace outlives an application directory removed from git) plus the `sops` component as in every other namespace. There is no database Kustomization: the project keeps every record in SQLite, so the CNPG cluster of LubeLogger, Mealie or Tandoor has no counterpart here. - `tracktor/ks.yaml` — the application Kustomization: `postBuild` substitution of `${SECRET_DOMAIN}`, `wait` with a health check on the HelmRelease, and `dependsOn` on `tracktor-config` (the pod reads the client Secret the operator creates from the CR there; the generators of the application are pulled in behind that Kustomization). - `tracktor/app/helmrelease.yaml` — `app-template` (the project publishes no chart of its own), image `ghcr.io/javedh-dev/tracktor:2.1.0@sha256:edb43955…66292138`: - the image starts as root (`Dockerfile` sets no `USER`), but the only uid it defines is 1000 — the `node` account of `node:22-alpine` — and every path the process writes lies under `/data` (`DB_PATH`, `UPLOADS_DIR`, `LOG_DIR` are set by the image itself), so the pod runs as 1000 with `readOnlyRootFilesystem`. - `APP_SECRET` from a Secret born in a generator of ESO: without a value the application refuses to store or read the credentials of a notification provider (`requireAppSecret` in `src/server/services/crypto.service.ts` of the tag), and the reminders are part of what the instance is installed for — the key is therefore created with the deployment, not on the day the first provider is configured. - `HTTP_MODE: https` (the session cookie gets the `secure` flag under TLS) and `CORS_ORIGINS` set to the one origin of the instance instead of the default `*` (`getCorsOrigin` in `src/server/middlewares/cors.ts`). - probes: `httpGet /api/health` as readiness and as liveness. The path is the one the middleware leaves without a session (`BYPASS_PATHS` in `src/server/middlewares/auth.ts`) and it is served by a static handler, while every request still awaits the initialization of the database (`handleInit` in `src/hooks.server.ts` runs the migrations) — a passing probe also says that the migrations ran and the volume is writable. The neighbouring applications carry no liveness because their `/health` answers from the database; this one touches no database once the initialization is done, and the single replica has nothing to take over a hung process. - `BODY_SIZE_LIMIT` stays `Infinity` as in the image, and the memory limit is what actually caps an upload: adapter-node collects the request body in memory (`get_raw_body` in `@sveltejs/kit`), not in a file. - the claim is mounted at `/data`, `/tmp` is an `emptyDir` (the root filesystem is read-only). - `tracktor/app/pvc.yaml` — 10Gi on `proxmox-local-zfs`: one volume for the database, the uploaded photographs and documents and the logs of the application, a separate object so that it survives the recreation of the release. - `tracktor/app/httproute.yaml` — `tracktor.${SECRET_DOMAIN}` through the `envoy-internal` gateway: the wildcard SAN of the certificate of the gateway already covers the name. - `tracktor/app/backend.yaml`, `tracktor/app/securitypolicy.yaml`, `tracktor/config/**`, `tracktor/secrets/**` — the login: OIDC at the gateway through pocket-id (a `Backend` `sso` of this namespace pointing at the provider in-cluster, and a `SecurityPolicy` on the route), the client CR the operator turns into the Secret `tracktor-oidc-client`, and two values born in generators of ESO (`CreatedOnce`, `immutable`, `Orphan`): the client secret and `APP_SECRET`. Tracktor has no OIDC, so its own username/password login stays as the emergency door behind the policy. - `vpa/**` — the object for the recommender, `updateMode: "Off"` as in the other namespaces. - `homepage/homepage/app/configmap.yaml` — the entry of the new service in the dashboard. ## Verified - `flate test all -p ./kubernetes/flux/cluster` — `222 passed`, including `Kustomization tracktor/{tracktor,tracktor-config,tracktor-secrets,tracktor-vpa}` and `HelmRelease tracktor/tracktor`; `flate build ks` renders the namespace directory, and the new Kustomization appears in the output with its path and its `dependsOn`. - The values of the HelmRelease against `values.schema.json` of `app-template` 5.2.1 (the chart the OCIRepository points at, layer digest `sha256:1cf49aeb…`): zero violations. - A full render of the chart with these values (`helm template`, v4.3.0): `ServiceAccount`, `Service` and `Deployment` are all named `tracktor`, so the `backendRef` of the HTTPRoute and the `targetRef` of the VPA point at objects that really appear; the pod mounts the claim at `/data` and an `emptyDir` at `/tmp`, and the environment, the probes and the security context are what the manifest declares. - The `SecurityPolicy` against the CRD of the INSTALLED Envoy Gateway (`gateway.envoyproxy.io_securitypolicies.yaml` of the `gateway-helm` chart 1.9.2, the tag of our OCIRepository): zero violations. `clientIDRef`/`clientSecret` expect the keys `client-id` and `client-secret` in that Secret, which is exactly what the client CR renames them to. - The `PocketIDOIDCClient` against the CRD of the installed operator (chart 0.14.3): zero violations; its callback address equals `redirectURL` of the policy to the letter. - The `Backend` against the CRD of the same chart: zero violations. - The facts about the image are read from the registry and not from memory: the config blob of `ghcr.io/javedh-dev/tracktor:2.1.0` (no `USER`, `WorkingDir /app`, `CMD node build`, the three paths under `/data`, `RUNTIME=docker`) and its build history (`docker-entrypoint.sh` belongs to `node:22-alpine`, uid 1000 is its `node` account). The tag is pinned by the index digest `sha256:edb43955…` of that manifest. - The facts about the application are read from the sources of tag 2.1.0: the environment variables and their defaults (`docs/environment.md`), the initialization and the migrations (`src/server/db/init.ts` with `handleInit`), the open path and the session guard, CORS, the refusal without `APP_SECRET`, the upload route writing into `UPLOADS_DIR`, and the body handling of the adapter. - `tracktor.grachevko.ru` answers NXDOMAIN today, while the neighbouring internal names (`lubelogger`, `vikunja`) resolve to `192.168.40.11`: the `k8s-gateway` answers the names that exist in the cluster, so the record is not a step of this PR — the check in the section below is what confirms it. ## After the merge 1. Flux creates the namespace and the release; the first visit passes pocket-id, and the instance then shows its registration page while no user exists (`docs/authentication.md`) — the account created there is also the emergency door behind the policy. 2. Check the name: `tracktor.grachevko.ru` answers with `192.168.40.11`, the address of the internal gateway. If it stays unknown, the record is a step of its own (the neighbouring internal names carry one). 3. The websockets of the UI behind the OIDC filter: nothing in the sources suggests them, but this is the first thing a policy like that can break silently. 4. LubeLogger is not touched by this PR: it keeps serving under its own name. ## Rollback - The whole PR: `git revert` — the namespace, the volume and the secrets are pruned with it; once records live on the volume, take a copy of it first (the revert deletes the PVC). - If the login does not come up, remove the `SecurityPolicy`: the route keeps serving the local login of the application. A mismatch between the callback address of the client CR and the `redirectURL` of the policy is the other candidate — the provider refuses an address it does not know.
feat(tracktor): add Tracktor with its own volume and pocket-id login
All checks were successful
Flate / Flate - Filter (pull_request) Successful in 4s
Flux Local / Flux Local - Test (pull_request) Successful in 57s
Flate / Flate (pull_request) Successful in 44s
Flate / Flate - Success (pull_request) Successful in 5s
Flux Local / Flux Local - Diff (pull_request) Successful in 2m5s
Flux Local / Flux Local - Success (pull_request) Successful in 3s
5d37f8b5e3
## What was wrong
The car logbook of the house is LubeLogger, and the owner wants Tracktor instead: the cluster has no
place for it. Nothing is migrated — the instance starts on an empty volume, LubeLogger stays where it
is, and the two run side by side until the records are moved by hand. The project warns in its own
README that it is under active development and not stable for production; that is said here so this
PR is not read as a promise of a stable service. Overlooked details: the application has no OIDC of
its own (a local user database with sessions), and it has no server database at all (SQLite).

## What this fixes
- `kubernetes/apps/tracktor/{namespace.yaml,kustomization.yaml}` — a namespace of its own
  (`prune: disabled`: the namespace outlives an application directory removed from git) plus the
  `sops` component as in every other namespace. There is no database Kustomization: the project
  keeps every record in SQLite, so the CNPG cluster of LubeLogger, Mealie or Tandoor has no
  counterpart here.
- `tracktor/ks.yaml` — the application Kustomization: `postBuild` substitution of
  `${SECRET_DOMAIN}`, `wait` with a health check on the HelmRelease, and `dependsOn` on
  `tracktor-config` (the pod reads the client Secret the operator creates from the CR there; the
  generators of the application are pulled in behind that Kustomization).
- `tracktor/app/helmrelease.yaml` — `app-template` (the project publishes no chart of its own), image
  `ghcr.io/javedh-dev/tracktor:2.1.0@sha256:edb43955…66292138`:
  - the image starts as root (`Dockerfile` sets no `USER`), but the only uid it defines is 1000 — the
    `node` account of `node:22-alpine` — and every path the process writes lies under `/data`
    (`DB_PATH`, `UPLOADS_DIR`, `LOG_DIR` are set by the image itself), so the pod runs as 1000 with
    `readOnlyRootFilesystem`.
  - `APP_SECRET` from a Secret born in a generator of ESO: without a value the application refuses to
    store or read the credentials of a notification provider (`requireAppSecret` in
    `src/server/services/crypto.service.ts` of the tag), and the reminders are part of what the
    instance is installed for — the key is therefore created with the deployment, not on the day the
    first provider is configured.
  - `HTTP_MODE: https` (the session cookie gets the `secure` flag under TLS) and `CORS_ORIGINS` set
    to the one origin of the instance instead of the default `*` (`getCorsOrigin` in
    `src/server/middlewares/cors.ts`).
  - probes: `httpGet /api/health` as readiness and as liveness. The path is the one the middleware
    leaves without a session (`BYPASS_PATHS` in `src/server/middlewares/auth.ts`) and it is served by
    a static handler, while every request still awaits the initialization of the database
    (`handleInit` in `src/hooks.server.ts` runs the migrations) — a passing probe also says that the
    migrations ran and the volume is writable. The neighbouring applications carry no liveness
    because their `/health` answers from the database; this one touches no database once the
    initialization is done, and the single replica has nothing to take over a hung process.
  - `BODY_SIZE_LIMIT` stays `Infinity` as in the image, and the memory limit is what actually caps an
    upload: adapter-node collects the request body in memory (`get_raw_body` in `@sveltejs/kit`), not
    in a file.
  - the claim is mounted at `/data`, `/tmp` is an `emptyDir` (the root filesystem is read-only).
- `tracktor/app/pvc.yaml` — 10Gi on `proxmox-local-zfs`: one volume for the database, the uploaded
  photographs and documents and the logs of the application, a separate object so that it survives
  the recreation of the release.
- `tracktor/app/httproute.yaml` — `tracktor.${SECRET_DOMAIN}` through the `envoy-internal` gateway:
  the wildcard SAN of the certificate of the gateway already covers the name.
- `tracktor/app/backend.yaml`, `tracktor/app/securitypolicy.yaml`, `tracktor/config/**`,
  `tracktor/secrets/**` — the login: OIDC at the gateway through pocket-id (a `Backend` `sso` of this
  namespace pointing at the provider in-cluster, and a `SecurityPolicy` on the route), the client CR
  the operator turns into the Secret `tracktor-oidc-client`, and two values born in generators of ESO
  (`CreatedOnce`, `immutable`, `Orphan`): the client secret and `APP_SECRET`. Tracktor has no OIDC,
  so its own username/password login stays as the emergency door behind the policy.
- `vpa/**` — the object for the recommender, `updateMode: "Off"` as in the other namespaces.
- `homepage/homepage/app/configmap.yaml` — the entry of the new service in the dashboard.

## Verified
- `flate test all -p ./kubernetes/flux/cluster` — `222 passed`, including `Kustomization
  tracktor/{tracktor,tracktor-config,tracktor-secrets,tracktor-vpa}` and `HelmRelease
  tracktor/tracktor`; `flate build ks` renders the namespace directory, and the new Kustomization
  appears in the output with its path and its `dependsOn`.
- The values of the HelmRelease against `values.schema.json` of `app-template` 5.2.1 (the chart the
  OCIRepository points at, layer digest `sha256:1cf49aeb…`): zero violations.
- A full render of the chart with these values (`helm template`, v4.3.0): `ServiceAccount`, `Service`
  and `Deployment` are all named `tracktor`, so the `backendRef` of the HTTPRoute and the `targetRef`
  of the VPA point at objects that really appear; the pod mounts the claim at `/data` and an
  `emptyDir` at `/tmp`, and the environment, the probes and the security context are what the
  manifest declares.
- The `SecurityPolicy` against the CRD of the INSTALLED Envoy Gateway
  (`gateway.envoyproxy.io_securitypolicies.yaml` of the `gateway-helm` chart 1.9.2, the tag of our
  OCIRepository): zero violations. `clientIDRef`/`clientSecret` expect the keys `client-id` and
  `client-secret` in that Secret, which is exactly what the client CR renames them to.
- The `PocketIDOIDCClient` against the CRD of the installed operator (chart 0.14.3): zero violations;
  its callback address equals `redirectURL` of the policy to the letter.
- The `Backend` against the CRD of the same chart: zero violations.
- The facts about the image are read from the registry and not from memory: the config blob of
  `ghcr.io/javedh-dev/tracktor:2.1.0` (no `USER`, `WorkingDir /app`, `CMD node build`, the three
  paths under `/data`, `RUNTIME=docker`) and its build history (`docker-entrypoint.sh` belongs to
  `node:22-alpine`, uid 1000 is its `node` account). The tag is pinned by the index digest
  `sha256:edb43955…` of that manifest.
- The facts about the application are read from the sources of tag 2.1.0: the environment variables
  and their defaults (`docs/environment.md`), the initialization and the migrations
  (`src/server/db/init.ts` with `handleInit`), the open path and the session guard, CORS, the refusal
  without `APP_SECRET`, the upload route writing into `UPLOADS_DIR`, and the body handling of the
  adapter.
- `tracktor.grachevko.ru` answers NXDOMAIN today, while the neighbouring internal names
  (`lubelogger`, `vikunja`) resolve to `192.168.40.11`: the `k8s-gateway` answers the names that
  exist in the cluster, so the record is not a step of this PR — the check in the section below is
  what confirms it.

## After the merge
1. Flux creates the namespace and the release; the first visit passes pocket-id, and the instance
   then shows its registration page while no user exists (`docs/authentication.md`) — the account
   created there is also the emergency door behind the policy.
2. Check the name: `tracktor.grachevko.ru` answers with `192.168.40.11`, the address of the internal
   gateway. If it stays unknown, the record is a step of its own (the neighbouring internal names
   carry one).
3. The websockets of the UI behind the OIDC filter: nothing in the sources suggests them, but this is
   the first thing a policy like that can break silently.
4. LubeLogger is not touched by this PR: it keeps serving under its own name.

## Rollback
- The whole PR: `git revert` — the namespace, the volume and the secrets are pruned with it; once
  records live on the volume, take a copy of it first (the revert deletes the PVC).
- If the login does not come up, remove the `SecurityPolicy`: the route keeps serving the local login
  of the application. A mismatch between the callback address of the client CR and the `redirectURL`
  of the policy is the other candidate — the provider refuses an address it does not know.

Rendered diff of the HelmReleases in this pull request:

--- HelmRelease: tracktor/tracktor ServiceAccount: tracktor/tracktor

+++ HelmRelease: tracktor/tracktor ServiceAccount: tracktor/tracktor

@@ -0,0 +1,11 @@

+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: tracktor
+  labels:
+    app.kubernetes.io/instance: tracktor
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: tracktor
+  namespace: tracktor
+
--- HelmRelease: tracktor/tracktor Service: tracktor/tracktor

+++ HelmRelease: tracktor/tracktor Service: tracktor/tracktor

@@ -0,0 +1,23 @@

+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: tracktor
+  labels:
+    app.kubernetes.io/instance: tracktor
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: tracktor
+    app.kubernetes.io/service: tracktor
+  namespace: tracktor
+spec:
+  type: ClusterIP
+  ports:
+  - port: 3000
+    targetPort: 3000
+    protocol: TCP
+    name: http
+  selector:
+    app.kubernetes.io/controller: tracktor
+    app.kubernetes.io/instance: tracktor
+    app.kubernetes.io/name: tracktor
+
--- HelmRelease: tracktor/tracktor Deployment: tracktor/tracktor

+++ HelmRelease: tracktor/tracktor Deployment: tracktor/tracktor

@@ -0,0 +1,102 @@

+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: tracktor
+  labels:
+    app.kubernetes.io/controller: tracktor
+    app.kubernetes.io/instance: tracktor
+    app.kubernetes.io/managed-by: Helm
+    app.kubernetes.io/name: tracktor
+  annotations:
+    reloader.stakater.com/auto: 'true'
+  namespace: tracktor
+spec:
+  revisionHistoryLimit: 3
+  replicas: 1
+  strategy:
+    type: Recreate
+  selector:
+    matchLabels:
+      app.kubernetes.io/controller: tracktor
+      app.kubernetes.io/name: tracktor
+      app.kubernetes.io/instance: tracktor
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/controller: tracktor
+        app.kubernetes.io/instance: tracktor
+        app.kubernetes.io/name: tracktor
+    spec:
+      enableServiceLinks: false
+      serviceAccountName: tracktor
+      automountServiceAccountToken: false
+      securityContext:
+        fsGroup: 1000
+        fsGroupChangePolicy: OnRootMismatch
+        runAsGroup: 1000
+        runAsNonRoot: true
+        runAsUser: 1000
+        seccompProfile:
+          type: RuntimeDefault
+      hostIPC: false
+      hostNetwork: false
+      hostPID: false
+      dnsPolicy: ClusterFirst
+      containers:
+      - env:
+        - name: APP_SECRET
+          valueFrom:
+            secretKeyRef:
+              key: app_secret
+              name: tracktor-app-secret
+        - name: CORS_ORIGINS
+          value: https://tracktor...PLACEHOLDER_SECRET_DOMAIN..
+        - name: HTTP_MODE
+          value: https
+        - name: TZ
+          value: Europe/Moscow
+        image: ghcr.io/javedh-dev/tracktor:2.1.0@sha256:edb439550243e0c2589daf2a72fc51805e69cbd27462fc979128a4bb66292138
+        livenessProbe:
+          failureThreshold: 3
+          httpGet:
+            path: /api/health
+            port: http
+          periodSeconds: 30
+        name: app
+        ports:
+        - containerPort: 3000
+          name: http
+          protocol: TCP
+        readinessProbe:
+          failureThreshold: 6
+          httpGet:
+            path: /api/health
+            port: http
+          initialDelaySeconds: 10
+          periodSeconds: 10
+          timeoutSeconds: 5
+        resources:
+          limits:
+            memory: 512Mi
+          requests:
+            cpu: 25m
+            memory: 128Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          capabilities:
+            drop:
+            - ALL
+          readOnlyRootFilesystem: true
+        volumeMounts:
+        - mountPath: /data
+          name: data
+        - mountPath: /tmp
+          name: tmp
+      volumes:
+      - name: data
+        persistentVolumeClaim:
+          claimName: tracktor
+      - emptyDir: {}
+        name: tmp
+
Rendered diff of the HelmReleases in this pull request: ```diff --- HelmRelease: tracktor/tracktor ServiceAccount: tracktor/tracktor +++ HelmRelease: tracktor/tracktor ServiceAccount: tracktor/tracktor @@ -0,0 +1,11 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tracktor + labels: + app.kubernetes.io/instance: tracktor + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: tracktor + namespace: tracktor + --- HelmRelease: tracktor/tracktor Service: tracktor/tracktor +++ HelmRelease: tracktor/tracktor Service: tracktor/tracktor @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: tracktor + labels: + app.kubernetes.io/instance: tracktor + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: tracktor + app.kubernetes.io/service: tracktor + namespace: tracktor +spec: + type: ClusterIP + ports: + - port: 3000 + targetPort: 3000 + protocol: TCP + name: http + selector: + app.kubernetes.io/controller: tracktor + app.kubernetes.io/instance: tracktor + app.kubernetes.io/name: tracktor + --- HelmRelease: tracktor/tracktor Deployment: tracktor/tracktor +++ HelmRelease: tracktor/tracktor Deployment: tracktor/tracktor @@ -0,0 +1,102 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: tracktor + labels: + app.kubernetes.io/controller: tracktor + app.kubernetes.io/instance: tracktor + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: tracktor + annotations: + reloader.stakater.com/auto: 'true' + namespace: tracktor +spec: + revisionHistoryLimit: 3 + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app.kubernetes.io/controller: tracktor + app.kubernetes.io/name: tracktor + app.kubernetes.io/instance: tracktor + template: + metadata: + labels: + app.kubernetes.io/controller: tracktor + app.kubernetes.io/instance: tracktor + app.kubernetes.io/name: tracktor + spec: + enableServiceLinks: false + serviceAccountName: tracktor + automountServiceAccountToken: false + securityContext: + fsGroup: 1000 + fsGroupChangePolicy: OnRootMismatch + runAsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault + hostIPC: false + hostNetwork: false + hostPID: false + dnsPolicy: ClusterFirst + containers: + - env: + - name: APP_SECRET + valueFrom: + secretKeyRef: + key: app_secret + name: tracktor-app-secret + - name: CORS_ORIGINS + value: https://tracktor...PLACEHOLDER_SECRET_DOMAIN.. + - name: HTTP_MODE + value: https + - name: TZ + value: Europe/Moscow + image: ghcr.io/javedh-dev/tracktor:2.1.0@sha256:edb439550243e0c2589daf2a72fc51805e69cbd27462fc979128a4bb66292138 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /api/health + port: http + periodSeconds: 30 + name: app + ports: + - containerPort: 3000 + name: http + protocol: TCP + readinessProbe: + failureThreshold: 6 + httpGet: + path: /api/health + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + resources: + limits: + memory: 512Mi + requests: + cpu: 25m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /data + name: data + - mountPath: /tmp + name: tmp + volumes: + - name: data + persistentVolumeClaim: + claimName: tracktor + - emptyDir: {} + name: tmp + ```
grachevko deleted branch feat/tracktor 2026-09-29 17:25:45 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
grachevko/home-ops!288
No description provided.