All apps · 0 apps
Traefik-Kop
Docker app from martial's Repository
Overview
Readme
View on GitHubtraefik-kop
A dynamic docker->redis->traefik discovery agent.
Solves the problem of running a non-Swarm/Kubernetes multi-host cluster with a single public-facing traefik instance.
+---------------------+ +---------------------+
| | | |
+---------+ :443 | +---------+ | :8088 | +------------+ |
| WAN |--------------->| traefik |<-------------------->| svc-nginx | |
+---------+ | +---------+ | | +------------+ |
| | | | |
| +---------+ | | +-------------+ |
| | redis |<-------------------->| traefik-kop | |
| +---------+ | | +-------------+ |
| docker1 | | docker2 |
+---------------------+ +---------------------+
traefik-kop solves this problem by using the same traefik docker-provider
logic. It reads the container labels from the local docker node and publishes
them to a given redis instance. Simply configure your traefik node with a
redis provider and point it to the same instance, as in the diagram above.
Contents
- traefik-kop
Usage
Configure traefik to use the redis provider, for example via traefik.yml:
providers:
providersThrottleDuration: 2s
docker:
watch: true
endpoint: unix:///var/run/docker.sock
swarmModeRefreshSeconds: 15s
exposedByDefault: false
redis:
endpoints:
# assumes a redis link with this service name running on the same
# docker host as traefik
- "redis:6379"
Run traefik-kop on your other nodes via docker-compose:
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- "REDIS_ADDR=192.168.1.50:6379"
- "BIND_IP=192.168.1.75"
# Alternatively, derive from an interface (requires network_mode: host)
# - "BIND_INTERFACE=eth0"
Then add the usual labels to your target service:
services:
nginx:
image: "nginx:alpine"
restart: unless-stopped
ports:
# The host port binding will automatically be picked up for use as the
# service endpoint. See 'service port binding' in the configuration
# section for more.
- 8088:80
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`nginx-on-docker2.example.com`)"
- "traefik.http.routers.nginx.tls=true"
- "traefik.http.routers.nginx.tls.certresolver=default"
# [opptional] explicitly set the port binding for this service.
# See 'service port binding' in the configuration section for more.
- "traefik.http.services.nginx.loadbalancer.server.scheme=http"
- "traefik.http.services.nginx.loadbalancer.server.port=8088"
See also the IP Binding section below.
Configuration
traefik-kop can be configured via either CLI flags or environment variables.
USAGE:
traefik-kop [global options] command [command options] [arguments...]
GLOBAL OPTIONS:
--hostname value Hostname to identify this node in redis (default: "server.local") [$KOP_HOSTNAME]
--bind-ip value IP address to bind services to [$BIND_IP]
--bind-interface value Network interface to derive bind IP (overrides auto-detect) [$BIND_INTERFACE]
--skip-replace Disable custom IP replacement (default: false) [$SKIP_REPLACE]
--redis-addr value Redis address (default: "127.0.0.1:6379") [$REDIS_ADDR]
--redis-user value Redis username (default: "default") [$REDIS_USER]
--redis-pass value Redis password (if needed) [$REDIS_PASS]
--redis-db value Redis DB number (default: 0) [$REDIS_DB]
--redis-ttl value Redis TTL (in seconds) (default: 0) [$REDIS_TTL]
--redis-tls Connect to Redis over TLS (default: false) [$REDIS_TLS]
--redis-tls-ca value Path to PEM CA bundle used to verify the Redis server (default: system roots) [$REDIS_TLS_CA]
--redis-tls-cert value Path to PEM client certificate for Redis mutual TLS [$REDIS_TLS_CERT]
--redis-tls-key value Path to PEM client private key for Redis mutual TLS [$REDIS_TLS_KEY]
--redis-tls-server-name value Server name used to verify the Redis certificate [$REDIS_TLS_SERVER_NAME]
--redis-tls-insecure-skip-verify Skip verification of the Redis server certificate (insecure) [$REDIS_TLS_INSECURE_SKIP_VERIFY]
--redis-sentinel-addrs value Comma-separated list of Redis Sentinel addresses (e.g., host1:26379,host2:26379) [$REDIS_SENTINEL_ADDRS]
--redis-sentinel-master value Redis Sentinel master name [$REDIS_SENTINEL_MASTER]
--docker-host value Docker endpoint (default: "unix:///var/run/docker.sock") [$DOCKER_ADDR]
--docker-config value Docker provider config (file must end in .yaml) [$DOCKER_CONFIG]
--docker-prefix value Docker label prefix [$DOCKER_PREFIX]
--poll-interval value Poll interval for refreshing container list (default: 60) [$KOP_POLL_INTERVAL]
--namespace value Namespace to process containers for [$NAMESPACE]
--verbose Enable debug logging (default: false) [$VERBOSE, $DEBUG]
--help, -h show help
--version, -V Print the version (default: false)
Most important are the bind-ip/bind-interface and redis-addr flags.
IP Binding
There are a number of ways to set the IP published to traefik. Below is the order of precedence (highest first) and detailed descriptions of each setting.
kop.<service name>.bind.iplabelkop.bind.iplabel- Container networking IP
--bind-ipCLI flag (orBIND_IPenv var)--bind-interfaceCLI flag (orBIND_INTERFACEenv var), requires network_mode: host- Auto-detected host IP
bind-ip
Since your upstream docker nodes are external to your primary traefik server, traefik needs to connect to these services via the server's public IP rather than the usual method of using the internal docker-network IPs (by default 172.20.0.x or similar).
When using host networking this can be auto-detected, however it is advisable in
the majority of cases to manually set this to the desired IP address. This can
be done using the docker image by exporting the BIND_IP environment variable.
bind-interface
If you prefer to bind using the primary IPv4 address of a specific network
interface, you can specify it via --bind-interface or the BIND_INTERFACE
environment variable, for example --bind-interface eth0. This is used when
--bind-ip is not provided. If the interface has multiple addresses, the first
non-loopback IPv4 address is selected.
This option requires that the container be run with network_mode: host so that the interface is visible to the container.
traefik-kop service labels
The bind IP can be set via label for each service/container.
Labels can be one of two keys:
kop.<service name>.bind.ip=2.2.2.2kop.bind.ip=2.2.2.2
For a container with a single exposed service, or where all services use the same IP, the latter is sufficient.
Container Networking
If your container is configured to use a network-routable IP address via an
overlay network or CNI plugin, that address will override the bind-ip
configuration above when the traefik.docker.network label is present on the
service.
If using a global overlay network in your Traefik Docker Provider
Config, it is recommended that you disable IP
replacement entirely (see below).
Disable IP Replacement (auto-detection)
traefik-kop's custom IP and port auto-detection can be disabled by passing the --skip-replace flag
or setting the SKIP_REPLACE=1 environment variable. When set, traefik-kop will rely solely on
traefik's native IP and port detection. Other relevant flags such as --bind-ip or --bind-interface
will have no effect.
This works best when your services are using an overlay network, as described in Container Networking above.
Load Balancer Merging
If your service is running on multiple nodes and load balanced by traefik, you can enable merging of load balancers by adding the following label to your container:
kop.merge-lbs=true
When set, kop will check in redis for an existing definition and, if found, append it's service address to the ones already present.
This setting is off by default as there are some cases where it could cause an issue, such as if your node's IP changes. In this case, the dead IP would be left in place and the new IP would get added to the list, causing some of your traffic to fail.
Service port binding
By default, the service port will be picked up from the container port bindings if only a single port is bound. For example:
services:
nginx:
image: "nginx:alpine"
restart: unless-stopped
ports:
- 8088:80
8088 would automatically be used as the service endpoint's port in traefik.
With multiple published ports, select the internal port using the standard
Traefik service label. Traefik-kop matches both the internal port and protocol
(TCP for HTTP/TCP services, UDP for UDP services) to find its host port:
services:
nginx:
image: "nginx:alpine"
ports:
- 8088:80
- "127.0.0.1::10/udp"
labels:
# (note: other labels snipped for brevity)
- "traefik.http.services.nginx.loadbalancer.server.port=80"
- "traefik.udp.services.nginx-udp.loadbalancer.server.port=10"
The HTTP endpoint uses host port 8088. The UDP endpoint uses the ephemeral
host port assigned by Docker, read from the container's runtime network settings.
The same internal port number can be published separately for TCP and UDP.
No additional labels or configuration are needed.
If a labeled port has no matching internal-port publication, its value is used unchanged. This preserves explicit host-port labels and supports host networking. If a number matches an internal port, its published host port takes precedence. Published ports must be reachable from Traefik; a loopback-only binding is only reachable on that host.
Namespaces
traefik-kop has the ability to target containers via namespaces(s). Simply
configure kop with a namespace:
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- "REDIS_ADDR=192.168.1.50:6379"
- "BIND_IP=192.168.1.75"
- "NAMESPACE=staging"
Then add the kop.namespace label to your target services, along with the usual traefik labels:
services:
nginx:
image: "nginx:alpine"
restart: unless-stopped
ports:
- 8088:80
labels:
- "kop.namespace=staging"
- "traefik.enable=true"
- "traefik..."
Multiple namespaces can be used by comma-delimiting your values. Traefik-kop will include a container as long as one of its namespaces is found.
services:
traefik-kop:
# ...
environment:
# will expose any service with either 'dev' or 'staging'
- "NAMESPACE=dev,staging"
services:
nginx:
# ...
labels:
# will be exposed because it has namespace 'staging'
- "kop.namespace=staging,experimental"
Namespace via label prefix
An alternative method of namespacing is to add a custom prefix for your traefik-related labels. This
works as an inclusion filter for traefik-kop and an exclusion filter for traefik. This can
be useful in a scenario here you are running both traefik and traefik-kop side-by-side on the
same host.
services:
nginx:
labels:
- "traefik.enable=true"
- "traefik.http.routers..."
- "traefik..."
becomes
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- "REDIS_ADDR=192.168.1.50:6379"
- "BIND_IP=192.168.1.75"
- "DOCKER_PREFIX=kop.public"
nginx:
labels:
- "kop.public.traefik.enable=true"
- "kop.public.traefik.http.routers..."
- "kop.public.traefik..."
Docker API
traefik-kop expects to connect to the Docker host API via a unix socket, by
default at /var/run/docker.sock. The location can be overridden via the
DOCKER_ADDR env var or --docker-host flag.
Other connection methods (like ssh, http/s) are not supported.
By default, traefik-kop will listen for push events via the Docker API in
order to detect configuration changes. In some circumstances, a change may not
be pushed correctly. For example, when using healthchecks in certain
configurations, the start -> healthy change may not be detected via push
event. As a failsafe, there is an additional polling mechanism to detect those
missed changes.
The default interval of 60 seconds should be light so as not to cause any
issues, however it can be adjusted as needed via the KOP_POLL_INTERVAL env var
or set to 0 to disable it completely.
Traefik Docker Provider Config
In addition to the simple --docker-host setting above, all Docker Provider
configuration
options
are available via the --docker-config <filename.yaml> flag which expects
either a filename to read configuration from or an inline YAML document.
For example:
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
REDIS_ADDR: "172.28.183.97:6380"
BIND_IP: "172.28.183.97"
DOCKER_CONFIG: |
---
docker:
defaultRule: Host(`{{.Name}}.foo.example.com`)
Redis TTL
Set REDIS_TTL (or --redis-ttl) to a positive number of seconds to expire
published configuration when traefik-kop stops renewing it. The default, 0,
disables expiration.
While running, traefik-kop renews its published keys every one-third of the TTL,
even when the configuration is unchanged. This timer is independent of
KOP_POLL_INTERVAL, so renewal also works when Docker polling is disabled (0)
or the TTL is shorter than the poll interval. For example, REDIS_TTL=300
renews keys every 100 seconds. Choose a TTL that leaves enough time for temporary
Redis connectivity failures and scheduling delays; keys can still expire if
renewal cannot reach Redis before the TTL elapses.
Use a unique KOP_HOSTNAME for each instance. Configuration names in Redis are
shared: if multiple instances publish the same router, service, or middleware
keys, any of those instances can renew them. TTL is not per-node health checking
for servers combined with kop.merge-lbs.
Redis Sentinel
If your Redis setup uses Sentinel
for high availability, you can configure traefik-kop to connect through
Sentinel instead of directly to a Redis instance. This ensures traefik-kop
always writes to the current master, even after a failover.
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- "REDIS_SENTINEL_ADDRS=sentinel1:26379,sentinel2:26379,sentinel3:26379"
- "REDIS_SENTINEL_MASTER=mymaster"
- "BIND_IP=192.168.1.75"
When Sentinel is configured, the --redis-addr flag is ignored.
Both --redis-sentinel-addrs and --redis-sentinel-master must be provided
together. The --redis-user, --redis-pass, and --redis-db flags still apply
and are used for authenticating with the Redis master discovered by Sentinel.
Redis TLS
To connect to a TLS-only Redis (optionally requiring client certificates),
enable REDIS_TLS and point at the PEM files. The server certificate is
verified by default against REDIS_TLS_CA (or the system roots if unset).
services:
traefik-kop:
image: "ghcr.io/jittering/traefik-kop:latest"
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./certs:/certs:ro
environment:
- "REDIS_ADDR=redis.example.com:6380"
- "REDIS_USER=kop"
- "REDIS_PASS=secret"
- "REDIS_TLS=true"
- "REDIS_TLS_CA=/certs/ca.pem"
# mutual TLS (both required together)
- "REDIS_TLS_CERT=/certs/client.pem"
- "REDIS_TLS_KEY=/certs/client.key"
# only if the address does not match a name/IP in the server certificate
# - "REDIS_TLS_SERVER_NAME=redis.example.com"
- "BIND_IP=192.168.1.75"
Invalid or unreadable certificate files cause traefik-kop to exit at startup.
REDIS_TLS_INSECURE_SKIP_VERIFY disables server verification and should be
avoided. TLS settings also apply when using Sentinel.
Releasing
To release a new version, simply push a new tag to github.
git push
git tag -a v0.11.0
git push --tags
To update the changelog:
make update-changelog
# or (replace tag below)
docker run -it --rm -v "$(pwd)":/usr/local/src/your-app \
githubchangeloggenerator/github-changelog-generator \
-u jittering -p traefik-kop --output "" \
--since-tag v0.10.1
License
traefik-kop: MIT, (c) 2015, Pixelcop Research, Inc.
traefik: MIT, (c) 2016-2025 Containous SAS; 2020-2022 Traefik Labs
Requirements
Categories
Related apps
Explore more like this
Explore allDetails
ghcr.io/jittering/traefik-kop:latestRuntime arguments
- Network
docker- Shell
bash- Privileged
- false
Template configuration
Docker Socket (read-only) access to find the docker containers and labels automatically..
- Target
- /var/run/docker.sock
- Default
- /var/run/docker.sock
- Value
- /var/run/docker.sock
Hostname to identify this node in redis
- Default
- foo
- Value
- foo
Redis address
- Default
- 192.168.222.11:6379
- Value
- 192.168.222.11:6379
IP address to bind services to
- Default
- 192.168.222.99
- Value
- 192.168.222.99
Redis user
- Default
- default
- Value
- default
Redis password (if needed, delete if not)
Redis DB number
- Default
- 0
- Value
- 0
Redis TTL (in seconds)
- Default
- 0
- Value
- 0
Poll interval for refreshing container list
- Default
- 60
- Value
- 60