diff --git a/docker-compose.yml b/docker-compose.yml index 65c6950e5d..34adbcc8e4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,7 +34,7 @@ x-sentry-defaults: &sentry_defaults <<: *depends_on-default smtp: <<: *depends_on-default - garage: + blob-storage: <<: *depends_on-default snuba-api: <<: *depends_on-default @@ -210,19 +210,29 @@ services: interval: 10s timeout: 10s retries: 30 - garage: - image: dxflrs/garage:v1.0.1 + blob-storage: + image: "rustfs/rustfs:1.0.0-alpha.33" + environment: + RUSTFS_VOLUMES: "/data/rustfs0" + RUSTFS_ADDRESS: ":7000" + RUSTFS_CONSOLE_ENABLE: false + RUSTFS_CONSOLE_ADDRESS: ":7001" + RUSTFS_ACCESS_KEY: "self-hosted-sentry" + RUSTFS_SECRET_KEY: "self-hosted-sentry" + RUSTFS_LOG_LEVEL: "info" volumes: - - type: bind - read_only: true - source: ./garage.toml - target: /etc/garage.toml - - "sentry-garage:/var/lib/garage/" + - "sentry-blob-storage:/data/rustfs0" healthcheck: - test: ["CMD", "/garage", "status"] - interval: 10s - timeout: 2s - retries: 2 + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + minio-cli: + image: "minio/mc:RELEASE.2025-07-16T15-35-03Z-cpuv1" + command: ["exit", "0"] + environment: + MC_HOST_BLOB: "http://self-hosted-sentry:self-hosted-sentry@blob-storage:7000" snuba-api: <<: *snuba_defaults # Kafka consumer responsible for feeding events into Clickhouse @@ -619,6 +629,8 @@ volumes: external: true sentry-symbolicator: external: true + sentry-blob-storage: + external: true # This volume stores JS SDK assets and the data inside this volume should # be cleaned periodically on upgrades. sentry-nginx-www: diff --git a/install/bootstrap-blob-storage.sh b/install/bootstrap-blob-storage.sh new file mode 100644 index 0000000000..b21c968816 --- /dev/null +++ b/install/bootstrap-blob-storage.sh @@ -0,0 +1,23 @@ +echo "${_group}Bootstrapping blob-storage (node store)..." + +$dc up --wait blob-storage postgres +s3_cli="$dcr minio-cli mc" + +# XXX(aldy505): I'm stuck here. I don't think this would work. +if [[ $($s3_cli ls BLOB/ | tail -1 | awk '{print $1}') != 'nodestore' ]]; then + # Only touch if no existing nodestore config is found + if ! grep -q "SENTRY_NODESTORE" $SENTRY_CONFIG_PY; then + nodestore_config=$(sed -n '/SENTRY_NODESTORE/,/[}]/{p}' sentry/sentry.conf.example.py) + if [[ $($dc exec postgres psql -qAt -U postgres -c "select exists (select * from nodestore_node limit 1)") = "f" ]]; then + nodestore_config=$(echo -e "$nodestore_config" | sed '$s/\}/ "read_through": True,\n "delete_through": True,\n\}/') + fi + echo "$nodestore_config" >>$SENTRY_CONFIG_PY + fi + + $s3_cli mb BLOB/nodestore + $s3_cli ilm rule add --expire-all-object-versions --expire-days ${SENTRY_EVENT_RETENTION_DAYS:-90} BLOB/nodestore +else + echo "Node store already exists, skipping..." +fi + +echo "${_endgroup}" diff --git a/sentry/sentry.conf.example.py b/sentry/sentry.conf.example.py index 4040aedd02..48e4ffe986 100644 --- a/sentry/sentry.conf.example.py +++ b/sentry/sentry.conf.example.py @@ -95,19 +95,29 @@ def get_internal_network(): # See https://develop.sentry.dev/self-hosted/experimental/errors-only/ SENTRY_SELF_HOSTED_ERRORS_ONLY = env("COMPOSE_PROFILES") != "feature-complete" -############## -# Node Store # -############## - +################ +# Node Storage # +################ + +# Sentry uses an abstraction layer called "node storage" to store raw events. +# Previously, it used PostgreSQL as the backend, but this didn't scale for +# high-throughput environments. Read more about this in the documentation: +# https://develop.sentry.dev/backend/application-domains/nodestore/ +# +# Through this setting, you can use the provided blob storage or +# your own S3-compatible API from your infrastructure. +# Other backend implementations for node storage developed by the community +# are available in public GitHub repositories. SENTRY_NODESTORE = "sentry_nodestore_s3.S3PassthroughDjangoNodeStorage" SENTRY_NODESTORE_OPTIONS = { - "compression": False, # we have compression enabled in Garage itself - "endpoint_url": "http://garage:3900", + "compression": True, + "endpoint_url": "http://blob-storage:7000", "bucket_path": "nodestore", "bucket_name": "nodestore", - "region_name": "garage", - "aws_access_key_id": "", - "aws_secret_access_key": "", + "region_name": "us-east-1", + "retry_attempts": 2, + "aws_access_key_id": "self-hosted-sentry", + "aws_secret_access_key": "self-hosted-sentry", } #########