Skip to content

metabrainz/serviceregistrator

serviceregistrator

A lightweight service registry bridge between Docker and Consul.

ServiceRegistrator automatically registers and deregisters services in Consul as Docker containers start and stop. It monitors the Docker event stream in real-time and keeps Consul's service catalog in sync with the running containers on a host.

Why ServiceRegistrator?

This project is a Python re-implementation of Gliderlabs Registrator, which is no longer actively maintained. It is partly compatible with Registrator's SERVICE_* environment variable syntax, making migration straightforward.

Key differences from Gliderlabs Registrator:

  • Explicit registration only: containers must define a SERVICE_NAME (or SERVICE_<port>_NAME) to be registered. Unnamed services are skipped, giving you full control over what appears in Consul.
  • Written in Python: easier to extend, debug, and contribute to.
  • Service aliases: register a service under an additional name with an alias health check, useful for renaming services without breaking existing Consul templates.
  • Periodic resync: optionally re-synchronize all services on a timer to recover from transient Consul issues.

Use Cases

  • Dynamic service discovery: automatically populate Consul's catalog so that load balancers, proxies, and other consumers can discover services by name.
  • Health-aware routing: leverage Docker and Consul health checks so that only healthy containers receive traffic.
  • Zero-touch service lifecycle: no manual Consul API calls needed — just start or stop containers and the catalog updates itself.
  • Gradual service renaming: use aliases to introduce new service names while keeping the old ones working during a migration period.

Install uv

https://docs.astral.sh/uv/getting-started/installation/

Dev env

uv sync
uv run serviceregistrator --help

Tests

Unit tests:

uv run pytest tests/

Integration tests (require Docker and pull a Consul image):

uv run pytest -m integration -v

All tests:

uv run pytest -m '' -v

Lint, format, and type checks:

uv run ruff check serviceregistrator tests
uv run ruff format --check serviceregistrator tests
uvx ty@0.0.29 check serviceregistrator

Manual end-to-end testing (see testing/README.md):

cd testing/dummyservice
./run_all.sh

Running in a docker container

Build Image

docker build . -t serviceregistrator

Running

docker run --rm serviceregistrator --help

References

Usage

Command-line

Usage: serviceregistrator [OPTIONS]

  Register docker containers as consul services

Options:
  -i, --ip TEXT                   address to use for services without
                                  SERVICE_IP  [required]
  -t, --tags TEXT                 comma-separated list of tags to append to
                                  all registered services
  -h, --consul-host TEXT          consul agent host  [default: 127.0.0.1]
  -p, --consul-port INTEGER       consul agent port  [default: 8500]
  -k, --dockersock TEXT           path to docker socket  [default:
                                  /var/run/docker.sock]
  -d, --delay INTEGER             delay in seconds between reconnection
                                  attempts  [default: 1]
  -s, --resync INTEGER            delay between each forced services resync
                                  [default: (disabled)]
  -f, --logfile TEXT              log file path
  -l, --loglevel [CRITICAL|ERROR|WARNING|INFO|DEBUG]
                                  log level  [default: INFO]
  -G, --debug                     output extra debug info
  -R, --debug-requests            log requests too (debug)
  -P, --service-prefix TEXT       string to prepend to all service names and
                                  IDs (testing purpose)
  --help                          Show this message and exit.

Configuring Services

ServiceRegistrator discovers services by reading SERVICE_* environment variables and Docker labels on each container. These variables control what gets registered in Consul and how.

How It Works

  1. A container must have explicitly published ports (-p or -P). For containers in host network mode, exposed ports (EXPOSE) are used.
  2. A container must define a SERVICE_NAME (or SERVICE_<port>_NAME for a specific port). Containers without a name are skipped — nothing is registered.
  3. ServiceRegistrator reads all SERVICE_* environment variables and labels, builds a service object for each named port, and registers it in Consul.

SERVICE_* Variables

You can set these as either environment variables (--env) or Docker labels (--label). Environment variables take precedence over labels when both are set.

There are two forms:

  • SERVICE_<KEY>=<value> — applies to all ports on the container (or the single exposed port).
  • SERVICE_<port>_<KEY>=<value> — applies only to the service on that internal (container) port. Port-specific values override the generic ones.

The recognized keys are:

Key Description Example
NAME (Required) Service name registered in Consul SERVICE_NAME=postgres
IP Override the service IP address SERVICE_IP=10.0.0.5
TAGS Comma-separated list of Consul tags SERVICE_TAGS=primary,db
ALIAS Register an additional service name (see Service Alias) SERVICE_ALIAS=pg-master

Any other key is stored as a service attribute (key-value metadata):

SERVICE_REGION=us-east        # sets attr "region" = "us-east"
SERVICE_80_WEIGHT=10          # sets attr "weight" = "10" on port 80

Attributes are also used to configure Consul health checks.

Container authors can set defaults in their Dockerfile; operators can override them at docker run time.

Example

docker run -d \
  --env "SERVICE_NAME=myapi" \
  --env "SERVICE_TAGS=web,public" \
  --env "SERVICE_80_CHECK_HTTP=/healthz" \
  --env "SERVICE_80_CHECK_INTERVAL=15s" \
  --publish "8080:80" \
  myimage

This registers a service named myapi in Consul at the host's IP on port 8080, with tags web and public, and an HTTP health check hitting /healthz every 15 seconds.

For a multi-port container, use port-specific names:

docker run -d \
  --env "SERVICE_80_NAME=myapi" \
  --env "SERVICE_443_NAME=myapi-ssl" \
  --publish "8080:80" \
  --publish "8443:443" \
  myimage

Service IP

The --ip command-line flag sets the default IP for all services. It can be overridden per-container with SERVICE_IP or per-port with SERVICE_<port>_IP.

Service Alias

You can register a service under an additional name using SERVICE_ALIAS or SERVICE_<port>_ALIAS. This creates a second service in Consul with a Consul alias health check that mirrors the health of the original service.

This is useful for renaming services without breaking existing Consul template files. For example:

docker run -d \
  --env "SERVICE_80_NAME=haproxy-postgres-primary" \
  --env "SERVICE_80_ALIAS=postgres-master" \
  --publish "5432:80" \
  myimage

This registers two services in Consul:

  • haproxy-postgres-primary — the real service with its normal health check
  • postgres-master — an alias that mirrors the health of haproxy-postgres-primary

Existing Consul template files using {{if service "postgres-master"}} will continue to work while you migrate to the new naming convention.

The alias service inherits the same IP, port, and tags as the original service. Its service ID has an :alias suffix appended.

Health Checks

Health checks are configured through service attributes (the SERVICE_* variables with check-related keys). The following check types are supported:

HTTP / HTTPS check:

SERVICE_80_CHECK_HTTP=/health        # path to check
SERVICE_80_CHECK_INTERVAL=15s        # check interval (default: 10s)
SERVICE_80_CHECK_TIMEOUT=2s          # request timeout
SERVICE_443_CHECK_HTTPS=/health      # same for HTTPS
SERVICE_443_CHECK_TLS_SKIP_VERIFY=true

TCP check:

SERVICE_5432_CHECK_TCP=true
SERVICE_5432_CHECK_INTERVAL=10s
SERVICE_5432_CHECK_TIMEOUT=3s

TTL check:

SERVICE_CHECK_TTL=30s

Script check:

SERVICE_CHECK_SCRIPT=curl --silent --fail http://$SERVICE_IP:$SERVICE_PORT/health

Docker check:

SERVICE_CHECK_DOCKER=curl --silent --fail http://localhost/health

Common check options:

Key Description
CHECK_INTERVAL Time between checks (default: 10s)
CHECK_TIMEOUT Check timeout
CHECK_DEREGISTER Deregister after being critical for this duration
CHECK_INITIAL_STATUS Initial check status (passing, warning, critical)

Service ID

The service ID is a cluster-wide unique identifier generated automatically:

<hostname>:<container-name>:<exposed-port>[:udp if udp]

This is mostly an implementation detail — you typically use service names, not IDs.

Docker

Docker hub: https://hub.docker.com/repository/docker/metabrainz/serviceregistrator

Image tags:

  • latest: points to latest released version (vA.B.C)
  • vA.B.C: released version
  • edge: latest build

Images are automatically built and pushed using Git Workflow (in this repo).

Running (Host mode):

docker run \
  --detach \
  --restart unless-stopped \
  --name=serviceregistrator \
  --net=host \
  --volume=/var/run/docker.sock:/var/run/docker.sock \
  metabrainz/serviceregistrator:latest \
    --ip 127.0.0.1 \
    --consul-port 8500 \
    --consul-host localhost

Running (Network bridge mode):

docker run \
  --detach \
  --restart unless-stopped \
  --name=serviceregistrator \
  --add-host=host.docker.internal:host-gateway \
  --volume=/var/run/docker.sock:/var/run/docker.sock \
  metabrainz/serviceregistrator:latest \
    --ip 127.0.0.1 \
    --consul-port 8500 \
    --consul-host host.docker.internal

Examples

See testing/dummyservice

About

A Python-based bridge between docker containers and consul services, based on gliderlabs/registrator

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

  •  

Packages

 
 
 

Contributors

Languages