traefik-kop

repository·main·Indexed 19 days ago

https://github.com/jittering/traefik-kop

A discovery agent that bridges Docker containers on multiple hosts to a central Traefik instance using Redis as a shared state provider. It reads container labels from local Docker nodes and publishes them to Redis, allowing Traefik to route traffic to services on remote nodes in non-Swarm/Kubernetes multi-host Docker clusters.

Tokens
9.2K
Snippets
22
Records
38
Agent score
67%

What's inside traefik-kop

  1. Configure Service Port Binding

    main

    By default, traefik-kop picks up the service port from the container's port bindings if only one port is exposed.

    Example (Auto-detection):

    services:
      nginx:
        ports:
          - 8088:80

    In this case, 8088 is automatically used as the service endpoint port.

    Manual Configuration (Required for multiple ports or network_mode: host): If you have multiple ports or are using host networking, you must explicitly tell Traefik which host-side port to connect to using the loadbalancer.server.port label.

    Crucial Note: You must point Traefik to the host port (e.g., 8088), not the internal container port (e.g., 80), so that Traefik can reach the service over the network.

    services:
      nginx:
        network_mode: host
        ports:
          - 8088:80
          - 8888:81
        labels:
          - "traefik.http.services.nginx.loadbalancer.server.port=8088"
  2. Target containers using Namespaces

    main

    You can restrict traefik-kop to only manage specific containers by using namespaces. This is achieved by configuring a NAMESPACE in the traefik-kop environment and applying a kop.namespace label to your target services.

    • Multiple Namespaces: You can provide a comma-delimited list of namespaces in the NAMESPACE environment variable. A container is included if at least one of its labels matches one of the configured namespaces.
    • Label Matching: A container is included if its kop.namespace label contains any of the namespaces defined in the traefik-kop configuration.
    # traefik-kop configuration
    services:
      traefik-kop:
        image: "ghcr.io/jittering/traefik-kop:latest"
        environment:
          - "NAMESPACE=dev,staging"
    
    # Target service configuration
    services:
      nginx:
        labels:
          - "kop.namespace=staging"
  3. How traefik-kop works

    main

    traefik-kop is a discovery agent designed for multi-host Docker clusters (non-Swarm/Kubernetes) to allow a single central Traefik instance to route traffic to services running on remote nodes.

    It works by:

    1. Reading container labels from the local Docker node.
    2. Publishing those labels to a shared redis instance.
    3. Allowing a central Traefik instance (configured with a redis provider) to discover these remote services via Redis.

    This architecture enables Traefik to treat remote Docker containers as if they were local, using the host's IP address to reach them across the network.

  4. Use Namespace via Label Prefix

    main

    If you are running both traefik and traefik-kop on the same host, you can prevent them from conflicting by using a custom label prefix.

    By setting the DOCKER_PREFIX environment variable in traefik-kop, you turn it into an inclusion filter for its own labels and an exclusion filter for standard traefik labels. All Traefik-related labels on your services must then be prefixed with this value.

    services:
      traefik-kop:
        image: "ghcr.io/jittering/traefik-kop:latest"
        environment:
          - "DOCKER_PREFIX=kop.public"
    
      nginx:
        labels:
          - "kop.public.traefik.enable=true"
          - "kop.public.traefik.http.routers..."
  5. Configure IP Binding for remote services

    main

    Because Traefik is running on a different host, it must connect to services using the host's IP address rather than the internal Docker network IP.

    Precedence for determining the Bind IP

    1. kop.<service name>.bind.ip label
    2. kop.bind.ip label
    3. Container networking IP (overridden by traefik.docker.network label)
    4. --bind-ip CLI flag (or BIND_IP env var)
    5. --bind-interface CLI flag (or BIND_INTERFACE env var) — requires network_mode: host
    6. Auto-detected host IP

    Methods of setting the IP

    Using Environment Variables

    Set BIND_IP to the host's IP address. If you prefer to derive the IP from a specific interface (e.g., eth0), use BIND_INTERFACE. Note that using an interface requires the container to run with network_mode: host.

    Using Docker Labels

    You can specify the IP directly on a per-service or per-container basis using labels:

    • kop.<service name>.bind.ip=2.2.2.2
    • kop.bind.ip=2.2.2.2 (applies to all services in the container)

    Disabling Auto-detection

    If you are using a global overlay network and want Traefik to handle IP/port detection natively, disable traefik-kop's replacement logic using the --skip-replace flag or SKIP_REPLACE=1 environment variable.

  6. Set up traefik-kop for multi-host discovery

    main

    To implement multi-host discovery, follow these three steps:

    1. Configure Traefik

    Configure your central Traefik instance to use the redis provider. Ensure it points to the same Redis instance that your traefik-kop agents will use.

    providers:
      redis:
        endpoints:
          - "redis:6379"

    2. Deploy traefik-kop on remote nodes

    Run traefik-kop on every node where you want to host services. It requires access to the local docker.sock and connection details for the central Redis instance.

    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"

    3. Label your target services

    Add standard Traefik labels to your services. If you have multiple ports or use network_mode: host, you must explicitly define the host-side port in the Traefik service configuration so Traefik knows which port to hit on the remote host.

    services:
      nginx:
        image: "nginx:alpine"
        restart: unless-stopped
        ports:
          - 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"
          - "traefik.http.services.nginx.loadbalancer.server.scheme=http"
          - "traefik.http.services.nginx.loadbalancer.server.port=8088"
  7. Merge Load Balancers across nodes

    main

    If a service is running on multiple nodes and you want Traefik to load balance across all of them, add the following label to your container:

    • kop.merge-lbs=true

    When enabled, traefik-kop checks Redis for an existing service definition and appends the current node's address to the list.

    Warning: This is off by default. If a node's IP changes, the old (dead) IP will remain in the Redis list alongside the new one, which can cause traffic failures.

  8. How label filtering works in DockerProxyServer

    main

    The DockerProxyServer uses a labelPrefix to transform container labels. This is useful for providing a clean set of labels to Traefik while keeping the original Docker labels intact on the host.

    Filtering Logic:

    1. If a label key starts with the labelPrefix (e.g., kop.), the prefix is removed. The remaining part becomes the new key.
    2. If a label key does not start with the labelPrefix and does not start with traefik., the label is kept exactly as it is.
    3. Labels starting with traefik. are explicitly dropped (unless they also match the prefix).

    Example: If labelPrefix is kop.:

    • kop.traefik.http.router.rule becomes traefik.http.router.rule (Wait, actually the logic says: if it matches prefix, strip it. If it doesn't match prefix AND doesn't start with traefik., keep it. Therefore, kop.traefik... becomes traefik..., but then the else if check for traefik. is skipped.

    Correction based on code logic:

    • kop.my-label $\rightarrow$ my-label
    • other-label $\rightarrow$ other-label
    • traefik.something $\rightarrow$ (dropped)
    • kop.traefik.something $\rightarrow$ traefik.something (because the first if matches, the else if is never evaluated).
  9. Use `traefik.docker.network` for CNI-based routing

    main

    If your containers use a CNI plugin (like Calico or Weave) that provides routable IP addresses, you can instruct traefik-kop to use the container's network IP instead of the host IP.

    Requirement:

    • Add the label traefik.docker.network=<network_name> to your container.

    traefik-kop will then look up the IP address assigned to the container within that specific network and use it for the service endpoint.

  10. How PollingProvider manages concurrent polling attempts

    main

    The PollingProvider ensures that only one polling attempt is active at a time using a cancellation mechanism.

    When startPollAttempt is triggered by a ticker:

    1. It acquires a mutex lock.
    2. It calls the existing activeAttemptCancel() function to signal the previous attempt's context to cancel.
    3. It stops the previous activeAttempt pool.
    4. It increments an attemptNumber and starts a new safe.Pool with a new cancellable context.

    This prevents multiple concurrent polling cycles from flooding the configurationChan if the upstream provider takes longer to respond than the refreshInterval.

  11. Configure Docker API connection

    main

    By default, traefik-kop connects to the Docker host API via the unix socket at /var/run/docker.sock.

    • Override Socket: Use the DOCKER_ADDR environment variable or the --docker-host flag to specify a different socket location.
    • Note: Connection methods like ssh or http/s are not supported.
    • Polling: traefik-kop listens for Docker push events to detect changes. As a failsafe, it uses a polling mechanism. You can adjust the polling interval using KOP_POLL_INTERVAL (default is 60 seconds) or set it to 0 to disable polling.
  12. Filter services by namespace using `kop.namespace` labels

    main

    Traefik-kop can filter which services and routers are included in the final configuration based on Docker container labels.

    Logic:

    • If no namespaces are configured in the Config, all containers are kept.
    • If namespaces are configured, a container is only kept if its kop.namespace label matches one of the configured namespaces.

    This is implemented via the keepContainer and filterServices functions.