OpenDecree is a single Go binary with two external dependencies: PostgreSQL and Redis (or zero dependencies in memory mode). This page covers local development, Docker, Helm, and raw Kubernetes deployment.
Run with in-memory storage — zero external dependencies:
go install github.com/opendecree/decree/cmd/server@latest
STORAGE_BACKEND=memory HTTP_PORT=8080 decree-server
# Swagger UI: http://localhost:8080/docs
# gRPC: localhost:9090The repository includes a docker-compose.yml that starts the full stack:
git clone https://github.com/opendecree/decree.git
cd decree
# Start everything: PostgreSQL, Redis, migrations, and the service
docker compose up -d --wait serviceThis starts:
| Service | Port | Purpose |
|---|---|---|
postgres |
5432 | PostgreSQL 17 database |
redis |
6379 | Redis 7 for cache + pub/sub |
migrate |
-- | Runs goose migrations, then exits |
service |
9090 (gRPC), 8080 (HTTP) | OpenDecree server |
The service is ready when docker compose up --wait returns. No JWT configuration needed — metadata auth is the default.
To include tracing and metrics, start the observability stack alongside the service:
docker compose up -d --wait service otel-collector jaegerThis adds:
| Service | Port | Purpose |
|---|---|---|
otel-collector |
4317 (gRPC), 4318 (HTTP) | OpenTelemetry Collector |
jaeger |
16686 | Jaeger UI for viewing traces |
Then enable OTel on the service by adding environment variables. See Observability for details.
docker compose down # stop containers
docker compose down -v # stop containers and delete volumes (database data)The repository includes a multi-stage Dockerfile at build/Dockerfile:
docker build -f build/Dockerfile -t decree:latest .
# Run with in-memory storage
docker run -p 9090:9090 -p 8080:8080 \
-e STORAGE_BACKEND=memory -e HTTP_PORT=8080 \
decree:latest
# Run with PostgreSQL + Redis
docker run -p 9090:9090 -p 8080:8080 \
-e DB_WRITE_URL=postgres://... \
-e REDIS_URL=redis://... \
-e HTTP_PORT=8080 \
decree:latestPre-built images are available on ghcr.io:
docker pull ghcr.io/opendecree/decree:latest # server
docker pull ghcr.io/opendecree/decree-cli:latest # CLIA Helm chart is provided at deploy/helm/decree/.
# In-memory mode (no external deps — good for evaluation)
helm install decree deploy/helm/decree \
--set config.storageBackend=memory
# With PostgreSQL and Redis (production)
helm install decree deploy/helm/decree \
--set database.existingSecret=db-creds \
--set redis.existingSecret=redis-creds| Parameter | Description | Default |
|---|---|---|
config.storageBackend |
postgres or memory |
postgres |
config.grpcPort |
gRPC port | 9090 |
config.httpPort |
REST gateway port (empty = disabled) | 8080 |
config.enableServices |
Comma-separated services | schema,config,audit |
database.existingSecret |
Secret with DB_WRITE_URL / DB_READ_URL | "" |
redis.existingSecret |
Secret with REDIS_URL | "" |
auth.jwksUrl |
JWKS URL for JWT auth | "" (metadata auth) |
ingress.enabled |
Enable Ingress | false |
otel.enabled |
Enable OpenTelemetry | false |
resources |
CPU/memory limits | {} |
replicaCount |
Number of replicas | 1 |
See deploy/helm/decree/values.yaml for all options.
Use config.enableServices to run specialized instances:
# High-traffic config reads
helm install decree-config deploy/helm/decree \
--set config.enableServices=config \
--set replicaCount=3
# Admin operations (lower traffic)
helm install decree-admin deploy/helm/decree \
--set config.enableServices="schema,audit"OpenDecree uses goose for database migrations. Migrations live in db/migrations/.
# Using the tools Docker image
docker build -f build/Dockerfile.tools -t decree-tools:latest .
docker run --rm decree-tools:latest \
goose -dir /migrations postgres \
"postgres://user:pass@host:5432/centralconfig?sslmode=disable" upThe migrate service in docker-compose.yml runs migrations automatically before the service starts. It waits for PostgreSQL to be healthy, runs goose up, and exits.
If you prefer raw manifests over Helm:
apiVersion: apps/v1
kind: Deployment
metadata:
name: decree
spec:
replicas: 2
template:
spec:
containers:
- name: decree
image: ghcr.io/opendecree/decree:latest
ports:
- containerPort: 9090
protocol: TCP
- containerPort: 8080
protocol: TCP
env:
- name: GRPC_PORT
value: "9090"
- name: HTTP_PORT
value: "8080"
- name: DB_WRITE_URL
valueFrom:
secretKeyRef:
name: decree-db
key: write-url
- name: DB_READ_URL
valueFrom:
secretKeyRef:
name: decree-db
key: read-url
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: decree-redis
key: url
readinessProbe:
grpc:
port: 9090
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
grpc:
port: 9090
initialDelaySeconds: 10
periodSeconds: 30OpenDecree exposes the standard gRPC health checking protocol, so Kubernetes gRPC probes work out of the box.
By default, the HTTP gateway rejects any request that carries x-subject, x-role, or x-tenant-id headers. These are the metadata-auth identity headers; allowing clients to set them directly enables impersonation attacks.
If you run a trusted authentication proxy (e.g. an Envoy sidecar, an Istio ingress, or a custom API gateway) in front of the HTTP gateway that sets these headers, you must declare it as trusted:
DECREE_GATEWAY_TRUSTED_PROXY=1 decree-serverA WARN is logged at startup when this flag is set. Only enable it if you can guarantee that the proxy strips or overwrites any client-supplied auth headers before they reach the gateway.
Note: The
authorizationheader (JWT Bearer tokens) is always forwarded. The restriction only applies to the three metadata-auth headers listed above.
Each enabled service registers with the gRPC health checking protocol. Services report SERVING once fully initialized:
centralconfig.v1.SchemaServicecentralconfig.v1.ConfigServicecentralconfig.v1.AuditService
Use grpc-health-probe or Kubernetes native gRPC probes to check readiness.
- Server Configuration — all environment variables
- Observability — OTel setup with Docker Compose
- Getting Started — quick start walkthrough