mirror of
https://github.com/PostHog/posthog.git
synced 2026-10-26 09:51:43 +08:00
968 lines
32 KiB
YAML
968 lines
32 KiB
YAML
#
|
|
# docker-compose file used ONLY for local development.
|
|
# For more info, see:
|
|
# https://posthog.com/handbook/engineering/developing-locally
|
|
#
|
|
# PostHog has sunset support for self-hosted K8s deployments.
|
|
# See: https://posthog.com/blog/sunsetting-helm-support-posthog
|
|
#
|
|
# Profile guidance:
|
|
# New optional services should declare `profiles:` directly on the service
|
|
# here (see capture, plugins, ingestion-* for examples).
|
|
# docker-compose.profiles.yml is a legacy overlay that retroactively gates
|
|
# older services; do not add new entries there.
|
|
#
|
|
|
|
services:
|
|
proxy:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: proxy
|
|
ports:
|
|
- 127.0.0.1:8010:8000
|
|
extra_hosts:
|
|
- 'web:host-gateway'
|
|
- 'plugins:host-gateway'
|
|
- 'capture:host-gateway'
|
|
- 'capture-ai:host-gateway'
|
|
- 'capture-logs:host-gateway'
|
|
- 'capture-apm-metrics:host-gateway'
|
|
- 'replay-capture:host-gateway'
|
|
- 'feature-flags:host-gateway'
|
|
- 'hypercache-server:host-gateway'
|
|
- 'push-api:host-gateway'
|
|
environment:
|
|
CADDYFILE: |
|
|
{
|
|
servers {
|
|
trusted_proxies static ${CADDY_TRUSTED_PROXIES:-127.0.0.1/32 ::1/128}
|
|
}
|
|
}
|
|
${CADDY_HOST:-http://localhost:8000} {
|
|
@replay-capture {
|
|
path /s
|
|
path /s/*
|
|
}
|
|
|
|
@capture-ai {
|
|
path /i/v0/ai
|
|
path /i/v0/ai/*
|
|
path /i/v1/ai/events
|
|
path /i/v1/ai/events/
|
|
}
|
|
|
|
@capture {
|
|
path /e
|
|
path /e/*
|
|
path /i/v0/*
|
|
path /i/v1/analytics/events
|
|
path /i/v1/analytics/events/
|
|
path /batch
|
|
path /batch*
|
|
path /capture
|
|
path /capture*
|
|
}
|
|
|
|
@capture-logs {
|
|
path /i/v1/logs
|
|
path /i/v1/traces
|
|
}
|
|
|
|
@capture-apm-metrics {
|
|
path /i/v1/metrics
|
|
path /i/v1/prometheus/write
|
|
path /i/v1/prometheus/write/*
|
|
}
|
|
|
|
@flags {
|
|
path /flags
|
|
path /flags*
|
|
# Local evaluation (flag definitions) — mirrors cloud Contour routing to Rust
|
|
path /api/feature_flag/local_evaluation
|
|
path /api/feature_flag/local_evaluation/
|
|
path /api/feature_flag/local_evaluation/*
|
|
}
|
|
|
|
@surveys {
|
|
path /surveys
|
|
path /surveys/
|
|
path /api/surveys
|
|
path /api/surveys/
|
|
}
|
|
|
|
@remote-config {
|
|
path /array/*
|
|
}
|
|
|
|
@webhooks {
|
|
path /public/webhooks
|
|
path /public/webhooks/*
|
|
path /public/m
|
|
path /public/m/*
|
|
}
|
|
|
|
@push-subscriptions {
|
|
path /api/push_subscriptions
|
|
path /api/push_subscriptions/
|
|
}
|
|
|
|
handle @capture-ai {
|
|
reverse_proxy capture-ai:3309
|
|
}
|
|
|
|
handle @capture {
|
|
reverse_proxy capture:3307
|
|
}
|
|
|
|
handle @capture-logs {
|
|
reverse_proxy capture-logs:4320
|
|
}
|
|
|
|
handle @capture-apm-metrics {
|
|
reverse_proxy capture-apm-metrics:4321
|
|
}
|
|
|
|
handle @replay-capture {
|
|
reverse_proxy replay-capture:3306
|
|
}
|
|
|
|
handle @flags {
|
|
reverse_proxy feature-flags:3001
|
|
}
|
|
|
|
handle @surveys {
|
|
reverse_proxy hypercache-server:3002
|
|
}
|
|
|
|
handle @remote-config {
|
|
reverse_proxy hypercache-server:3002
|
|
}
|
|
|
|
handle @webhooks {
|
|
reverse_proxy plugins:6738
|
|
}
|
|
|
|
handle @push-subscriptions {
|
|
reverse_proxy push-api:6750
|
|
}
|
|
|
|
handle {
|
|
reverse_proxy web:8000
|
|
}
|
|
}
|
|
|
|
capture:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: capture
|
|
image: ghcr.io/posthog/posthog/capture:${POSTHOG_CAPTURE_TAG:-master}
|
|
restart: on-failure
|
|
ports:
|
|
- '3307:3000'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_healthy
|
|
redis7:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:3000/_liveness']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 24
|
|
start_period: 10s
|
|
profiles:
|
|
- capture
|
|
|
|
capture-ai:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: capture-ai
|
|
image: ghcr.io/posthog/posthog/capture:${POSTHOG_CAPTURE_TAG:-master}
|
|
restart: on-failure
|
|
ports:
|
|
- '3309:3000'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_healthy
|
|
redis7:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:3000/_liveness']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 24
|
|
start_period: 10s
|
|
profiles:
|
|
- ingestion
|
|
|
|
plugins:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: plugins
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6738:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
PERSONS_DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
# The plugins container runs the CDP rerun worker (default capabilities), which
|
|
# requires this. bin/start exports it for local dev; the value below is the default
|
|
# for callers (like the E2E CI job) that launch this service without bin/start.
|
|
CYCLOTRON_NODE_DATABASE_URL: ${CYCLOTRON_NODE_DATABASE_URL:-postgres://posthog:posthog@db:5432/cyclotron_node}
|
|
CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE:-posthog}
|
|
# CDP Redis defaults to 127.0.0.1 — must point to the Docker service
|
|
CDP_REDIS_HOST: redis7
|
|
CDP_VALKEY_HOST: valkey-cluster
|
|
CDP_VALKEY_PORT: 6390
|
|
# Encryption keys default is only set when NODE_ENV=dev, but the image uses production
|
|
ENCRYPTION_SALT_KEYS: '00beef0000beef0000beef0000beef00'
|
|
# PersonHog is required for CDP — point at the local gRPC router
|
|
PERSONHOG_ADDR: 'personhog-router:50052'
|
|
PERSONHOG_ENABLED: 'true'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
valkey-cluster:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
personhog-router:
|
|
condition: service_started
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
ingestion-general:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: ingestion-general
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6739:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
PERSONS_DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE:-posthog}
|
|
# The combined-mode AI consumer reads persons through PersonHog
|
|
PERSONHOG_ADDR: 'personhog-router:50052'
|
|
PERSONHOG_ENABLED: 'true'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
objectstorage:
|
|
# The combined AI consumer's blob store healthchecks the ai-blobs bucket at
|
|
# startup, and SeaweedFS creates it asynchronously, so wait for the sentinel.
|
|
condition: service_healthy
|
|
personhog-router:
|
|
condition: service_started
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
ingestion-sessionreplay:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: ingestion-sessionreplay
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6740:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
ENCRYPTION_SALT_KEYS: '00beef0000beef0000beef0000beef00'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
recording-api:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: recording-api
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6741:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
CLICKHOUSE_DATABASE: ${CLICKHOUSE_DATABASE:-posthog}
|
|
ENCRYPTION_SALT_KEYS: '00beef0000beef0000beef0000beef00'
|
|
# The image runs as production, so the in-code dev defaults do not apply. Set both
|
|
# secrets to the values Django uses under DEBUG so local calls authenticate and exercise
|
|
# the JWT path. These live here rather than in docker-compose.base.yml because hobby
|
|
# extends that file, and hobby's Django resolves both secrets to empty, so inheriting
|
|
# them there would make recording-api reject every hobby call.
|
|
INTERNAL_API_SECRET: 'posthog123'
|
|
RECORDING_API_JWT_SECRET: 'dev-recording-api-jwt-secret'
|
|
depends_on:
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
ingestion-error-tracking:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: ingestion-error-tracking
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6742:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
PERSONHOG_ADDR: 'personhog-router:50052'
|
|
PERSONHOG_ENABLED: 'true'
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
personhog-router:
|
|
condition: service_started
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
ingestion-logs:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: ingestion-logs
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6743:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
ingestion-traces:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: ingestion-traces
|
|
image: ghcr.io/posthog/posthog-node:${POSTHOG_NODE_TAG:-master}
|
|
ports:
|
|
- '6744:6738'
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_DB_NAME:-posthog}
|
|
depends_on:
|
|
kafka:
|
|
condition: service_started
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
healthcheck:
|
|
test: ['CMD', 'curl', '-f', 'http://localhost:6738/_ready']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 30
|
|
start_period: 15s
|
|
profiles:
|
|
- ingestion
|
|
|
|
browserless:
|
|
# Renders heatmap screenshots and image exports — there is no local-browser fallback.
|
|
# Optional: docker compose -f docker-compose.dev.yml --profile browserless up -d browserless
|
|
# See the HEATMAP_BROWSERLESS_* / BROWSERLESS_* entries in .env.example for the app-side wiring.
|
|
image: ghcr.io/browserless/chromium:v2.51.2
|
|
restart: on-failure
|
|
ports:
|
|
- '127.0.0.1:4445:3000'
|
|
environment:
|
|
TOKEN: dev
|
|
LOG_LEVEL: warn
|
|
DEBUG: '-*'
|
|
profiles:
|
|
- browserless
|
|
|
|
db:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: db
|
|
ports:
|
|
- '5432:5432'
|
|
volumes:
|
|
- postgres-15-data:/var/lib/postgresql/data
|
|
# something in the django app when running in dev mode
|
|
# (maybe only in Pycharm) keeps many idle transactions open
|
|
# and eventually kills postgres, these settings aim to stop that happening.
|
|
# They are only for DEV and should not be used in production.
|
|
command: postgres -c max_connections=1000 -c idle_in_transaction_session_timeout=300000 -c max_prepared_transactions=10
|
|
|
|
redis7:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: redis7
|
|
ports:
|
|
- '6379:6379'
|
|
|
|
valkey-cluster:
|
|
image: valkey/valkey:8.1-alpine
|
|
restart: on-failure
|
|
ports:
|
|
- '127.0.0.1:6390:6390'
|
|
command:
|
|
- /bin/sh
|
|
- -ec
|
|
- |
|
|
# 6390 inside the container as well as on the host, so the port CLUSTER SLOTS
|
|
# announces is right for both. It announces no address, which every cluster
|
|
# client reads as "the one you reached me on", so a host client stays on
|
|
# 127.0.0.1 and a container client stays on valkey-cluster. Announcing an
|
|
# address instead would name one of those two and break the other.
|
|
valkey-server --port 6390 --cluster-enabled yes --cluster-config-file /tmp/nodes.conf --cluster-node-timeout 5000 &
|
|
pid=$$!
|
|
until valkey-cli -p 6390 ping >/dev/null 2>&1; do sleep 0.1; done
|
|
valkey-cli -p 6390 cluster addslots $$(seq 0 16383)
|
|
wait $$pid
|
|
healthcheck:
|
|
test:
|
|
[
|
|
'CMD-SHELL',
|
|
'valkey-cli -p 6390 cluster info | grep -q cluster_state:ok && test "$$(valkey-cli -p 6390 cluster info | sed -n "s/cluster_slots_assigned://p" | tr -d "\r")" = 16384',
|
|
]
|
|
interval: 2s
|
|
timeout: 3s
|
|
retries: 15
|
|
start_period: 5s
|
|
|
|
redis-cluster:
|
|
image: redis:7.2
|
|
restart: on-failure
|
|
ports:
|
|
- '127.0.0.1:6399:6379'
|
|
command: >
|
|
bash -c "
|
|
redis-server
|
|
--port 6379
|
|
--cluster-enabled yes
|
|
--cluster-config-file /data/nodes.conf
|
|
--cluster-node-timeout 5000
|
|
--cluster-announce-ip 127.0.0.1
|
|
--cluster-announce-port 6399
|
|
--appendonly yes &
|
|
sleep 1 &&
|
|
redis-cli -p 6379 cluster addslots $$(seq 0 16383) &&
|
|
tail -f /dev/null
|
|
"
|
|
volumes:
|
|
- redis-cluster-data:/data
|
|
healthcheck:
|
|
test: ['CMD', 'redis-cli', '-p', '6379', 'cluster', 'info']
|
|
interval: 2s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
flower:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: flower
|
|
ports:
|
|
- '5555:5555'
|
|
|
|
clickhouse:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: clickhouse
|
|
hostname: clickhouse
|
|
# ClickHouse writes ~1 GB/hour in dev and json-file driver has no default rotation
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: '50m'
|
|
max-file: '3'
|
|
# Development performance optimizations
|
|
mem_limit: 8g
|
|
cpus: 2
|
|
environment:
|
|
- AWS_ACCESS_KEY_ID=object_storage_root_user
|
|
- AWS_SECRET_ACCESS_KEY=object_storage_root_password
|
|
- CLICKHOUSE_SKIP_USER_SETUP=1
|
|
ports:
|
|
- '8123:8123'
|
|
- '8443:8443'
|
|
- '9000:9000'
|
|
- '9440:9440'
|
|
- '9009:9009'
|
|
volumes:
|
|
- ./posthog/idl:/idl
|
|
- ./docker/clickhouse/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d
|
|
- ./docker/clickhouse/config.xml:/etc/clickhouse-server/config.xml
|
|
- ./docker/clickhouse/config.d/default.xml:/etc/clickhouse-server/config.d/default.xml
|
|
- ./docker/clickhouse/config.d/dev-memory.xml:/etc/clickhouse-server/config.d/dev-memory.xml
|
|
- ./docker/clickhouse/users-dev.xml:/etc/clickhouse-server/users.xml
|
|
- ./docker/clickhouse/user_defined_function.xml:/etc/clickhouse-server/user_defined_function.xml
|
|
- ./posthog/user_scripts:/var/lib/clickhouse/user_scripts
|
|
- clickhouse-data:/var/lib/clickhouse
|
|
extra_hosts:
|
|
- 'host.docker.internal:host-gateway'
|
|
depends_on:
|
|
- kafka
|
|
- zookeeper
|
|
|
|
zookeeper:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: zookeeper
|
|
ports:
|
|
- '2181:2181'
|
|
# With persistent volumes, snapshots and txn logs accumulate forever unless
|
|
# autopurge is on (the image default disables it). Matches hobby.
|
|
environment:
|
|
ZOO_AUTOPURGE_PURGEINTERVAL: 1
|
|
ZOO_AUTOPURGE_SNAPRETAINCOUNT: 3
|
|
volumes:
|
|
- zookeeper-datalog:/datalog
|
|
- zookeeper-data:/data
|
|
- zookeeper-logs:/logs
|
|
|
|
kafka:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: kafka
|
|
ports:
|
|
- '9092:9092'
|
|
depends_on:
|
|
- zookeeper
|
|
|
|
kafka-init:
|
|
image: docker.io/redpandadata/redpanda:v25.1.9
|
|
entrypoint: /bin/sh
|
|
restart: 'no'
|
|
command:
|
|
- -c
|
|
- |
|
|
set -x
|
|
# Redpanda auto_create_topics_enabled=true only fires on producer-first
|
|
# writes. Consumer-only services (e.g. embedding-worker) error on missing
|
|
# topics, so we pre-create them here. Idempotent — re-running is safe.
|
|
TIMEOUT=60
|
|
ELAPSED=0
|
|
until rpk topic list --brokers kafka:9092 2>/dev/null; do
|
|
echo "Waiting for Kafka broker... (elapsed: ${ELAPSED}s)"
|
|
sleep 2
|
|
ELAPSED=$((ELAPSED + 2))
|
|
if [ $ELAPSED -ge $TIMEOUT ]; then
|
|
echo "Timeout waiting for Kafka broker after ${TIMEOUT}s"
|
|
exit 1
|
|
fi
|
|
done
|
|
# The topic list is docker/kafka/topics.txt, mounted below. It is a
|
|
# shared file rather than a literal here so a test can check it against the
|
|
# Kafka tables in schema.py; that header explains what needs pre-creating.
|
|
TOPICS=$$(grep -vE '^[[:space:]]*#|^[[:space:]]*$$' /topics.txt)
|
|
EXISTING=$$(rpk topic list --brokers kafka:9092 | awk '{print $$1}')
|
|
for topic in $$TOPICS; do
|
|
if rpk topic create "$$topic" --brokers kafka:9092 -p 1 -r 1 2>&1; then
|
|
echo "Topic $$topic created"
|
|
elif echo "$$EXISTING" | grep -qx "$$topic"; then
|
|
echo "Topic $$topic already exists"
|
|
else
|
|
echo "Failed to create topic $$topic"
|
|
exit 1
|
|
fi
|
|
done
|
|
volumes:
|
|
- ./docker/kafka/topics.txt:/topics.txt:ro
|
|
depends_on:
|
|
kafka:
|
|
condition: service_healthy
|
|
|
|
kafka_ui:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: kafka_ui
|
|
ports:
|
|
- '9093:8080'
|
|
environment:
|
|
SERVER_MAX_HTTP_REQUEST_HEADER_SIZE: 65536
|
|
depends_on:
|
|
- kafka
|
|
|
|
objectstorage:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: objectstorage
|
|
ports:
|
|
- '19000:19000'
|
|
- '19001:19001'
|
|
# Named volume from the SeaweedFS swap; the old MinIO volume is left in place
|
|
# because SeaweedFS cannot read its on-disk format.
|
|
volumes:
|
|
- objectstorage-data:/data
|
|
|
|
objectstorage-azure:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: objectstorage-azure
|
|
ports:
|
|
- '10000:10000'
|
|
|
|
maildev:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: maildev
|
|
ports:
|
|
- '1080:1080'
|
|
- '1025:1025'
|
|
|
|
webhook-tester:
|
|
image: tarampampam/webhook-tester:2.2.6
|
|
restart: on-failure
|
|
ports:
|
|
- '2080:8080'
|
|
environment:
|
|
- AUTO_CREATE_SESSIONS=true
|
|
|
|
personhog-replica:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-replica
|
|
environment:
|
|
PRIMARY_DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
profiles:
|
|
- ingestion
|
|
|
|
personhog-router:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-router
|
|
ports:
|
|
- '50052:50052'
|
|
depends_on:
|
|
personhog-replica:
|
|
condition: service_started
|
|
profiles:
|
|
- ingestion
|
|
|
|
personhog-router-leader:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-router-leader
|
|
ports:
|
|
- '50054:50054'
|
|
depends_on:
|
|
etcd:
|
|
condition: service_healthy
|
|
personhog-replica:
|
|
condition: service_started
|
|
profiles:
|
|
- ingestion
|
|
|
|
personhog-leader:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-leader
|
|
environment:
|
|
FALLBACK_DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
depends_on:
|
|
etcd:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
kafka:
|
|
condition: service_started
|
|
personhog-etcd-init:
|
|
condition: service_completed_successfully
|
|
profiles:
|
|
- ingestion
|
|
|
|
personhog-writer:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-writer
|
|
environment:
|
|
DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
depends_on:
|
|
etcd:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
kafka:
|
|
condition: service_started
|
|
personhog-etcd-init:
|
|
condition: service_completed_successfully
|
|
profiles:
|
|
- ingestion
|
|
|
|
personhog-identity:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: personhog-identity
|
|
environment:
|
|
PRIMARY_DATABASE_URL: postgres://posthog:posthog@db:5432/${POSTHOG_PERSONS_DB_NAME:-posthog}
|
|
ports:
|
|
- '50055:50055'
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
personhog-router-leader:
|
|
condition: service_started
|
|
profiles:
|
|
- ingestion
|
|
|
|
# Seeds the changelog config the personhog services read at boot;
|
|
# idempotent, and the same key bin/mprocs.yaml writes for hogli runs.
|
|
personhog-etcd-init:
|
|
image: quay.io/coreos/etcd:v3.6.8
|
|
restart: 'no'
|
|
entrypoint:
|
|
[
|
|
'etcdctl',
|
|
'--endpoints=http://etcd:2379',
|
|
'put',
|
|
'/personhog/config/changelog',
|
|
'{"topic":"personhog_updates","partitions":4,"epoch":1,"writer_group":"personhog-writer","draining":[]}',
|
|
]
|
|
depends_on:
|
|
etcd:
|
|
condition: service_healthy
|
|
profiles:
|
|
- ingestion
|
|
|
|
feature-flags:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: feature-flags
|
|
depends_on:
|
|
redis7:
|
|
condition: service_healthy
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
FLAGS_REDIS_URL: 'redis://redis7:6379/1'
|
|
# The /flags/definitions reader stays on shared Redis unless
|
|
# FLAG_DEFINITIONS_DEDICATED_REDIS_ENABLED is set.
|
|
REDIS_COMPRESSION_ENABLED: 'true'
|
|
INTERNAL_REQUEST_TOKEN: 'dev-internal-token'
|
|
|
|
usage-ingestion:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: usage-ingestion
|
|
ports:
|
|
- '7143:7143'
|
|
- '7144:7144'
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
kafka:
|
|
condition: service_healthy
|
|
valkey-cluster:
|
|
condition: service_healthy
|
|
environment:
|
|
USAGE_INGESTION_REDIS_URL: 'redis://valkey-cluster:6390'
|
|
# Keeps a bare `up` from building an image that is not published yet.
|
|
profiles:
|
|
- ingestion
|
|
|
|
# Temporal containers
|
|
elasticsearch:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: elasticsearch
|
|
expose:
|
|
- 9200
|
|
|
|
# OpenSearch (LLM trace reverse index). 9201 to avoid Elasticsearch's 9200.
|
|
opensearch:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: opensearch
|
|
ports:
|
|
- '127.0.0.1:9201:9200'
|
|
profiles: [opensearch]
|
|
opensearch-dashboards:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: opensearch-dashboards
|
|
ports:
|
|
- '127.0.0.1:5601:5601'
|
|
profiles: [opensearch]
|
|
opensearch-init:
|
|
image: curlimages/curl:8.10.1
|
|
depends_on:
|
|
opensearch:
|
|
condition: service_healthy
|
|
restart: 'no'
|
|
volumes:
|
|
- ./products/ai_observability/opensearch:/work:ro
|
|
entrypoint: ['sh', '/work/init.sh']
|
|
profiles: [opensearch]
|
|
|
|
temporal:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: temporal
|
|
ports:
|
|
- 7233:7233
|
|
volumes:
|
|
- ./docker/temporal/dynamicconfig:/etc/temporal/config/dynamicconfig
|
|
|
|
temporal-admin-tools:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: temporal-admin-tools
|
|
depends_on:
|
|
- temporal
|
|
temporal-ui:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: temporal-ui
|
|
ports:
|
|
- 8081:8080
|
|
depends_on:
|
|
temporal:
|
|
condition: service_started
|
|
db:
|
|
condition: service_healthy
|
|
|
|
otel-collector:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: otel-collector
|
|
container_name: otel-collector-local
|
|
ports:
|
|
- '4317:4317' # OTLP gRPC receiver
|
|
- '4318:4318' # OTLP HTTP receiver
|
|
- '13133:13133' # health_check extension
|
|
- '55679:55679' # zpages extension
|
|
volumes:
|
|
- ./otel-collector-config.dev.yaml:/etc/otel-collector-config.yaml
|
|
environment:
|
|
# Used by otel-collector-config.dev.yaml to scope container log
|
|
# collection to this compose project only.
|
|
COMPOSE_PROJECT: posthog
|
|
extra_hosts:
|
|
- 'host.docker.internal:host-gateway'
|
|
depends_on:
|
|
- jaeger
|
|
|
|
jaeger:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: jaeger
|
|
container_name: jaeger-local
|
|
ports:
|
|
- '16686:16686' # Jaeger UI
|
|
- '14268:14268' # jaeger.thrift
|
|
- '14250:14250' # model.proto
|
|
|
|
dynamodb:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: dynamodb
|
|
profiles: [dynamodb]
|
|
container_name: '${DYNAMODB_DOCKER_NAME:-dynamodb-main}'
|
|
ports:
|
|
# Not 8000 (the Django dev server) and not 18000, which the eval harness binds for its
|
|
# live server, where sharing the port fails `hogli evals` on Linux with the stack up.
|
|
- '127.0.0.1:18010:8000'
|
|
|
|
seaweedfs:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: seaweedfs
|
|
container_name: '${SEAWEEDFS_DOCKER_NAME:-seaweedfs-main}'
|
|
command: server -s3 -s3.port=8333 -filer -dir=/data
|
|
ports:
|
|
- '127.0.0.1:8333:8333' # S3 API
|
|
- '127.0.0.1:9333:9333' # Master server
|
|
- '127.0.0.1:8888:8888' # SeaweedFS Filer UI
|
|
volumes:
|
|
- 'seaweedfs-data:/data'
|
|
|
|
duckgres:
|
|
extends:
|
|
file: docker-compose.base.yml
|
|
service: duckgres
|
|
profiles: ['duckgres']
|
|
ports:
|
|
- '15432:15432'
|
|
|
|
etcd:
|
|
image: quay.io/coreos/etcd:v3.6.8
|
|
restart: on-failure
|
|
environment:
|
|
ETCD_NAME: etcd0
|
|
ETCD_ADVERTISE_CLIENT_URLS: http://etcd:2379
|
|
ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
|
|
ports:
|
|
- '127.0.0.1:2379:2379'
|
|
healthcheck:
|
|
test: ['CMD', 'etcdctl', 'endpoint', 'health']
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
networks:
|
|
otel_network:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
postgres-15-data:
|
|
redis-cluster-data:
|
|
redpanda-data:
|
|
seaweedfs-data:
|
|
duckgres-data:
|
|
objectstorage-data:
|
|
clickhouse-data:
|
|
zookeeper-data:
|
|
zookeeper-datalog:
|
|
zookeeper-logs:
|