{"id":32739391,"url":"https://github.com/turbinelabs/rotor","last_synced_at":"2026-01-14T14:01:22.330Z","repository":{"id":57483907,"uuid":"133552986","full_name":"turbinelabs/rotor","owner":"turbinelabs","description":null,"archived":false,"fork":false,"pushed_at":"2019-08-08T10:10:35.000Z","size":5924,"stargazers_count":305,"open_issues_count":3,"forks_count":78,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-11-03T09:04:19.728Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/turbinelabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-15T17:50:27.000Z","updated_at":"2025-07-13T20:06:32.000Z","dependencies_parsed_at":"2022-08-28T17:02:14.456Z","dependency_job_id":null,"html_url":"https://github.com/turbinelabs/rotor","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/turbinelabs/rotor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbinelabs%2Frotor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbinelabs%2Frotor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbinelabs%2Frotor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbinelabs%2Frotor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/turbinelabs","download_url":"https://codeload.github.com/turbinelabs/rotor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/turbinelabs%2Frotor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28422402,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T13:30:50.153Z","status":"ssl_error","status_checked_at":"2026-01-14T13:29:08.907Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-11-03T09:01:08.177Z","updated_at":"2026-01-14T14:01:22.323Z","avatar_url":"https://github.com/turbinelabs.png","language":"Go","funding_links":[],"categories":["Envoy","Service Discovery \u0026 Registry"],"sub_categories":["工具"],"readme":"\n[//]: # ( Copyright 2018 Turbine Labs, Inc.                                   )\n[//]: # ( you may not use this file except in compliance with the License.    )\n[//]: # ( You may obtain a copy of the License at                             )\n[//]: # (                                                                     )\n[//]: # (     http://www.apache.org/licenses/LICENSE-2.0                      )\n[//]: # (                                                                     )\n[//]: # ( Unless required by applicable law or agreed to in writing, software )\n[//]: # ( distributed under the License is distributed on an \"AS IS\" BASIS,   )\n[//]: # ( WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     )\n[//]: # ( implied. See the License for the specific language governing        )\n[//]: # ( permissions and limitations under the License.                      )\n\n![Rotor Logo](rotor.png)\n\n# turbinelabs/rotor\n\n**This project is no longer maintained by Turbine Labs, which has\n[shut down](https://blog.turbinelabs.io/turbine-labs-is-shutting-down-and-our-team-is-joining-slack-2ad41554920c).**\n\n[![Apache 2.0](https://img.shields.io/badge/license-apache%202.0-blue.svg)](LICENSE)\n[![GoDoc](https://godoc.org/github.com/turbinelabs/rotor?status.svg)](https://godoc.org/github.com/turbinelabs/rotor)\n[![CircleCI](https://circleci.com/gh/turbinelabs/rotor.svg?style=shield)](https://circleci.com/gh/turbinelabs/rotor)\n[![Go Report Card](https://goreportcard.com/badge/github.com/turbinelabs/rotor)](https://goreportcard.com/report/github.com/turbinelabs/rotor)\n[![codecov](https://codecov.io/gh/turbinelabs/rotor/branch/master/graph/badge.svg)](https://codecov.io/gh/turbinelabs/rotor)\n\nRotor is a fast, lightweight bridge between your service discovery and\n[Envoy’s](https://envoyproxy.github.io) configuration APIs. It groups your\ninfrastructure into Envoy clusters and defines simple routes for each service.\nInstances are gathered directly from your service discovery registry, and\nclusters are created by grouping together instances under a common tag or label.\nThis instance and cluster information is served via Envoy’s endpoint and cluster\ndiscovery services, CDS and EDS.\n\nRotor also sets up Envoy’s routing and listeners (RDS and LDS) to serve\nthese clusters and send stats to common backends like Prometheus, statsd,\ndogstatsd, and Wavefront.\n\nRotor is a great starting point for quickly integrating Envoy with your\nexisting environment. It provides a simple service mesh for many applications\nout of the box. If you have a more complex application, you can modify it to\nyour needs or [add an API key](#api-key) to unlock traffic management with\n[Houston](https://turbinelabs.io).\n\n## Features\n\nRotor connects two types of information:\n\n- **Service Discovery** information is collected from your existing registry,\n  such as Kubernetes or Consul.\n- **Envoy Configuration** is served over Envoy’s discovery services: EDS, CDS,\n  RDS, and LDS.\n- (optionally) **Configuration via UI and API** is provided by the\n  [Turbine Labs](turbinelabs.io) API, with an [API key](#api-key).\n\nWithout an API key (“standalone mode”), Rotor will serve Envoy\nconfiguration as follows:\n\n- **Endpoints (EDS)** are mirrored from your service discovery.\n- **Clusters (CDS)** are created by grouping endpoints based on labels on your\n  nodes/pods/hosts. The label format depends on the service discovery; typically\n  `tbn_cluster` or `tbn-cluster`.\n- **Routes (RDS)** are created from your clusters. Each cluster is exposed via\n  a single domain with the same names as the cluster, and a single catch-all\n  route (`/`). This is similar to Consul or Kubernetes DNS discovery for\n  service registries.\n- **Listeners (LDS)** are statically configured. Rotor configures Envoy\n  to listen on port 80 and sets up ALS to collect stats on the routes served\n  via RDS.\n- **Access Logging (ALS)** is configured, and Rotor can send request\n  metrics to Prometheus, statsd, dogstatsd, and/or Wavefront.\n\nFor better control over the routes and listeners that Rotor sets up, there are two options:\n\n- Define static listeners and routes in a config file via the\n  `ROTOR_XDS_STATIC_RESOURCES_FILENAME` environment variable. Rotor will serve\n  these \"dynamic\" routes over RDS and LDS. To change these routes, update the\n  file and restart Rotor. More information and examples in\n  [this blog post](https://blog.turbinelabs.io/rotor-a-complete-control-plane-for-envoy-294acb3fc92).\n- Add an an API key for [Houston](https://turbinelabs.io). This allows Rotor to\n  pull routes from Houston, provides full control over domains, routes, and\n  cluster behavior via Houston's UI and API. For more information, see the\n  section below on [adding an API key](#api-key).\n\nFor control over cluster features like circuit breaking, gRPC, and static\nclusters, Rotor can also read either a set of static clusters or a cluster\ntemplate from the same `ROTOR_XDS_STATIC_RESOURCES_FILENAME` file. See an\nexample of setting up gRPC and static clusters on\n[the Turbine Labs blog](https://blog.turbinelabs.io/rotor-a-complete-control-plane-for-envoy-294acb3fc92).\n\n## Installation\n\nThe simplest way to start using Rotor is to use the docker image. You’ll\nneed to configure it to point to your service discovery, then configure Envoy to\nread xDS configuration from Rotor. How you setup Envoy will depend on your\nenvironment, though you can see a simple example\n[in the section on Envoy configuration](#envoy).\n\nRotor supports the following service discovery integrations:\n\n- Kubernetes\n- Consul\n- AWS/EC2\n- AWS/ECS\n- DC/OS\n- (experimental) Envoy v1 CDS/SDS\n- (experimental) Envoy v2 CDS/EDS\n\nAdditionally, Rotor can poll a file for service discovery information. This\nprovides a lowest-common-denominator interface if you have a mechanism for\nservice discovery that we don't yet support. We plan to add support for other\ncommon service discovery mechanisms in the future, and we'd\n[love your help](http://github.com/turbinelabs/developer/blob/master/README.md#contributing).\n\n**Note**: you must label or tag the instances you want Rotor to collect!\nThe name of this label is configurable, and the exact configuration option\ndepends on your service discovery registry. To see the flags available for your\nSD, run:\n\n```console\ndocker run turbinelabs/rotor:0.19.0 rotor \u003cplatform\u003e --help\n```\n\nwhere `\u003cplatform\u003e` is one of: aws, ecs, consul, file, kubernetes, or marathon.\n\n### Kubernetes\n\nKubernetes requires a number of RBAC objects to be created before running\nRotor. The easiest way to create all these is via\n[the YAML file](examples/kubernetes-rotor.yaml) in this repo:\n\n```console\nkubectl create -f https://raw.githubusercontent.com/turbinelabs/rotor/master/examples/kubernetes/kubernetes-rotor.yaml\n```\n\nRotor discovers clusters by looking for active pods in Kubernetes and grouping\nthem based on their labels. You will have to add two pieces of information to\neach pod to have Rotor recognize it:\n\n  - A `tbn_cluster: \u003cname\u003e` label to name the service to which the Pod belongs. The label key can be customized.\n\n  - An exposed port named `http` or a customized name.\n  A pod must have both the `tbn_cluster` label and a port named `http` to be collected by Rotor.\n\nRotor will also collect all other labels on the Pod, which can be used for\nrouting.\n\nAn example of a pod with labels correctly configured is included\n[here](https://github.com/turbinelabs/rotor/blob/master/examples/kubernetes/example-pod.yaml).\nAn [example Envoy-simple yaml](https://github.com/turbinelabs/rotor/blob/master/examples/kubernetes/envoy-simple.yaml) is also included.\n\n### Consul\n\nConsul requires the datacenter and the host/port of your Consul server.\n\n```console\ndocker run -d \\\n  -e \"ROTOR_CMD=consul\" \\\n  -e \"ROTOR_CONSUL_DC=\u003cyour datacenter\u003e\" \\\n  -e \"ROTOR_CONSUL_HOSTPORT=\u003cconsul ip address\u003e:8500\" \\\n  turbinelabs/rotor:0.19.0\n```\n\nTo mark a `Service` for Rotor, add a tag called `tbn-cluster`. See\n[examples/consul](examples/consul) for a working example.\n\n### EC2\n\nRotor can collect labels from the AWS API on EC2 instances.\n\n```console\ndocker run -d \\\n  -e 'ROTOR_AWS_AWS_ACCESS_KEY_ID=\u003cyour aws access key\u003e' \\\n  -e 'ROTOR_AWS_AWS_REGION=\u003cyour aws region\u003e' \\\n  -e 'ROTOR_AWS_AWS_SECRET_ACCESS_KEY=\u003cyour secret access key\u003e' \\\n  -e 'ROTOR_AWS_VPC_ID=\u003cyour vpc id\u003e' \\\n  -e 'ROTOR_CMD=aws' \\\n  -p 50000:50000 \\\n  turbinelabs/rotor:0.19.0\n```\n\nYou need to tag instances with the service name and port it exposes\nby adding a tag of the format `tbn:cluster:\u003ccluster-name\u003e:\u003cport-name\u003e`.\nInstances that serve more than one port can be tagged multiple times.\nFor example, to expose two services from a single instance on ports\n8080 and 8081, you can tag the instance by running:\n\n```console\naws ec2 create-tags \\\n  --resources \u003cyour instance id\u003e \\\n  --tags \\\n    Key=tbn:cluster:your-service-name:8080,Value= \\\n    Key=tbn:cluster:your-other-service:8081,Value=\n```\n\n### ECS\n\nECS integration uses the AWS API, similar to EC2.\n\n```console\ndocker run -d \\\n  -e 'ROTOR_AWS_AWS_ACCESS_KEY_ID=\u003cyour aws access key\u003e' \\\n  -e 'ROTOR_AWS_AWS_REGION=\u003cyour aws region\u003e' \\\n  -e 'ROTOR_AWS_AWS_SECRET_ACCESS_KEY=\u003cyour secret access key\u003e' \\\n  -e 'ROTOR_CMD=ecs' \\\n  -p 50000:50000 \\\n  turbinelabs/rotor:0.19.0\n```\nYou can run this inside or outside of ECS itself, as long as your\nEnvoy instances have access to the container on port 50000.\n\nECS tags indicate the service name and exposed port, and they\nare located with `dockerLabels` on the container definition:\n\n```json\n{\n  \"dockerLabels\": {\n    \"tbn-cluster\": \"your-service:8080\"\n  }\n}\n```\n\n### DC/OS\n\nRotor runs as an app inside DC/OS. Save this as `rotor.json`:\n\n```json\n{\n  \"id\": \"/tbn/rotor\",\n  \"cpus\": 1,\n  \"mem\": 128,\n  \"container\": {\n    \"type\": \"DOCKER\",\n    \"docker\": {\n      \"image\": \"turbinelabs/rotor:0.19.0\",\n      \"forcePullImage\": true\n    }\n  },\n  \"env\": {\n   \"ROTOR_CMD\": \"marathon\",\n    \"ROTOR_MARATHON_DCOS_ACS_TOKEN\": \"\u003cyour dc/os access token\u003e\",\n    \"ROTOR_MARATHON_DCOS_URL\": \"\u003cyour dc/os admin URL\u003e\",\n    \"ROTOR_MARATHON_DCOS_INSECURE\": \"\u003ctrue if admin URL is not HTTPS\u003e\"\n  },\n  \"healthChecks\": []\n}\n```\n\nDeploy the app with:\n\n```console\ndcos marathon app add rotor.json\n```\n\nTo have rotor pick up services, add `tbn_cluster` labels to each container\ndefinition with the service name.\n\n### Flat files\n\nRotor can read from flat files that define clusters and instances. To\nspecify the format of the file, use the `--format` flag (or the\n`ROTOR_FILE_FORMAT` environment variable). Possible values are \"json\"\nand \"yaml\", and the default value is \"json\".\n\n```console\ndocker run -d \\\n  -e 'ROTOR_CMD=file' \\\n  -e 'ROTOR_FILE_FORMAT=yaml' \\\n  -e 'ROTOR_FILE_FILENAME=/path/to/file/in/container' \\\n  -p 50000:50000 \\\n  turbinelabs/rotor:0.19.0\n```\n\nThe format defines clusters and the associated instances:\n\n```yaml\n- cluster: example-cluster-1\n  instances:\n    - host: 127.0.0.1\n      port: 8080\n    - host: 127.0.0.1\n      port: 8081\n- cluster: example-cluster-2\n  instances:\n    - host: 127.0.0.1\n      port: 8083\n```\n\n## Envoy\n\nOnce Rotor is running, you can configure Envoy to receive EDS, CDS,\nRDS, and LDS configuration from it. You can put together a bootstrap config\nbased on the\n[Envoy docs](https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/v2_overview#dynamic),\nor you can use [envoy-simple](https://github.com/turbinelabs/envoy-simple),\na minimal Envoy container that can configured via environment variables.\n\n```console\ndocker run -d \\\n  -e 'ENVOY_XDS_HOST=127.0.0.1' \\\n  -e 'ENVOY_XDS_PORT=50000' \\\n  -p 9999:9999 \\\n  -p 80:80 \\\n  turbinelabs/envoy-simple:0.19.0\n```\n\nYou may have to modify the host and port, depending on where you have Rotor\ndeployed.\n\nIf you are not using `envoy-simple`, you will have to set\n`--service-cluster=default-cluster` and `--service-zone=default-zone` flags on\nyour Envoy. With a Houston API key, Rotor is capable of serving many different\nEnvoy configurations, depending on which Envoy is asking. In standalone mode,\nall Envoys are assumed to be part of the same Zone and Cluster, so you must make\nsure these values are passed to Rotor.  `envoy-simple` passes `default-cluster`\nand `default-zone` by default. To serve multiple configs, either run multiple\nRotors, fork Rotor and add your own config, or see\n[Using with Houston](#api-key).\n\nYou can verify that Rotor and Envoy are working correctly together by curling\nthe admin interface to Envoy to see the routes that have been set up:\n\n```console\ncurl localhost:9999/config_dump\n```\n\nIf everything is working, you should see a JSON config object with routes for\nall your services.\n\n## Configuration\n\nGlobal flags for Rotor can be listed with\n`docker run turbinelabs/rotor:0.19.0 rotor --help`. Global flags can be be\npassed via upper-case, underscore-delimited environment variables prefixed\nwith `ROTOR_`, with all non-alpha characters converted to underscores. For\nexample, `--some-flag` becomes `ROTOR_SOME_FLAG`.\n\nPer-platform flags can be listed with\n`docker run turbinelabs/rotor:0.19.0 rotor \u003cplatform\u003e --help`. Per-platform\nflags can be similarly passed as environment variables, prefixed with\n`ROTOR_\u003cPLATFORM\u003e`. For example `--some-flag` for the kubernetes platform\nbecomes `ROTOR_KUBERNETES_SOME_FLAG`.\n\n**Note** Command-line flags take precedence over environment variables.\n\n## Configuring Leaderboard Logging\n\nRotor can be configured to periodically log a leaderboard of non-2xx requests\nto `stdout`. This functionality is controlled by selecting the number of\nresponses to track (`ROTOR_XDS_GRPC_LOG_TOP` or `--xds.grpc-log-top`) and the aggregation period\n(`ROTOR_XDS_GRPC_LOG_TOP_INTERVAL` or `--xds.grpc-log-top-interval`). These are global flags and, if being passed\non the command line, should come before platform configuration. As with any\nflag they may also be specified via environment variable.\n\nWhen viewing Rotor logs the request leaderboard is recorded in the following\nformat:\n\n```shell\n[info] \u003ctimestamp\u003e ALS: \u003cnumber of requests\u003e: \u003cHTTP response code\u003e \u003crequest path\u003e\n```\n\n## Debugging Rotor\n\nThere are a few ways to figure out what's going on with Rotor.\n\n### Debug Logging\n\nYou can make Rotor's logging more verbose by adding `ROTOR_CONSOLE_LEVEL=debug`\nto the environment, or by setting the `--console.level` flag if running the\nbinary by hand.\n\n### Config Dump\n\nYou can dump the full configuration that Rotor serves by running\n`rotor-test-client` within the running Rotor docker container:\n\n```console\ndocker exec \u003ccontainer id\u003e rotor-test-client\n```\n\nIf you've set `ROTOR_XDS_DEFAULT_CLUSTER` or `ROTOR_XDS_DEFAULT_ZONE`, you'll\nneed to correspondingly set them as arguments:\n\n```console\ndocker exec \u003ccontainer id\u003e rotor-test-client --zone=\u003czone\u003e --cluster=\u003ccluster\u003e\n```\n\nIf you're running the binaries by hand, and you've passed the `--xds.addr` flag\nto rotor, you'll need to pass the same value in the `--addr` flag to\n`rotor-test-client`.\n\n## Local Installation / Development\n\nFor development, running tests, or custom integration, you may want to run\nRotor locally.\n\n### Requirements\n\n- Go 1.10.3 or later (previous versions may work, but we don't build or test against them)\n\n### Dependencies\n\nThe `rotor` project depends on these packages:\n\n- [api](https://github.com/turbinelabs/api)\n- [cache](https://github.com/turbinelabs/cache)\n- [cli](https://github.com/turbinelabs/cli)\n- [codec](https://github.com/turbinelabs/codec)\n- [nonstdlib](https://github.com/turbinelabs/nonstdlib)\n- [stats](https://github.com/turbinelabs/stats)\n\nThe tests depend on our [test package](https://github.com/turbinelabs/test),\nand on [gomock](https://github.com/golang/mock), and gomock-based Mocks of\nmost interfaces are provided.\n\nThe Rotor plugins depend on many packages, none of which is\nexposed in the public interfaces. This should be considered an opaque\nimplementation detail, see\n[Vendoring](http://github.com/turbinelabs/developer/blob/master/README.md#vendoring)\nfor more discussion.\n\nIt should always be safe to use HEAD of all master branches of Turbine Labs\nopen source projects together, or to vendor them with the same git tag.\n\n### Install\n\n```console\ngo get -u github.com/turbinelabs/rotor/...\ngo install github.com/turbinelabs/rotor/...\n```\n\n### Clone/Test\n\n```console\nmkdir -p $GOPATH/src/turbinelabs\ngit clone https://github.com/turbinelabs/rotor.git \u003e $GOPATH/src/turbinelabs/rotor\ngo test github.com/turbinelabs/rotor/...\n```\n\n## Godoc\n\n[Rotor](https://godoc.org/github.com/turbinelabs/rotor)\n\n## Versioning\n\nPlease see\n[Versioning of Turbine Labs Open Source Projects](http://github.com/turbinelabs/developer/blob/master/README.md#versioning).\n\n## Pull Requests\n\nPatches accepted! In particular we'd love to support other mechanisms of\nservice discovery. Please see\n[Contributing to Turbine Labs Open Source Projects](http://github.com/turbinelabs/developer/blob/master/README.md#contributing).\n\n## API Key\n\nRotor is also a part of a paid subscription to\n[Houston](https://turbinelabs.io).\nBy adding an API key to Rotor, you unlock traffic management for your whole\nteam, including:\n\n- An easy-to-use UI for creating and modifying routes\n- Full configuration of all of Envoy’s features: advanced load balancing, health checking, circuit breakers, and more\n- Automatic collection of Envoy’s metrics for routes, clusters, and more, with easy integration into statsd, Prometheus, and other common dashboards\n\nSpecifically, instead of the static routes described in [Features](#features),\nan API key allows more flexible configuration of routes, domains, listeners,\nand clusters through Houston. You can also run multiple Rotor processes to\nbridge, e.g. EC2 and Kubernetes, allowing you configure routes that\nincrementally migrate traffic from one to the other. Houston also collects\nall the additional metadata on your instances, allowing you to route traffic\nbased on custom tags and labels.\n\nIf you already have an API key, see the\n[Turbine Labs docs](http://docs.turbinelabs.io/)\nfor how to get started.\n\n## Code of Conduct\n\nAll Turbine Labs open-sourced projects are released with a\n[Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in our\nprojects you agree to abide by its terms, which will be carefully enforced.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbinelabs%2Frotor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fturbinelabs%2Frotor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fturbinelabs%2Frotor/lists"}