SkillAgentSearch skills...

Millau

Ingress proxy and load balancer designed for microservice architectures built on Docker Swarm

Install / Use

/learn @codelev/Millau
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Millau

Millau (pronounced mijo) is a free ingress proxy and load balancer designed for microservice architectures built on Docker Swarm.

Millau

Traditional proxies require configuration for each path and host, and must be restarted to apply changes. Modern proxies listen to Docker events and configure routes automatically. While traditional proxies store configuration files on mounted volumes, modern proxies store routes in memory. However, modern proxies do not support load balancing across services - Millau does.

Millau

  • Listens to Docker events for zero restarts
  • Failover retries for guaranteed delivery
  • Written in Golang and available as a slim Docker image

Comparison

| Product | Configuration | Multi-service LB | Service discovery | Prometheus metrics | Automatic HTTPS | mTLS | Image size, MB | |------------|---------------|------------------|-------------------|--------------------|-----------------|---------|----------------| | NGINX | File | Yes | No | No | No | Yes | 192 | | HAProxy | File | Yes | No | Yes | No | Yes | 105 | | Envoy | File | Yes | No | Yes | No | Yes | 191 | | Caddy | File | Yes | No | Yes | Yes | Yes | 49 | | Traefik | Labels | No | Yes | Yes | Yes | Yes | 224 | | Millau | Labels | Yes | Yes | Yes | Yes | Yes | 33 |

Performance

| Product | Test type | Avg response (ms) | Shortest response (ms) | |------------|-----------------------------------|-------------------|------------------------| | NGINX | GET application/json | 2.45 | 1.73 | | HAProxy | GET application/json | 2.99 | 1.93 | | Caddy | GET application/json | 2.80 | 1.66 | | Traefik | GET application/json | 2.66 | 1.53 | | Millau | GET application/json | 2.76 | 1.74 | | NGINX | POST application/octet-stream 5Mb | 32.24 | 29.27 | | HAProxy | POST application/octet-stream 5Mb | 23.12 | 20.69 | | Caddy | POST application/octet-stream 5Mb | 23.81 | 20.98 | | Traefik | POST application/octet-stream 5Mb | 23.35 | 21.04 | | Millau | POST application/octet-stream 5Mb | 22.86 | 20.53 |

Quickstart

  1. Create docker-compose.proxy.yml:
    services:
      proxy:
        image: codelev/millau:latest
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
        ports:
          - "8080:80"
        networks:
          - millau
    networks:
      millau:
        external: true
    
  2. Create docker-compose.service.yml:
    services:
      whoami:
        image: traefik/whoami
        deploy:
          mode: replicated
          replicas: 3
          labels:
            - "millau.enabled=true"
            - "millau.port=80"
        ports:
          - "80"
        networks:
          - millau
    networks:
      millau:
        external: true
    
  3. Create network: docker network create --driver=overlay millau
  4. Deploy proxy: docker stack deploy -c docker-compose.proxy.yml proxy
  5. Deploy service: docker stack deploy -c docker-compose.service.yml service

Use Cases

Blue-Green

docker stack deploy -c docker-compose.bluegreen.yml bluegreen
curl -i -H 'Host: company.com' localhost:8080/api/
# HTTP 200 blue or green
curl -i -H 'Host: www.company.com' localhost:8080/api/
# HTTP 200 blue or green
curl -i -H 'Host: green.local' localhost:8080/api/
# HTTP 200 green
curl -i -H 'Host: blue.local' localhost:8080/api/
# HTTP 200 blue
curl -i -H 'Host: company.locall' localhost:8080
# HTTP 502 No matching services found
curl -i -H 'Host: company.local' localhost:8080/apii/
# HTTP 502 No matching services found
curl -k --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/
# HTTP 200 blue or green
curl -k --http2 --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 -H 'Host: company.local' https://company.local:8443/api/
# HTTP 200 blue or green
docker stack rm bluegreen

Ingress

docker stack deploy -c docker-compose.ingress.yml ingress
curl -i localhost:8080
# HTTP 200 backend
docker stack rm ingress

Failover

docker stack deploy -c docker-compose.failover.yml failover
curl localhost:8080/rest/echo
# HTTP 200
docker stack rm failover

Maintenance Mode

docker stack deploy -c docker-compose.spa.yml spa
curl -H 'Host: company.com' localhost:8080
# homepage
docker service scale spa_homepage=0
curl -H 'Host: company.com' localhost:8080
# maintenance page
docker service scale spa_homepage=1
curl -H 'Host: company.com' localhost:8080
# homepage
docker stack rm spa

Docker Compose

docker compose up -d
curl -i localhost:8080/rest/echo
# HTTP 200
curl -k --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 https://company.local:8443/rest/echo
curl -k --http2 --resolve company.local:8443:127.0.0.1 --connect-to company.local:8443 https://company.local:8443/rest/echo
# HTTP 200
docker compose down

Telemetry

Millau exposes the following endpoints on port 9100:

  • Healthcheck /:
    • responds up and 200 OK when healthy,
    • responds down and 503 Service Unavailable when unhealthy.
  • Prometheus metrics /metrics:

| Metric | Description | |----------------------------------------|----------------------------------------------------------| | Ingress | | | millau_ingress_open_connections | The current count of open connections by port. | | millau_ingress_requests_total | The total count of requests received by port. | | millau_ingress_requests_bytes_total | The total size of requests in bytes handled by port. | | millau_ingress_responses_bytes_total | The total size of responses in bytes handled by port. | | Load Balancer | | | millau_lb_successful_requests_total | The total count of requests handled by service. | | millau_lb_failed_requests_total | The total count of requests not handled by service. | | millau_lb_requests_bytes_total | The total size of requests in bytes handled by service. | | millau_lb_responses_bytes_total | The total size of responses in bytes handled by service. | | millau_lb_retries_total | The count of retries made for service. | | millau_lb_status | Current service status, 0 for down or 1 for up. | | millau_lb_request_duration_seconds | Request handling histogram by service. | | millau_topology | Requests routed to services. |

Millau has an official Grafana dashboard. You can try it out locally using the docker-compose.yml, which sets up Millau, Echo service, Prometheus and Grafana together.

Grafana Grafana Grafana

Once the stack is running, log in Grafana at http://localhost:3000 with username admin and password admin. The millau.json is already installed and ready to use.

Configuration

Logging Levels

  • FATAL: Indicates an unrecoverable error; the process will exit.
  • ERROR: Indicates a proxy failure; the process continues running.
  • WARN: Indicates client or microservice misbehavior; the process continues running.
  • INFO: Indicates normal functional behavior. Default level.
  • DEBUG: Indicates step‑by‑step functional behavior.
services:
  proxy:
    image: codelev/millau:latest
     environment:
       - LOGGING=DEBUG
     ...

HTTP and HTTPS Ports

By default, the HTTP and HTTPS ports are 80 and 443. You can change them as follows:

services:
  proxy:
    image: codelev/millau:latest
     environment:
       - HTTP=8080
       - HTTPS=8443
     ...

Automatic HTTPS

By default, ACME API is https://api.buypass.com/acme/directory (Buypass AS Certificate Authority, Norway). You can change is as follows:

services:
  proxy:
    image: codelev/millau:latest
     environment:
       - ACME=https://acme-v02.api.letsencrypt.org/directory
     ...

HTTP Host Matching

The matching logic selects the services whose millau.hosts label matches the domain hierarchy. It prioritizes:

  • exact matches,
  • longest suffix.

| Configured | Requested | Selected | |---------------------|-----------------|-----------| | one.com two.com | one.com | one.com | | one.com two.com | www.two.com | two.com | | one.com two.com | three.two.com | two.com | | one.com local | blue.local | local | | * two.com | two.com | two.com | | * two.com

View on GitHub
GitHub Stars29
CategoryDevelopment
Updated3d ago
Forks0

Languages

Java

Security Score

80/100

Audited on Apr 3, 2026

No findings