{"id":26576482,"url":"https://github.com/getsentry/xds","last_synced_at":"2026-03-09T19:40:00.780Z","repository":{"id":42013317,"uuid":"190784891","full_name":"getsentry/xds","owner":"getsentry","description":"xDS service for Envoy","archived":false,"fork":false,"pushed_at":"2024-05-07T13:12:03.000Z","size":102,"stargazers_count":35,"open_issues_count":2,"forks_count":3,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-22T06:47:12.748Z","etag":null,"topics":["tag-production"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getsentry.png","metadata":{"funding":{"custom":["https://sentry.io/pricing/","https://sentry.io/"]},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-07T17:39:35.000Z","updated_at":"2025-03-08T19:09:49.000Z","dependencies_parsed_at":"2022-08-12T02:20:50.119Z","dependency_job_id":null,"html_url":"https://github.com/getsentry/xds","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fxds","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fxds/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fxds/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsentry%2Fxds/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getsentry","download_url":"https://codeload.github.com/getsentry/xds/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245049599,"owners_count":20552707,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["tag-production"],"created_at":"2025-03-23T03:21:07.940Z","updated_at":"2026-03-09T19:40:00.737Z","avatar_url":"https://github.com/getsentry.png","language":"Go","readme":"# xDS\n\nImplementation of [Envoy's](https://www.envoyproxy.io/) dynamic resources discovery [xDS REST](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol).\n\nxDS is fundamentally an HTTP service that is hit by every Envoy process to get its state of listeners (LDS), clusters (CDS) and subsequently each cluster's endpoints through (EDS).\n\nIt's tightly coupled to Kubernetes:\n- Uses config map for configuration.\n- Cluster endpoints are Kubernetes service endpoints.\n\nLimitations:\n- Supports only services exposing one port. Services exposing multiple ports will are ignored.\n\n\n## Configuration\n\nxDS uses environment variables for configuration:\n\n- **XDS_CONFIGMAP** - Path to the configuration configmap in form `{namespace}/{configmap.name}`. Defaults to `default/xds`.\n- **XDS_LISTEN** - Socket address for the http server. Defaults to `127.0.0.1:5000`.\n\n\n## Running\n\nBuild a docker image:\n\n```\ngo build xds\n```\n\nFor xds to run, you need access to Kubernetes cluster. During startup xDS will try to infer by reading the `~/.kube/config` file with fallback to a in cluster config.\n\nAssume you have local cluster running, accessible and the configuration loaded:\n\n```\n./xds\n2020/05/22 15:24:52 configstore.go:146: ConfigStore.Init:  default xds default/xds\n2020/05/22 15:24:52 main.go:106: ready.\n```\n\nFor testing out use the example configmap at `example/k8s/configmap.yaml`.\n\n\n## Configuration validation\n\nValidate configmap using `--validate` cli argument:\n\n```\n./xds --validate path/to/configmap.yaml\n\n# or from stdin\n\nrender_my_configmap | ./xds --validate -\n```\n\nOr by `POST`ing to the `/validate` endpoint:\n\n```\ncurl localhost:5000/validate --data-binary @example/k8s/configmap.yaml\nok\n\n# or\n\nrender_my_configmap | curl localhost:5000/validate --data-binary @-\nok\n```\n\n\n## Inspecting\n\nThese can easily be introspected through the HTTP API with `curl`.\n\nLDS - http://xds.service.sentry.internal/v2/discovery:listeners\u003cbr\u003e\nCDS - http://xds.service.sentry.internal/v2/discovery:clusters\u003cbr\u003e\nEDS - http://xds.service.sentry.internal/v2/discovery:endpoints\n\n\nBoth LDS and CDS only need information about the host it's querying about, whereas EDS needs to know what service it's asking about.\n\nAn example LDS request looks like:\n\n```shell\n% curl -s -XPOST -d '{\"node\": {\"id\": \"xxx\", \"cluster\":\"snuba\"}}'  xds.service.sentry.internal/v2/discovery:listeners | jq .\n{\n  \"version_info\": \"0\",\n  \"resources\": [\n    {\n      \"@type\": \"type.googleapis.com/envoy.api.v2.Listener\",\n      \"name\": \"snuba-query-tcp\",\n      \"address\": {\n        \"socket_address\": {\n          \"address\": \"127.0.0.1\",\n          \"port_value\": 9000\n        }\n      },\n      \"filter_chains\": [\n        {\n          \"filters\": [\n            {\n              \"name\": \"envoy.tcp_proxy\",\n              \"typed_config\": {\n                \"@type\": \"type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy\",\n                \"stat_prefix\": \"snuba-query-tcp\",\n                \"cluster\": \"snuba-query-tcp\"\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\nThe request is sending along a node id, and a node cluster assignment. This relates to the `assignments` dataset in our `ConfigMap` if we want to make sure that the correct listeners are being served for `snuba`.\n\nThis exact query can be made against the CDS endpoint to get the cluster assignments.\n\nFrom there, the only weird one is EDS, which is probably the most important one. Since EDS returns back the list of endpoints for a specific backend.\n\nExample:\n\n```shell\n% curl -s -XPOST -d '{\"node\": {\"id\": \"xxx\", \"cluster\":\"snuba\"},\"resource_names\":[\"default/snuba-query-tcp\"]}'  xds.service.sentry.internal/v2/discovery:endpoints | jq .\n{\n  \"version_info\": \"0\",\n  \"resources\": [\n    {\n      \"@type\": \"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment\",\n      \"cluster_name\": \"default/snuba-query-tcp\",\n      \"endpoints\": [\n        {\n          \"lb_endpoints\": [\n            {\n              \"endpoint\": {\n                \"address\": {\n                  \"socket_address\": {\n                    \"address\": \"192.168.208.109\",\n                    \"port_value\": 9000\n                  }\n                }\n              }\n            },\n            {\n              \"endpoint\": {\n                \"address\": {\n                  \"socket_address\": {\n                    \"address\": \"192.168.208.139\",\n                    \"port_value\": 9000\n                  }\n                }\n              }\n            }\n          ]\n        }\n      ]\n    }\n  ]\n}\n```\n\nFor EDS, it takes an extra \"resource_names\" key to match the cluster_name inside of the cluster definition.\n","funding_links":["https://sentry.io/pricing/","https://sentry.io/"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsentry%2Fxds","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetsentry%2Fxds","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsentry%2Fxds/lists"}