From 812d676792987b704f0526cece2f73dc925539ac Mon Sep 17 00:00:00 2001 From: Nageshbansal <76246968+Nageshbansal@users.noreply.github.com> Date: Thu, 26 Mar 2026 23:51:57 +0530 Subject: [PATCH] feat: introduce signoz-standalone and fix systemdcasting (#80) #### Features - Add standalone Docker image (docs/standalone/): single container running all SigNoz components via systemd casting - Add SQLite metastore support in systemd casting (enricher, signoz molding, forge, cast) - Add Restart=on-failure with RestartSec=5 to migrator, ingester, and signoz service templates to remove job readiness checks with `After`/`Wants`/`Requires` #### Fixes - Enable all services before starting any (fixes Unit not found during start) - Use --no-block for systemctl start (prevents cast from blocking on oneshot services) #### Refactors - Remove inter-service dependency coupling (After=/Requires=/Wants=) from all service templates; services manage their own readiness via restart policies and readiness checks - Move config material paths from configs// to // - Move IsEnabled() checks to forgeCasting dispatcher instead of individual forge methods - Simplify discoverAndPrepareServices and startAllService, remove service categorization map - Render environment variables (Spec.Env) and ClickHouse DSN in ingester, migrator, and telemetrystore templates Related: https://github.com/SigNoz/platform-pod/issues/1522 --- .versions/debian | 16 + docs/examples/docker/compose/README.md | 4 + docs/examples/ecs/ec2/terraform/README.md | 3 + docs/examples/kubernetes/helm/README.md | 6 + docs/examples/kubernetes/kustomize/README.md | 73 ++++ docs/examples/systemd/binary/README.md | 3 + .../examples/systemd/binary/casting.yaml.lock | 4 + .../{configs => }/ingester/ingester.yaml | 0 .../{configs => }/ingester/opamp.yaml | 0 .../pours/deployment/signoz-ingester.service | 8 +- .../pours/deployment/signoz-signoz.service | 3 +- ...gnoz-telemetrystore-clickhouse-0-0.service | 4 +- .../signoz-telemetrystore-migrator.service | 11 +- .../clickhousekeeper}/keeper-0.yaml | 0 .../clickhouse}/config.yaml | 0 .../clickhouse}/functions.yaml | 0 docs/standalone/Dockerfile.multi-arch | 74 ++++ docs/standalone/README.md | 86 +++++ docs/standalone/casting.yaml | 12 + docs/standalone/foundry-setup.service | 13 + internal/casting/systemdcasting/casting.go | 315 ++++++++---------- internal/casting/systemdcasting/enricher.go | 30 +- ...khouse.telemetrystore.v2556.service.gotmpl | 10 +- ...eeper.telemetrykeeper.v2556.service.gotmpl | 7 +- .../templates/ingester.service.gotmpl | 18 +- .../migrator.telemetrystore.service.gotmpl | 21 +- .../postgres.metastore.service.gotmpl | 8 +- .../templates/signoz.service.gotmpl | 14 +- internal/molding/signozmolding/signoz.go | 39 ++- 29 files changed, 531 insertions(+), 251 deletions(-) create mode 100644 .versions/debian rename docs/examples/systemd/binary/pours/deployment/{configs => }/ingester/ingester.yaml (100%) rename docs/examples/systemd/binary/pours/deployment/{configs => }/ingester/opamp.yaml (100%) rename docs/examples/systemd/binary/pours/deployment/{configs/telemetrykeeper => telemetrykeeper/clickhousekeeper}/keeper-0.yaml (100%) rename docs/examples/systemd/binary/pours/deployment/{configs/telemetrystore => telemetrystore/clickhouse}/config.yaml (100%) rename docs/examples/systemd/binary/pours/deployment/{configs/telemetrystore => telemetrystore/clickhouse}/functions.yaml (100%) create mode 100644 docs/standalone/Dockerfile.multi-arch create mode 100644 docs/standalone/README.md create mode 100644 docs/standalone/casting.yaml create mode 100644 docs/standalone/foundry-setup.service diff --git a/.versions/debian b/.versions/debian new file mode 100644 index 0000000..950f88a --- /dev/null +++ b/.versions/debian @@ -0,0 +1,16 @@ +#### Auto generated by make docker-version-debian. DO NOT EDIT! #### +amd64=8af0e5095f9964007f5ebd11191dfe52dcb51bf3afa2c07f055fc5451b78ba0e +unknown=aa26de2aeba103c4f2232de5efe83d2b4522c26fec20c5848c9f16f2aa244b3f +arm=159390659db54d341957fe78ef829de76e5549d0f9fcbb777287bcfc6f6da2f8 +unknown=83be97aab0d6eb03517006eea2cd7ecece54c20d3acbfe312d0ff4505dd4c344 +arm=0a52c3389a9a13dbeb3f3183578c15dfd712e17dad4feacbe55d224d0f459afa +unknown=728313602cf4214e7e5fd2ab88fa68f2f9a8e11118ec24b04f9f05e93fd443f0 +arm64=ee5473f786ff8a4e03409277c276b459b29afa55a84268bef55342c4f705b7ad +unknown=35e1cb927bb44a86ca8799cfe3d482a9e54e31a3995c28887c28bed9c0338bdd +386=02274f94f52336abd6ab4a8471ea09966613910ebaeed622429dc7b4b780e804 +unknown=3cc496e7c7df2b166481306e36070238a7644af6b230646688ca3c6f675995a2 +mips64le=b5bfd550af6266602aaef6c249baebf2c9835a2d0984013a23471cd8954503ff +ppc64le=8e69db6097e3efc0901fc84af17ea906710ae90b5842d919723eda3518ea6811 +unknown=d1dc187105900becbeca525ab9ef08efa3c71cdb4b8c67a2151e3aadc1f57a48 +s390x=a54db69bf6707382949f777f5fb8d0651d34a1b8602111a41eee7533e4ce07d8 +unknown=57ae880cf756c23f9afd4ef46b418eaae9232ea48f7c994b5c81215b58f226a7 diff --git a/docs/examples/docker/compose/README.md b/docs/examples/docker/compose/README.md index a59ee4a..4123fa2 100644 --- a/docs/examples/docker/compose/README.md +++ b/docs/examples/docker/compose/README.md @@ -77,6 +77,10 @@ docker compose -f pours/deployment/compose.yaml logs -f signoz cd pours/deployment && docker compose down ``` +> [!NOTE] +> - `foundryctl cast` detects whether `docker compose` (v2 plugin) or `docker-compose` (legacy standalone) is available and uses whichever it finds, preferring the v2 plugin. +> - The `metadata.name` is used as the Compose project name (`-p` flag). + ## Customization Override component images, replicas, or environment variables in the casting spec. For platform-level changes to the generated `compose.yaml` (memory limits, networks, volumes), use [patches](../../concepts/patches.md). diff --git a/docs/examples/ecs/ec2/terraform/README.md b/docs/examples/ecs/ec2/terraform/README.md index 7dc5392..8b1a3f1 100644 --- a/docs/examples/ecs/ec2/terraform/README.md +++ b/docs/examples/ecs/ec2/terraform/README.md @@ -57,6 +57,9 @@ Run the full pipeline (generate Terraform files and apply): foundryctl cast -f casting.yaml ``` +> [!NOTE] +> `foundryctl cast` runs `terraform init` followed by `terraform apply -auto-approve`. If you prefer to review the plan before applying, use the step-by-step approach below. + Step-by-step alternative: ```bash diff --git a/docs/examples/kubernetes/helm/README.md b/docs/examples/kubernetes/helm/README.md index 6241005..79a6c8d 100644 --- a/docs/examples/kubernetes/helm/README.md +++ b/docs/examples/kubernetes/helm/README.md @@ -40,10 +40,16 @@ Or step by step: # Generate values.yaml foundryctl forge -f casting.yaml +# Add the SigNoz Helm repo +helm repo add signoz https://charts.signoz.io + # Install with Helm helm install signoz signoz/signoz -f pours/deployment/values.yaml -n signoz --create-namespace ``` +> [!NOTE] +> `foundryctl cast` is idempotent. It detects whether a Helm release already exists and runs `helm upgrade` instead of `helm install` accordingly. + ## Generated output ```text diff --git a/docs/examples/kubernetes/kustomize/README.md b/docs/examples/kubernetes/kustomize/README.md index aaa0385..c0f41e2 100644 --- a/docs/examples/kubernetes/kustomize/README.md +++ b/docs/examples/kubernetes/kustomize/README.md @@ -39,10 +39,19 @@ Or step by step: # Generate manifests foundryctl forge -f casting.yaml +# Apply CRDs first (cast does this automatically) +kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/0.25.3/deploy/operatorhub/0.25.3/clickhouseinstallations.clickhouse.altinity.com.crd.yaml +kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/0.25.3/deploy/operatorhub/0.25.3/clickhouseinstallationtemplates.clickhouse.altinity.com.crd.yaml +kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/0.25.3/deploy/operatorhub/0.25.3/clickhouseoperatorconfigurations.clickhouse.altinity.com.crd.yaml +kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/0.25.3/deploy/operatorhub/0.25.3/clickhousekeeperinstallations.clickhouse-keeper.altinity.com.crd.yaml + # Apply with kubectl kubectl apply -k pours/deployment/ ``` +> [!NOTE] +> `foundryctl cast` automatically fetches and applies the four Altinity ClickHouse Operator CRDs (v0.25.3) from GitHub before running `kubectl apply -k`. If you apply manually, you must install the CRDs first or the ClickHouseInstallation and ClickHouseKeeperInstallation resources will fail to create. + ## Generated output ```text @@ -103,3 +112,67 @@ Open `http://localhost:8080` to access the SigNoz UI. ## Customization To set resource limits, storage classes, or scheduling constraints on the generated manifests, use [patches](../../concepts/patches.md). See the [kustomize-patches](../kustomize-patches/) example for a complete working configuration. + +### Native Kustomize patches + +Since Foundry generates standard Kustomize bases, you can also use native Kustomize patches on the generated `kustomization.yaml`. This lets you use strategic merge patches or overlays for environment-specific customization without re-forging. + +Use a Foundry patch to inject a `patches` block into the root `kustomization.yaml`: + +```yaml +apiVersion: v1alpha1 +metadata: + name: signoz +spec: + deployment: + flavor: kustomize + mode: kubernetes + patches: + - target: "deployment/kustomization.yaml" + operations: + - op: add + path: /patches + value: + - target: + kind: StatefulSet + name: signoz-signoz + patch: |- + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: signoz-signoz + spec: + template: + spec: + nodeSelector: + node-role.kubernetes.io/observability: "" +``` + +Or create an overlay directory that references the generated base: + +``` +my-deployment/ +├── base/ # Copy of pours/deployment/ +│ └── ... +└── overlays/ + └── prod/ + ├── kustomization.yaml + └── increase-resources.yaml +``` + +```yaml +# overlays/prod/kustomization.yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ../../base +patches: +- path: increase-resources.yaml + target: + kind: StatefulSet + name: signoz-clickhouse +``` + +```bash +kubectl apply -k overlays/prod/ +``` diff --git a/docs/examples/systemd/binary/README.md b/docs/examples/systemd/binary/README.md index ace383d..98795e3 100644 --- a/docs/examples/systemd/binary/README.md +++ b/docs/examples/systemd/binary/README.md @@ -45,6 +45,9 @@ Run the full pipeline (validate prerequisites, generate files, install and start sudo foundryctl cast -f casting.yaml ``` +> [!NOTE] +> `foundryctl cast` requires `sudo` because it manages systemd services, creates system users, and writes to system directories. + Step-by-step alternative: ```bash diff --git a/docs/examples/systemd/binary/casting.yaml.lock b/docs/examples/systemd/binary/casting.yaml.lock index eb90ad2..8b2debd 100644 --- a/docs/examples/systemd/binary/casting.yaml.lock +++ b/docs/examples/systemd/binary/casting.yaml.lock @@ -142,6 +142,8 @@ spec: opamp.yaml: | server_endpoint: ws://localhost:4320/v1/opamp enabled: true + env: + SIGNOZ_OTEL_COLLECTOR_TIMEOUT: 10m image: signoz/signoz-otel-collector:latest version: latest status: @@ -276,6 +278,8 @@ spec: - signozclickhousemeter opamp.yaml: | server_endpoint: ws://localhost:4320/v1/opamp + env: + SIGNOZ_OTEL_COLLECTOR_TIMEOUT: 10m metastore: kind: postgres spec: diff --git a/docs/examples/systemd/binary/pours/deployment/configs/ingester/ingester.yaml b/docs/examples/systemd/binary/pours/deployment/ingester/ingester.yaml similarity index 100% rename from docs/examples/systemd/binary/pours/deployment/configs/ingester/ingester.yaml rename to docs/examples/systemd/binary/pours/deployment/ingester/ingester.yaml diff --git a/docs/examples/systemd/binary/pours/deployment/configs/ingester/opamp.yaml b/docs/examples/systemd/binary/pours/deployment/ingester/opamp.yaml similarity index 100% rename from docs/examples/systemd/binary/pours/deployment/configs/ingester/opamp.yaml rename to docs/examples/systemd/binary/pours/deployment/ingester/opamp.yaml diff --git a/docs/examples/systemd/binary/pours/deployment/signoz-ingester.service b/docs/examples/systemd/binary/pours/deployment/signoz-ingester.service index d4c482d..36617d4 100644 --- a/docs/examples/systemd/binary/pours/deployment/signoz-ingester.service +++ b/docs/examples/systemd/binary/pours/deployment/signoz-ingester.service @@ -2,15 +2,17 @@ WantedBy=multi-user.target [Service] -ExecStart=/opt/ingester/bin/signoz-otel-collector --config=%Y/configs/ingester/ingester.yaml --manager-config=%Y/configs/ingester/opamp.yaml --copy-path=/var/lib/ingester/ingester.yaml +Environment=SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://localhost:9000 +Environment=SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m +ExecStart=/opt/ingester/bin/signoz-otel-collector --config=%Y/ingester/ingester.yaml --manager-config=%Y/ingester/opamp.yaml --copy-path=/var/lib/ingester/ingester.yaml +ExecStartPre=/opt/ingester/bin/signoz-otel-collector migrate sync check Group=signoz KillMode=mixed Restart=on-failure +RestartSec=5 Type=simple User=signoz [Unit] -After=signoz-telemetrystore-clickhouse-0-0 signoz-telemetrystore-migrator Description=SigNoz OTel Collector Documentation=https://signoz.io/docs -Requires=signoz-telemetrystore-migrator diff --git a/docs/examples/systemd/binary/pours/deployment/signoz-signoz.service b/docs/examples/systemd/binary/pours/deployment/signoz-signoz.service index e7109e0..a326f2d 100644 --- a/docs/examples/systemd/binary/pours/deployment/signoz-signoz.service +++ b/docs/examples/systemd/binary/pours/deployment/signoz-signoz.service @@ -11,12 +11,11 @@ ExecStart=/opt/signoz/bin/signoz server Group=signoz KillMode=mixed Restart=on-failure +RestartSec=5 Type=simple User=signoz WorkingDirectory=/opt/signoz [Unit] -After=signoz-telemetrystore-clickhouse-0-0 signoz-metastore-postgres signoz-telemetrystore-migrator Description=SigNoz Documentation=https://signoz.io/docs -Requires=signoz-telemetrystore-migrator diff --git a/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-clickhouse-0-0.service b/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-clickhouse-0-0.service index c892e86..ebf677b 100644 --- a/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-clickhouse-0-0.service +++ b/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-clickhouse-0-0.service @@ -14,7 +14,7 @@ Type=simple User=clickhouse [Unit] -After=time-sync.target network-online.target signoz-telemetrykeeper-clickhousekeeper-0.service +After=time-sync.target network-online.target Description=ClickHouse Server (v25.5.6) Requires=network-online.target -Wants=time-sync.target signoz-telemetrykeeper-clickhousekeeper-0.service +Wants=time-sync.target diff --git a/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-migrator.service b/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-migrator.service index 55097c1..052f0df 100644 --- a/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-migrator.service +++ b/docs/examples/systemd/binary/pours/deployment/signoz-telemetrystore-migrator.service @@ -2,14 +2,17 @@ WantedBy=multi-user.target [Service] -ExecStart=/bin/bash -c '/opt/ingester/bin/signoz-otel-collector migrate bootstrap --clickhouse-dsn=tcp://localhost:9000 && /opt/ingester/bin/signoz-otel-collector migrate sync up --clickhouse-dsn=tcp://localhost:9000 && /opt/ingester/bin/signoz-otel-collector migrate async up --clickhouse-dsn=tcp://localhost:9000' +Environment=SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://localhost:9000 +Environment=SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m +ExecStart=/bin/bash -c '/opt/ingester/bin/signoz-otel-collector migrate bootstrap && /opt/ingester/bin/signoz-otel-collector migrate sync up && /opt/ingester/bin/signoz-otel-collector migrate async up' +ExecStartPre=/opt/ingester/bin/signoz-otel-collector migrate ready Group=signoz RemainAfterExit=yes +Restart=on-failure +RestartSec=5 Type=oneshot User=signoz [Unit] -After=signoz-telemetrystore-clickhouse-0-0 -Description=SigNoz Schema Migrator +Description=SigNoz TelemetryStore Migrator Documentation=https://signoz.io/docs -Requires=signoz-telemetrystore-clickhouse-0-0 diff --git a/docs/examples/systemd/binary/pours/deployment/configs/telemetrykeeper/keeper-0.yaml b/docs/examples/systemd/binary/pours/deployment/telemetrykeeper/clickhousekeeper/keeper-0.yaml similarity index 100% rename from docs/examples/systemd/binary/pours/deployment/configs/telemetrykeeper/keeper-0.yaml rename to docs/examples/systemd/binary/pours/deployment/telemetrykeeper/clickhousekeeper/keeper-0.yaml diff --git a/docs/examples/systemd/binary/pours/deployment/configs/telemetrystore/config.yaml b/docs/examples/systemd/binary/pours/deployment/telemetrystore/clickhouse/config.yaml similarity index 100% rename from docs/examples/systemd/binary/pours/deployment/configs/telemetrystore/config.yaml rename to docs/examples/systemd/binary/pours/deployment/telemetrystore/clickhouse/config.yaml diff --git a/docs/examples/systemd/binary/pours/deployment/configs/telemetrystore/functions.yaml b/docs/examples/systemd/binary/pours/deployment/telemetrystore/clickhouse/functions.yaml similarity index 100% rename from docs/examples/systemd/binary/pours/deployment/configs/telemetrystore/functions.yaml rename to docs/examples/systemd/binary/pours/deployment/telemetrystore/clickhouse/functions.yaml diff --git a/docs/standalone/Dockerfile.multi-arch b/docs/standalone/Dockerfile.multi-arch new file mode 100644 index 0000000..275ec81 --- /dev/null +++ b/docs/standalone/Dockerfile.multi-arch @@ -0,0 +1,74 @@ +ARG DEBIAN_SHA="pass-a-valid-docker-sha-otherwise-this-will-fail" + +FROM debian@sha256:${DEBIAN_SHA} +LABEL maintainer="signoz" + +ARG OS="linux" +ARG ARCH + +ARG SIGNOZ_VERSION=latest +ARG INGESTER_VERSION=latest +ARG FOUNDRY_VERSION=latest + +# Install systemd +RUN apt-get update && apt-get install -y --no-install-recommends \ + systemd \ + systemd-sysv \ + ca-certificates \ + curl \ + tar \ + gnupg && \ + rm -f /lib/systemd/system/multi-user.target.wants/* \ + /etc/systemd/system/*.wants/* \ + /lib/systemd/system/local-fs.target.wants/* \ + /lib/systemd/system/sockets.target.wants/*udev* \ + /lib/systemd/system/sockets.target.wants/*initctl* \ + /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \ + /lib/systemd/system/systemd-update-utmp* + +# SigNoz +RUN mkdir -p /opt/signoz && \ + curl -fsSL "https://github.com/SigNoz/signoz/releases/${SIGNOZ_VERSION}/download/signoz_${OS}_${ARCH}.tar.gz" | \ + tar -xz --strip-components=1 -C /opt/signoz && \ + chmod +x /opt/signoz/bin/signoz + +# OTel Collector (ingester) +RUN mkdir -p /opt/ingester && \ + curl -fsSL "https://github.com/SigNoz/signoz-otel-collector/releases/${INGESTER_VERSION}/download/signoz-otel-collector_${OS}_${ARCH}.tar.gz" | \ + tar -xz --strip-components=1 -C /opt/ingester && \ + chmod +x /opt/ingester/bin/signoz-otel-collector + +# Foundry +RUN mkdir -p /usr/local/bin && \ + curl -fsSL "https://github.com/SigNoz/foundry/releases/${FOUNDRY_VERSION}/download/foundry_${OS}_${ARCH}.tar.gz" | \ + tar -xz --strip-components=1 -C /tmp && \ + mv /tmp/bin/foundryctl /usr/local/bin/foundryctl && \ + chmod +x /usr/local/bin/foundryctl + + +# Install ClickHouse from apt repo +RUN curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | \ + gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg && \ + echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" \ + > /etc/apt/sources.list.d/clickhouse.list && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + clickhouse-server \ + clickhouse-client && \ + systemctl disable clickhouse-server || true + +RUN apt-get clean && rm -rf /var/lib/apt/lists/* + +RUN useradd -r -m -d /opt/signoz -s /bin/false signoz && \ + mkdir -p /var/lib/signoz /var/lib/ingester /etc/foundry /opt/signoz/web && \ + chown signoz:signoz /var/lib/signoz /var/lib/ingester /opt/signoz + +COPY docs/standalone/casting.yaml /etc/foundry/casting.yaml +COPY docs/standalone/foundry-setup.service /etc/systemd/system/foundry-setup.service +RUN mkdir -p /var/lib/foundry && systemctl enable foundry-setup.service + +EXPOSE 8080 4317 4318 +VOLUME ["/var/lib/clickhouse", "/var/lib/signoz"] + +STOPSIGNAL SIGRTMIN+3 +CMD ["/sbin/init"] diff --git a/docs/standalone/README.md b/docs/standalone/README.md new file mode 100644 index 0000000..46f9ac3 --- /dev/null +++ b/docs/standalone/README.md @@ -0,0 +1,86 @@ +# Standalone Docker Image + +| | | +| --- | --- | +| **Casting** | `systemd` / `binary` | +| **Use Case** | Single Docker image for quick testing, development, and CI | + +## Overview + +An OpenTelemetry-native observability backend in a single Docker image. The standalone image bundles all SigNoz components into one container for development, demo, and testing environments. + +**Included components:** + +- **SigNoz** - query engine and UI +- **OpenTelemetry Collector** - telemetry ingestion +- **ClickHouse** - telemetry storage +- **SQLite** - metadata storage +- **[Foundry](https://github.com/SigNoz/foundry)** - deployment orchestration via `foundryctl` + +Applications can send telemetry using OpenTelemetry's standard defaults (OTLP gRPC/HTTP) without additional configuration. On first boot, Foundry generates all service configs and starts components via systemd. + +## Prerequisites + +- Docker Engine 20.10+ + +## Deploy + +```bash +docker run -d --name signoz --privileged \ + -p 8080:8080 \ + -p 4317:4317 \ + -p 4318:4318 \ + signoz/signoz-standalone:latest +``` + +Access SigNoz UI at `http://localhost:8080`. + +Send telemetry to: + +- OTLP gRPC: `localhost:4317` +- OTLP HTTP: `localhost:4318` + +## Customization + +To customize the deployment, mount your own `casting.yaml` into the container: + +```bash +docker run -d --name signoz --privileged \ + -p 8080:8080 \ + -p 4317:4317 \ + -p 4318:4318 \ + -v ./casting.yaml:/etc/foundry/casting.yaml \ + signoz/signoz-standalone:latest +``` + +See the default [casting.yaml](casting.yaml) for the full config structure. + +## Persist Data + +```bash +docker run -d --name signoz --privileged \ + -p 8080:8080 \ + -p 4317:4317 \ + -p 4318:4318 \ + -v signoz-clickhouse:/var/lib/clickhouse \ + -v signoz-data:/var/lib/signoz \ + signoz/signoz-standalone:latest +``` + +## After deployment + +```bash +# View logs for all services +docker exec signoz journalctl -f + +# View logs for a specific service +docker exec signoz journalctl -u signoz-signoz.service -f +docker exec signoz journalctl -u signoz-ingester.service -f +docker exec signoz journalctl -u signoz-telemetrystore-clickhouse-0-0.service -f +``` + +## Limitations + +- Requires `--privileged` flag (systemd needs cgroup access) +- `docker logs` is empty - use `journalctl` inside the container +- Single-node only (no clustering) diff --git a/docs/standalone/casting.yaml b/docs/standalone/casting.yaml new file mode 100644 index 0000000..69ba1f9 --- /dev/null +++ b/docs/standalone/casting.yaml @@ -0,0 +1,12 @@ +apiVersion: v1alpha1 +metadata: + name: signoz + annotations: + foundry.signoz.io/signoz-binary-path: /opt/signoz/bin/signoz + foundry.signoz.io/ingester-binary-path: /opt/ingester/bin/signoz-otel-collector +spec: + deployment: + flavor: binary + mode: systemd + metastore: + kind: sqlite diff --git a/docs/standalone/foundry-setup.service b/docs/standalone/foundry-setup.service new file mode 100644 index 0000000..1cab795 --- /dev/null +++ b/docs/standalone/foundry-setup.service @@ -0,0 +1,13 @@ +[Unit] +Description=Foundry Setup - SigNoz Standalone +After=multi-user.target +ConditionPathExists=!/var/lib/foundry/.initialized + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/foundryctl cast -f /etc/foundry/casting.yaml -p /etc/foundry/pours --no-gauge +ExecStartPost=/bin/touch /var/lib/foundry/.initialized + +[Install] +WantedBy=multi-user.target diff --git a/internal/casting/systemdcasting/casting.go b/internal/casting/systemdcasting/casting.go index e522238..9e9dee7 100644 --- a/internal/casting/systemdcasting/casting.go +++ b/internal/casting/systemdcasting/casting.go @@ -22,10 +22,6 @@ import ( const svcSuffix = ".service" -const ( - serviceStartTimeout = 2 * time.Minute -) - var _ rootcasting.Casting = (*systemdCasting)(nil) type systemdCasting struct { @@ -54,7 +50,7 @@ func (c *systemdCasting) Enricher(ctx context.Context, config *v1alpha1.Casting) func (c *systemdCasting) Forge(ctx context.Context, cfg v1alpha1.Casting, poursPath string) ([]types.Material, error) { var materials []types.Material for _, tmpl := range c.castings { - m, err := c.forgeCasting(tmpl, &cfg, poursPath) + m, err := c.forgeCasting(tmpl, &cfg) if err != nil { return nil, fmt.Errorf("failed to forge: %w", err) } @@ -70,11 +66,11 @@ func (c *systemdCasting) Cast(ctx context.Context, config v1alpha1.Casting, pour defer cancel() // Discover and prepare services - serviceMap, err := c.discoverAndPrepareServices(runctx, poursPath) + services, err := c.discoverAndPrepareServices(runctx, poursPath) if err != nil { return err } - if serviceMap == nil { + if len(services) == 0 { c.logger.WarnContext(runctx, "No service files found in pours directory") return nil } @@ -85,13 +81,21 @@ func (c *systemdCasting) Cast(ctx context.Context, config v1alpha1.Casting, pour } if config.Spec.MetaStore.Spec.IsEnabled() { - if err := c.initializePostgres(ctx, &config); err != nil { - return err + switch config.Spec.MetaStore.Kind { + case v1alpha1.MetaStoreKindPostgres: + if err := c.initializePostgres(ctx, &config); err != nil { + return err + } + case v1alpha1.MetaStoreKindSQLite: + if err := os.MkdirAll("/var/lib/signoz", 0755); err != nil { + return fmt.Errorf("failed to create sqlite data directory: %w", err) + } + _ = c.execCommand(ctx, "chown", "-R", "signoz:signoz", "/var/lib/signoz") } } // Start all services - systemd dependencies handle ordering - if err := c.startAllServices(runctx, serviceMap); err != nil { + if err := c.startAllServices(runctx, services); err != nil { return err } @@ -99,115 +103,113 @@ func (c *systemdCasting) Cast(ctx context.Context, config v1alpha1.Casting, pour return nil } -func (c *systemdCasting) forgeCasting(tmpl *types.Template, cfg *v1alpha1.Casting, poursPath string) ([]types.Material, error) { +func (c *systemdCasting) forgeCasting(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { switch tmpl { case signozServiceTemplate: + if !cfg.Spec.Signoz.Spec.IsEnabled() { + return nil, nil + } return c.forgeSignoz(tmpl, cfg) case metaStoreServiceTemplate: - return c.forgeMetaStore(tmpl, cfg, poursPath) + if !cfg.Spec.MetaStore.Spec.IsEnabled() { + return nil, nil + } + return c.forgeMetaStore(tmpl, cfg) case ingesterServiceTemplate: - return c.forgeIngester(tmpl, cfg, poursPath) + if !cfg.Spec.Ingester.Spec.IsEnabled() { + return nil, nil + } + return c.forgeIngester(tmpl, cfg) case telemetryStoreServiceTemplate: - return c.forgeTelemetryStore(tmpl, cfg, poursPath) + if !cfg.Spec.TelemetryStore.Spec.IsEnabled() { + return nil, nil + } + return c.forgeTelemetryStore(tmpl, cfg) case telemetryKeeperServiceTemplate: - return c.forgeTelemetryKeeper(tmpl, cfg, poursPath) + if !cfg.Spec.TelemetryKeeper.Spec.IsEnabled() { + return nil, nil + } + return c.forgeTelemetryKeeper(tmpl, cfg) case telemetryStoreMigratorServiceTemplate: + if !cfg.Spec.TelemetryStore.Spec.IsEnabled() { + return nil, nil + } return c.forgeMigrator(tmpl, cfg) default: return nil, nil } } -// --- Forge Handlers --- - -func (c *systemdCasting) forgeIngester(tmpl *types.Template, cfg *v1alpha1.Casting, poursPath string) ([]types.Material, error) { +func (c *systemdCasting) forgeIngester(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { spec := &cfg.Spec.Ingester - if !spec.Spec.IsEnabled() { - return nil, nil - } - if spec.Status.Config.Data == nil { - return nil, fmt.Errorf("no config molded for %s", v1alpha1.MoldingKindIngester) - } - // Initialize status extras if spec.Status.Extras == nil { spec.Status.Extras = make(map[string]string) } - - // Create config materials - mats, err := c.configMaterials(spec.Status.Config.Data, "ingester") - if err != nil { - return nil, err - } - - // Set extras for template - spec.Status.Extras["cfgPath"] = "configs/ingester/ingester.yaml" - spec.Status.Extras["cfgOpampPath"] = "configs/ingester/opamp.yaml" + spec.Status.Extras["cfgPath"] = filepath.Join("ingester", "ingester.yaml") + spec.Status.Extras["cfgOpampPath"] = filepath.Join("ingester", "opamp.yaml") spec.Status.Extras["workingDir"] = "/opt/ingester" - // Create service material + var materials []types.Material + svcMat, err := c.renderTemplate(tmpl, cfg, cfg.Metadata.Name+"-ingester"+svcSuffix) if err != nil { return nil, err } - return append(mats, svcMat), nil + materials = append(materials, svcMat) + + cfgMats, err := c.configMaterials(spec.Spec.Config.Data, "ingester", "") + if err != nil { + return nil, err + } + materials = append(materials, cfgMats...) + + return materials, nil } func (c *systemdCasting) forgeSignoz(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { spec := &cfg.Spec.Signoz - if !spec.Spec.IsEnabled() { - return nil, nil - } - // Initialize status maps if spec.Status.Extras == nil { spec.Status.Extras = make(map[string]string) } - - // Create env material - prefix := cfg.Metadata.Name + "-signoz" - spec.Status.Extras["workingDir"] = "/opt/signoz" - // Create service material - svcMat, err := c.renderTemplate(tmpl, cfg, prefix+svcSuffix) + var materials []types.Material + + svcMat, err := c.renderTemplate(tmpl, cfg, cfg.Metadata.Name+"-signoz"+svcSuffix) if err != nil { return nil, err } - return []types.Material{svcMat}, nil + materials = append(materials, svcMat) + + return materials, nil } -func (c *systemdCasting) forgeMetaStore(tmpl *types.Template, cfg *v1alpha1.Casting, poursPath string) ([]types.Material, error) { +func (c *systemdCasting) forgeMetaStore(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { spec := &cfg.Spec.MetaStore - if !spec.Spec.IsEnabled() { - return nil, nil - } - // Initialize status extras if spec.Status.Extras == nil { spec.Status.Extras = make(map[string]string) } - // Create env material - prefix := fmt.Sprintf("%s-metastore-%s", cfg.Metadata.Name, spec.Kind.String()) - // Create service material - svcMat, err := c.renderTemplate(tmpl, cfg, prefix+svcSuffix) - if err != nil { - return nil, err + var materials []types.Material + + switch spec.Kind { + case v1alpha1.MetaStoreKindPostgres: + svcMat, err := c.renderTemplate(tmpl, cfg, fmt.Sprintf("%s-metastore-%s%s", cfg.Metadata.Name, spec.Kind.String(), svcSuffix)) + if err != nil { + return nil, err + } + materials = append(materials, svcMat) } - return []types.Material{svcMat}, nil + + return materials, nil } -func (c *systemdCasting) forgeTelemetryStore(tmpl *types.Template, cfg *v1alpha1.Casting, poursPath string) ([]types.Material, error) { +func (c *systemdCasting) forgeTelemetryStore(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { spec := &cfg.Spec.TelemetryStore - if !spec.Spec.IsEnabled() { - return nil, nil - } - if spec.Status.Config.Data == nil { - return nil, fmt.Errorf("no config molded for %s", v1alpha1.MoldingKindTelemetryStore) - } - // Initialize status extras if spec.Status.Extras == nil { spec.Status.Extras = make(map[string]string) } @@ -216,36 +218,30 @@ func (c *systemdCasting) forgeTelemetryStore(tmpl *types.Template, cfg *v1alpha1 reps := max(1, *spec.Spec.Cluster.Replicas+1) shards := max(1, *spec.Spec.Cluster.Shards) - // Create config materials - mats, err := c.configMaterials(spec.Status.Config.Data, "telemetrystore") - if err != nil { - return nil, err - } + var materials []types.Material - // Create service materials for each shard/replica for s := range shards { for r := range reps { - svcName := fmt.Sprintf("%s-telemetrystore-%s-%d-%d%s", cfg.Metadata.Name, kind, s, r, svcSuffix) - svcMat, err := c.renderTemplate(tmpl, cfg, svcName) + svcMat, err := c.renderTemplate(tmpl, cfg, fmt.Sprintf("%s-telemetrystore-%s-%d-%d%s", cfg.Metadata.Name, kind, s, r, svcSuffix)) if err != nil { return nil, err } - mats = append(mats, svcMat) + materials = append(materials, svcMat) } } - return mats, nil + + cfgMats, err := c.configMaterials(spec.Spec.Config.Data, "telemetrystore", kind) + if err != nil { + return nil, err + } + materials = append(materials, cfgMats...) + + return materials, nil } -func (c *systemdCasting) forgeTelemetryKeeper(tmpl *types.Template, cfg *v1alpha1.Casting, poursPath string) ([]types.Material, error) { +func (c *systemdCasting) forgeTelemetryKeeper(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { spec := &cfg.Spec.TelemetryKeeper - if !spec.Spec.IsEnabled() { - return nil, nil - } - if spec.Status.Config.Data == nil { - return nil, fmt.Errorf("no config molded for %s", v1alpha1.MoldingKindTelemetryKeeper) - } - // Initialize status extras if spec.Status.Extras == nil { spec.Status.Extras = make(map[string]string) } @@ -253,42 +249,53 @@ func (c *systemdCasting) forgeTelemetryKeeper(tmpl *types.Template, cfg *v1alpha kind := spec.Kind.String() reps := max(1, *spec.Spec.Cluster.Replicas) - // Create config materials - mats, err := c.configMaterials(spec.Status.Config.Data, "telemetrykeeper") + // Config materials are created first because cfgPath extra is derived from them + cfgMats, err := c.configMaterials(spec.Spec.Config.Data, "telemetrykeeper", kind) if err != nil { return nil, err } + if len(cfgMats) > 0 { + spec.Status.Extras["cfgPath"] = filepath.Join("/etc/clickhouse-keeper/", filepath.Base(cfgMats[0].Path())) + } - // Set config path for template - spec.Status.Extras["cfgPath"] = filepath.Join("/etc/clickhouse-keeper/", filepath.Base(mats[0].Path())) + var materials []types.Material - // Create service materials for each replica for r := range reps { - svcName := fmt.Sprintf("%s-telemetrykeeper-%s-%d%s", cfg.Metadata.Name, kind, r, svcSuffix) - svcMat, err := c.renderTemplate(tmpl, cfg, svcName) + svcMat, err := c.renderTemplate(tmpl, cfg, fmt.Sprintf("%s-telemetrykeeper-%s-%d%s", cfg.Metadata.Name, kind, r, svcSuffix)) if err != nil { return nil, err } - mats = append(mats, svcMat) + materials = append(materials, svcMat) } - return mats, nil + + materials = append(materials, cfgMats...) + + return materials, nil } func (c *systemdCasting) forgeMigrator(tmpl *types.Template, cfg *v1alpha1.Casting) ([]types.Material, error) { - spec := &cfg.Spec.TelemetryStore - if !spec.Spec.IsEnabled() { - return nil, nil - } + var materials []types.Material - // Create service material svcMat, err := c.renderTemplate(tmpl, cfg, cfg.Metadata.Name+"-telemetrystore-migrator"+svcSuffix) if err != nil { return nil, err } - return []types.Material{svcMat}, nil + materials = append(materials, svcMat) + + return materials, nil } -// --- Material Helpers --- +func (c *systemdCasting) configMaterials(data map[string]string, component string, kind string) ([]types.Material, error) { + mats := make([]types.Material, 0, len(data)) + for filename, content := range data { + m, err := types.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, component, kind, filename)) + if err != nil { + return nil, fmt.Errorf("failed to create %s config material %s: %w", component, filename, err) + } + mats = append(mats, m) + } + return mats, nil +} func (c *systemdCasting) renderTemplate(tmpl *types.Template, cfg *v1alpha1.Casting, path string) (types.Material, error) { var buf bytes.Buffer @@ -298,18 +305,6 @@ func (c *systemdCasting) renderTemplate(tmpl *types.Template, cfg *v1alpha1.Cast return types.NewINIMaterial(buf.Bytes(), filepath.Join(rootcasting.DeploymentDir, path)) } -func (c *systemdCasting) configMaterials(data map[string]string, path string) ([]types.Material, error) { - mats := make([]types.Material, 0, len(data)) - for file, content := range data { - m, err := types.NewYAMLMaterial([]byte(content), filepath.Join(rootcasting.DeploymentDir, "configs/", path, file)) - if err != nil { - return nil, fmt.Errorf("failed to create config material %s: %w", file, err) - } - mats = append(mats, m) - } - return mats, nil -} - // execCommand executes a command and returns an error if it fails. func (c *systemdCasting) execCommand(ctx context.Context, name string, args ...string) error { cmd := exec.CommandContext(ctx, name, args...) @@ -318,61 +313,33 @@ func (c *systemdCasting) execCommand(ctx context.Context, name string, args ...s return cmd.Run() } -// discoverAndPrepareServices discovers service files, categorizes them, and prepares systemd. -// Returns nil serviceMap if no services found. -func (c *systemdCasting) discoverAndPrepareServices(ctx context.Context, poursPath string) (map[string][]string, error) { +// discoverAndPrepareServices discovers service files in the pours directory and reloads systemd. +func (c *systemdCasting) discoverAndPrepareServices(ctx context.Context, poursPath string) ([]string, error) { deploymentPath := filepath.Join(poursPath, rootcasting.DeploymentDir) entries, err := os.ReadDir(deploymentPath) if err != nil { return nil, fmt.Errorf("failed to read directory %s: %w", deploymentPath, err) } - serviceMap := map[string][]string{"keeper": {}, "store": {}, "postgres": {}, "signoz": {}, "ingester": {}, "migrator": {}} - + var services []string for _, entry := range entries { - if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".service") { + if entry.IsDir() || !strings.HasSuffix(entry.Name(), svcSuffix) { continue } - servicePath := filepath.Join(deploymentPath, entry.Name()) - baseName := strings.TrimSuffix(entry.Name(), ".service") - - switch { - case strings.HasSuffix(baseName, "-migrator"): - serviceMap["migrator"] = append(serviceMap["migrator"], servicePath) - case strings.Contains(baseName, "-telemetrykeeper-") && !strings.Contains(baseName, "-migrator"): - serviceMap["keeper"] = append(serviceMap["keeper"], servicePath) - case strings.Contains(baseName, "-telemetrystore-") && !strings.Contains(baseName, "-migrator"): - serviceMap["store"] = append(serviceMap["store"], servicePath) - case strings.Contains(baseName, "-metastore-postgres"): - serviceMap["postgres"] = append(serviceMap["postgres"], servicePath) - case strings.HasSuffix(baseName, "-signoz"): - serviceMap["signoz"] = append(serviceMap["signoz"], servicePath) - case strings.HasSuffix(baseName, "-ingester"): - serviceMap["ingester"] = append(serviceMap["ingester"], servicePath) - default: - c.logger.WarnContext(ctx, "Unknown service type, skipping", slog.String("service", servicePath)) - } + services = append(services, filepath.Join(deploymentPath, entry.Name())) } - // Check if any services were found - total := 0 - for cat, svcs := range serviceMap { - if len(svcs) > 0 { - c.logger.DebugContext(ctx, "Found services", slog.String("category", cat), slog.Int("count", len(svcs))) - total += len(svcs) - } - } - if total == 0 { - return map[string][]string{}, nil + if len(services) == 0 { + return nil, nil } - // Reload systemd to pick up new service files - c.logger.DebugContext(ctx, "Reloading systemd daemon") + c.logger.DebugContext(ctx, "Found services", slog.Int("count", len(services))) + if err := c.execCommand(ctx, "systemctl", "daemon-reload"); err != nil { return nil, fmt.Errorf("systemd daemon-reload failed: %w", err) } - return serviceMap, nil + return services, nil } // setupSystemEnvironment creates signoz user, directories, copies configs, and validates binaries. @@ -394,12 +361,14 @@ func (c *systemdCasting) setupSystemEnvironment(ctx context.Context, config *v1a // Copy clickhouse configs to standard locations if config.Spec.TelemetryStore.Spec.IsEnabled() { - if err := c.copyDir(filepath.Join(poursPath, rootcasting.DeploymentDir, "configs", "telemetrystore"), "/etc/clickhouse-server/"); err != nil { + src := filepath.Join(poursPath, rootcasting.DeploymentDir, "telemetrystore", config.Spec.TelemetryStore.Kind.String()) + if err := c.copyDir(src, "/etc/clickhouse-server/"); err != nil { return fmt.Errorf("failed to copy clickhouse-server configs: %w", err) } } if config.Spec.TelemetryKeeper.Spec.IsEnabled() { - if err := c.copyDir(filepath.Join(poursPath, rootcasting.DeploymentDir, "configs", "telemetrykeeper"), "/etc/clickhouse-keeper/"); err != nil { + src := filepath.Join(poursPath, rootcasting.DeploymentDir, "telemetrykeeper", config.Spec.TelemetryKeeper.Kind.String()) + if err := c.copyDir(src, "/etc/clickhouse-keeper/"); err != nil { return fmt.Errorf("failed to copy clickhouse-keeper configs: %w", err) } } @@ -463,32 +432,28 @@ func (c *systemdCasting) validateBinaries(config *v1alpha1.Casting) error { } // startAllServices enables and starts all discovered services. -// Systemd dependencies ensure proper ordering. -func (c *systemdCasting) startAllServices(ctx context.Context, serviceMap map[string][]string) error { - // Collect all services - var allServices []string - for _, services := range serviceMap { - allServices = append(allServices, services...) - } - - if len(allServices) == 0 { - return nil - } - - // Enable and start all services - systemd will handle ordering via dependencies - for _, svc := range allServices { +// All services are enabled first so that dependency references resolve, +// then started — systemd handles ordering via After=/Requires=. +func (c *systemdCasting) startAllServices(ctx context.Context, services []string) error { + // Enable all services first so dependencies can be resolved + for _, svc := range services { unitName := filepath.Base(svc) - c.logger.DebugContext(ctx, "Enabling service", slog.String("service", unitName), slog.String("path", svc)) - // Use full path for enable - systemctl can work with paths to service files + c.logger.DebugContext(ctx, "Enabling service", slog.String("service", unitName)) if err := c.execCommand(ctx, "systemctl", "enable", svc); err != nil { return fmt.Errorf("failed to enable service %s: %w", unitName, err) } + } + + // Reload systemd to pick up all enabled services + if err := c.execCommand(ctx, "systemctl", "daemon-reload"); err != nil { + return fmt.Errorf("systemd daemon-reload failed: %w", err) + } + + // Start all services without blocking — systemd dependencies handle ordering + for _, svc := range services { + unitName := filepath.Base(svc) c.logger.InfoContext(ctx, "Starting service", slog.String("service", unitName)) - startCtx, cancel := context.WithTimeout(ctx, serviceStartTimeout) - // Use full path for start as well - err := c.execCommand(startCtx, "systemctl", "start", unitName) - cancel() - if err != nil { + if err := c.execCommand(ctx, "systemctl", "start", "--no-block", unitName); err != nil { return fmt.Errorf("failed to start service %s: %w", unitName, err) } } diff --git a/internal/casting/systemdcasting/enricher.go b/internal/casting/systemdcasting/enricher.go index 81f0757..4505c89 100644 --- a/internal/casting/systemdcasting/enricher.go +++ b/internal/casting/systemdcasting/enricher.go @@ -97,20 +97,25 @@ func (e *linuxMoldingEnricher) enrichTelemetryKeeper(config *v1alpha1.Casting) e } func (e *linuxMoldingEnricher) enrichMetaStore(config *v1alpha1.Casting) error { - dsn := types.FormatAddress("postgres", "localhost", baseMetaStorePostgresPort) - config.Spec.MetaStore.Status.Addresses.DSN = []string{dsn} + switch config.Spec.MetaStore.Kind { + case v1alpha1.MetaStoreKindSQLite: + // SQLite — no addresses or binaries to enrich. + case v1alpha1.MetaStoreKindPostgres: + dsn := types.FormatAddress("postgres", "localhost", baseMetaStorePostgresPort) + config.Spec.MetaStore.Status.Addresses.DSN = []string{dsn} - // Get the annotation value - metastoreBin := config.Metadata.Annotations["foundry.signoz.io/metastore-postgres-binary-path"] + // Get the annotation value + metastoreBin := config.Metadata.Annotations["foundry.signoz.io/metastore-postgres-binary-path"] - // If it's missing, apply the default and write it back - if metastoreBin == "" { - metastoreBin = "/usr/bin/postgres" + // If it's missing, apply the default and write it back + if metastoreBin == "" { + metastoreBin = "/usr/bin/postgres" - if config.Metadata.Annotations == nil { - config.Metadata.Annotations = make(map[string]string) + if config.Metadata.Annotations == nil { + config.Metadata.Annotations = make(map[string]string) + } + config.Metadata.Annotations["foundry.signoz.io/metastore-postgres-binary-path"] = metastoreBin } - config.Metadata.Annotations["foundry.signoz.io/metastore-postgres-binary-path"] = metastoreBin } return nil } @@ -157,5 +162,10 @@ func (e *linuxMoldingEnricher) enrichIngester(config *v1alpha1.Casting) error { config.Metadata.Annotations["foundry.signoz.io/ingester-binary-path"] = ingesterBin } + if config.Spec.Ingester.Status.Env == nil { + config.Spec.Ingester.Status.Env = make(map[string]string) + } + config.Spec.Ingester.Status.Env["SIGNOZ_OTEL_COLLECTOR_TIMEOUT"] = "10m" + return nil } diff --git a/internal/casting/systemdcasting/templates/clickhouse.telemetrystore.v2556.service.gotmpl b/internal/casting/systemdcasting/templates/clickhouse.telemetrystore.v2556.service.gotmpl index cb815fe..2599c01 100644 --- a/internal/casting/systemdcasting/templates/clickhouse.telemetrystore.v2556.service.gotmpl +++ b/internal/casting/systemdcasting/templates/clickhouse.telemetrystore.v2556.service.gotmpl @@ -1,9 +1,8 @@ [Unit] Description=ClickHouse Server (v25.5.6) Requires=network-online.target -After=time-sync.target network-online.target{{ if $.Spec.TelemetryKeeper.Spec.Enabled }} {{ $.Metadata.Name }}-telemetrykeeper-{{ $.Spec.TelemetryKeeper.Kind }}-0.service{{ end }} -Wants=time-sync.target{{ if $.Spec.TelemetryKeeper.Spec.Enabled }} {{ $.Metadata.Name }}-telemetrykeeper-{{ $.Spec.TelemetryKeeper.Kind }}-0.service{{ end }} - +After=time-sync.target network-online.target +Wants=time-sync.target [Service] Type=simple @@ -13,9 +12,12 @@ Restart=always RestartSec=30 RuntimeDirectory=clickhouse ExecStart=/usr/bin/clickhouse-server --config=/etc/clickhouse-server/config.yaml --pid-file=/run/clickhouse/clickhouse.pid +{{- range $key, $value := $.Spec.TelemetryStore.Spec.Env }} +Environment={{ $key }}={{ $value }} +{{- end }} LimitCORE=infinity LimitNOFILE=500000 CapabilityBoundingSet=CAP_NET_ADMIN CAP_IPC_LOCK CAP_SYS_NICE CAP_NET_BIND_SERVICE - + [Install] WantedBy=multi-user.target diff --git a/internal/casting/systemdcasting/templates/clickhousekeeper.telemetrykeeper.v2556.service.gotmpl b/internal/casting/systemdcasting/templates/clickhousekeeper.telemetrykeeper.v2556.service.gotmpl index c7e9ec1..b752751 100644 --- a/internal/casting/systemdcasting/templates/clickhousekeeper.telemetrykeeper.v2556.service.gotmpl +++ b/internal/casting/systemdcasting/templates/clickhousekeeper.telemetrykeeper.v2556.service.gotmpl @@ -11,9 +11,12 @@ Group=clickhouse Restart=always RestartSec=30 RuntimeDirectory=clickhouse-keeper -{{ if and $.Spec.TelemetryKeeper.Status.Extras (index $.Spec.TelemetryKeeper.Status.Extras "cfgPath") }} +{{- if and $.Spec.TelemetryKeeper.Status.Extras (index $.Spec.TelemetryKeeper.Status.Extras "cfgPath") }} ExecStart=/usr/bin/clickhouse-keeper --config={{ index $.Spec.TelemetryKeeper.Status.Extras "cfgPath" }} --pid-file=/run/clickhouse-keeper/clickhouse-keeper.pid -{{ end }} +{{- end }} +{{- range $key, $value := $.Spec.TelemetryKeeper.Spec.Env }} +Environment={{ $key }}={{ $value }} +{{- end }} LimitCORE=infinity LimitNOFILE=500000 CapabilityBoundingSet=CAP_NET_ADMIN CAP_IPC_LOCK CAP_SYS_NICE CAP_NET_BIND_SERVICE diff --git a/internal/casting/systemdcasting/templates/ingester.service.gotmpl b/internal/casting/systemdcasting/templates/ingester.service.gotmpl index f8f37a0..2b47f9f 100644 --- a/internal/casting/systemdcasting/templates/ingester.service.gotmpl +++ b/internal/casting/systemdcasting/templates/ingester.service.gotmpl @@ -1,10 +1,6 @@ [Unit] Description=SigNoz OTel Collector Documentation=https://signoz.io/docs -After={{ $.Metadata.Name }}-telemetrystore-{{ $.Spec.TelemetryStore.Kind }}-0-0{{ if $.Spec.TelemetryStore.Spec.Enabled }} {{ $.Metadata.Name }}-telemetrystore-migrator{{ end }} -{{ if $.Spec.TelemetryStore.Spec.Enabled }} -Requires={{ $.Metadata.Name }}-telemetrystore-migrator -{{ end }} [Service] User=signoz @@ -12,12 +8,20 @@ Group=signoz Type=simple KillMode=mixed Restart=on-failure -{{/* Using Fragment specifier to get the config from pours directory */}} +RestartSec=5 {{- if and $.Metadata.Annotations (index $.Metadata.Annotations "foundry.signoz.io/ingester-binary-path") }} {{- $ingesterBinaryPath := index $.Metadata.Annotations "foundry.signoz.io/ingester-binary-path" }} -{{ if and $.Spec.Ingester.Status.Extras (index $.Spec.Ingester.Status.Extras "cfgPath") (index $.Spec.Ingester.Status.Extras "cfgOpampPath") }} +{{- if and $.Spec.Ingester.Status.Extras (index $.Spec.Ingester.Status.Extras "cfgPath") (index $.Spec.Ingester.Status.Extras "cfgOpampPath") }} +ExecStartPre={{ $ingesterBinaryPath }} migrate sync check ExecStart={{ $ingesterBinaryPath }} --config=%Y/{{ index $.Spec.Ingester.Status.Extras "cfgPath" }} --manager-config=%Y/{{ index $.Spec.Ingester.Status.Extras "cfgOpampPath" }} --copy-path=/var/lib/ingester/ingester.yaml -{{ end }} {{- end }} +{{- end }} +{{- if and $.Spec.TelemetryStore.Spec.Enabled $.Spec.TelemetryStore.Status.Addresses.TCP (index $.Spec.TelemetryStore.Status.Addresses.TCP 0) }} +Environment=SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN={{ index $.Spec.TelemetryStore.Status.Addresses.TCP 0 }} +{{- end }} +{{- range $key, $value := $.Spec.Ingester.Spec.Env }} +Environment={{ $key }}={{ $value }} +{{- end }} + [Install] WantedBy=multi-user.target diff --git a/internal/casting/systemdcasting/templates/migrator.telemetrystore.service.gotmpl b/internal/casting/systemdcasting/templates/migrator.telemetrystore.service.gotmpl index 328ffbe..8566e45 100644 --- a/internal/casting/systemdcasting/templates/migrator.telemetrystore.service.gotmpl +++ b/internal/casting/systemdcasting/templates/migrator.telemetrystore.service.gotmpl @@ -1,23 +1,24 @@ [Unit] -Description=SigNoz Schema Migrator +Description=SigNoz TelemetryStore Migrator Documentation=https://signoz.io/docs -{{ if $.Spec.TelemetryStore.Spec.Enabled }} -{{ $firstStore := printf "%s-telemetrystore-%s-0-0" $.Metadata.Name $.Spec.TelemetryStore.Kind.String }} -After={{ $firstStore }} -Requires={{ $firstStore }} -{{ end }} [Service] Type=oneshot RemainAfterExit=yes +Restart=on-failure +RestartSec=5 User=signoz Group=signoz {{- if and $.Metadata.Annotations (index $.Metadata.Annotations "foundry.signoz.io/ingester-binary-path") }} {{- $migratorBinary := index $.Metadata.Annotations "foundry.signoz.io/ingester-binary-path" }} -{{ if and $.Spec.TelemetryStore.Spec.Enabled $.Spec.TelemetryStore.Status.Addresses.TCP (index $.Spec.TelemetryStore.Status.Addresses.TCP 0) }} -{{- $dsn := index $.Spec.TelemetryStore.Status.Addresses.TCP 0 }} -ExecStart=/bin/bash -c '{{ $migratorBinary }} migrate bootstrap --clickhouse-dsn={{ $dsn }} && {{ $migratorBinary }} migrate sync up --clickhouse-dsn={{ $dsn }} && {{ $migratorBinary }} migrate async up --clickhouse-dsn={{ $dsn }}' -{{ end }} +ExecStartPre={{ $migratorBinary }} migrate ready +ExecStart=/bin/bash -c '{{ $migratorBinary }} migrate bootstrap && {{ $migratorBinary }} migrate sync up && {{ $migratorBinary }} migrate async up' +{{- end }} +{{- if and $.Spec.TelemetryStore.Spec.Enabled $.Spec.TelemetryStore.Status.Addresses.TCP (index $.Spec.TelemetryStore.Status.Addresses.TCP 0) }} +Environment=SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN={{ index $.Spec.TelemetryStore.Status.Addresses.TCP 0 }} +{{- end }} +{{- range $key, $value := $.Spec.Ingester.Spec.Env }} +Environment={{ $key }}={{ $value }} {{- end }} [Install] WantedBy=multi-user.target diff --git a/internal/casting/systemdcasting/templates/postgres.metastore.service.gotmpl b/internal/casting/systemdcasting/templates/postgres.metastore.service.gotmpl index b104c77..0d0c3da 100644 --- a/internal/casting/systemdcasting/templates/postgres.metastore.service.gotmpl +++ b/internal/casting/systemdcasting/templates/postgres.metastore.service.gotmpl @@ -7,11 +7,9 @@ After=network-online.target [Service] Type=notify User=postgres -{{ if $.Spec.MetaStore.Spec.Env }} -{{ range $key, $value := $.Spec.MetaStore.Spec.Env }} +{{- range $key, $value := $.Spec.MetaStore.Spec.Env }} Environment={{ $key }}={{ $value }} -{{ end }} -{{ end }} +{{- end }} {{- if and $.Metadata.Annotations (index $.Metadata.Annotations "foundry.signoz.io/metastore-postgres-binary-path") }} {{- $metastoreBinaryPath := index $.Metadata.Annotations "foundry.signoz.io/metastore-postgres-binary-path" }} ExecStart={{ $metastoreBinaryPath }} -D /usr/local/pgsql/data @@ -22,4 +20,4 @@ KillSignal=SIGINT TimeoutSec=infinity [Install] -WantedBy=multi-user.target \ No newline at end of file +WantedBy=multi-user.target diff --git a/internal/casting/systemdcasting/templates/signoz.service.gotmpl b/internal/casting/systemdcasting/templates/signoz.service.gotmpl index 956666f..1fb7441 100644 --- a/internal/casting/systemdcasting/templates/signoz.service.gotmpl +++ b/internal/casting/systemdcasting/templates/signoz.service.gotmpl @@ -1,10 +1,6 @@ [Unit] Description=SigNoz Documentation=https://signoz.io/docs -After={{ $.Metadata.Name }}-telemetrystore-{{ $.Spec.TelemetryStore.Kind }}-0-0 {{ $.Metadata.Name }}-metastore-{{ $.Spec.MetaStore.Kind }}{{ if $.Spec.TelemetryStore.Spec.Enabled }} {{ $.Metadata.Name }}-telemetrystore-migrator{{ end }} -{{ if $.Spec.TelemetryStore.Spec.Enabled }} -Requires={{ $.Metadata.Name }}-telemetrystore-migrator -{{ end }} [Service] User=signoz @@ -12,18 +8,16 @@ Group=signoz Type=simple KillMode=mixed Restart=on-failure +RestartSec=5 WorkingDirectory=/opt/signoz {{- if and $.Metadata.Annotations (index $.Metadata.Annotations "foundry.signoz.io/signoz-binary-path") }} {{- $signozBinaryPath := index $.Metadata.Annotations "foundry.signoz.io/signoz-binary-path" }} ExecStart={{ $signozBinaryPath }} server {{- end }} Environment=SIGNOZ_WEB_DIRECTORY=/opt/signoz/web -{{ if $.Spec.Signoz.Spec.Env }} -{{ range $key, $value := $.Spec.Signoz.Spec.Env }} +{{- range $key, $value := $.Spec.Signoz.Spec.Env }} Environment={{ $key }}={{ $value }} -{{ end }} -{{ end }} -{{ if and $.Spec.Signoz.Status.Extras (index $.Spec.Signoz.Status.Extras "envPath") }} -{{ end }} +{{- end }} + [Install] WantedBy=multi-user.target diff --git a/internal/molding/signozmolding/signoz.go b/internal/molding/signozmolding/signoz.go index 9f4b20e..a5e92a1 100644 --- a/internal/molding/signozmolding/signoz.go +++ b/internal/molding/signozmolding/signoz.go @@ -48,24 +48,29 @@ func (molding *signoz) MoldV1Alpha1(ctx context.Context, config *v1alpha1.Castin // Add metastore addresses config.Spec.Signoz.Status.Env["SIGNOZ_SQLSTORE_PROVIDER"] = config.Spec.MetaStore.Kind.String() - if config.Spec.MetaStore.Status.Addresses.DSN != nil { - if val, ok := config.Spec.Signoz.Spec.Env["SIGNOZ_SQLSTORE_POSTGRES_DSN"]; ok { - molding.logger.WarnContext(ctx, "SIGNOZ_SQLSTORE_POSTGRES_DSN is going to be overridden", slog.String("value", val)) + switch config.Spec.MetaStore.Kind { + case v1alpha1.MetaStoreKindSQLite: + config.Spec.Signoz.Status.Env["SIGNOZ_SQLSTORE_SQLITE_PATH"] = "/var/lib/signoz/signoz.db" + case v1alpha1.MetaStoreKindPostgres: + if config.Spec.MetaStore.Status.Addresses.DSN != nil { + if val, ok := config.Spec.Signoz.Spec.Env["SIGNOZ_SQLSTORE_POSTGRES_DSN"]; ok { + molding.logger.WarnContext(ctx, "SIGNOZ_SQLSTORE_POSTGRES_DSN is going to be overridden", slog.String("value", val)) + } + // construct postgres dsn with user, password, host, port, and db + addrs, err := types.NewAddresses(config.Spec.MetaStore.Status.Addresses.DSN) + if err != nil { + return fmt.Errorf("failed to parse addresses: %w", err) + } + var dsns []string + user := config.Spec.MetaStore.Status.Env["POSTGRES_USER"] + password := config.Spec.MetaStore.Status.Env["POSTGRES_PASSWORD"] + db := config.Spec.MetaStore.Status.Env["POSTGRES_DB"] + for _, addr := range addrs { + dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", user, password, addr.Host(), addr.Port(), db) + dsns = append(dsns, dsn) + } + config.Spec.Signoz.Status.Env["SIGNOZ_SQLSTORE_POSTGRES_DSN"] = strings.Join(dsns, ",") } - // construct postgres dsn with user, password, host, port, and db - addrs, err := types.NewAddresses(config.Spec.MetaStore.Status.Addresses.DSN) - if err != nil { - return fmt.Errorf("failed to parse addresses: %w", err) - } - var dsns []string - user := config.Spec.MetaStore.Status.Env["POSTGRES_USER"] - password := config.Spec.MetaStore.Status.Env["POSTGRES_PASSWORD"] - db := config.Spec.MetaStore.Status.Env["POSTGRES_DB"] - for _, addr := range addrs { - dsn := fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=disable", user, password, addr.Host(), addr.Port(), db) - dsns = append(dsns, dsn) - } - config.Spec.Signoz.Status.Env["SIGNOZ_SQLSTORE_POSTGRES_DSN"] = strings.Join(dsns, ",") } return nil }