10K+
This image contains a simple load balancer made on top of Caddy v2 using its reverse_proxy directive. If you are unfamiliar with Caddy webserver, check their website
This image is automatically updated every week and is maintained by ReDemoNBR and rdnxk. It is not maintained by Caddy
The motivation of this project is to create a simple load balancer that can be easily used as a Load Balancer utility in Docker Compose or in CI/CD pipelines.
We have some environment variables that are used for running the load balancer and some that are directly passed to Caddy's reverse_proxy directive configuration.
SLB_FROM_HOST: (required). Name of the host that will act as the load balancer distributing the connections over the upstream hostsSLB_TO_UPSTREAMS: (required). Names or addresses of the upstream hosts that will handle the final connections from the load balancerSLB_FORMAT_CADDYFILE: (optional). Format and prettify the generated Caddyfile before starting the load balancer. It is activated if it is set to 1 or true. Default value is 1SLB_VALIDATE_CADDYFILE: (optional). Validate the generated Caddyfile before starting the load balancer. It is activated if it is set to 1 or true. Default value is 1SLB_EXPOSE_PORT: (optional). Port to expose. Default is 9000These variables can be used to customize the underlying Caddy Reverse Proxy behavior. They can be used to change the load balancing policy algorithms, to set active or passive health checks, or to add/remove headers upstream or downstream.
SLB_LB_POLICY: lb_policySLB_LB_TRY_DURATION: lb_try_durationSLB_LB_TRY_INTERVAL: lb_try_intervalSLB_HEALTH_URI: health_uriSLB_HEALTH_PORT: health_portSLB_HEALTH_INTERVAL: health_intervalSLB_HEALTH_STATUS: health_statusSLB_HEALTH_BODY: health_bodySLB_HEALTH_HEADERS: health_headers. Format: key and values are split by an equal (=) sign, key-value sets are separated by comma. Ex: field1=value1,field2=value2,field3=value3SLB_FAIL_DURATION: fail_durationSLB_MAX_FAILS: max_failsSLB_UNHEALTHY_STATUS: unhealthy_statusSLB_UNHEALTHY_LATENCY: unhealthy_latencySLB_UNHEALTHY_REQUEST_COUNT: unhealthy_request_countSLB_FLUSH_INTERVAL: flush_intervalSLB_BUFFER_REQUESTS: buffer_requests. It is activated if it is set to 1 or trueSLB_BUFFER_RESPONSES: buffer_responses. It is activated if it is set to 1 or trueSLB_MAX_BUFFER_SIZE: max_buffer_sizeSLB_HEADER_UP: header_up. Format: key and values are split by an equal (=) sign, key-value sets are separated by comma. Ex: field1=value1,field2=value2,field3=value3. Just like in Caddy's docs, you can use +|- to add or remove headersSLB_HEADER_DOWN: header_down. Format: key and values are split by an equal (=) sign, key-value sets are separated by comma. Ex: field1=value1,field2=value2,field3=value3. Just like in Caddy's docs, you can use +|- to add or remove headersUsing Simple Load Balancer to balance load for a MinIO (an open-source S3-compliant file storage service) with erasure code on 4 different hosts with 2 disks in each.
MinIO will be running the service on port 9000 and the console (web browser) on port 9001. So we will open 2 load balancers, one for the service on port 9000 and another for the console on port 9001
# template for minio services
x-minio-common: &minio-common
image: minio/minio:latest
command: ["server", "--address", ":9000", "--console-address", ":9001", "http://minio{1...4}/data{1...2}"]
environment:
MINIO_ROOT_USER: root-user
MINIO_ROOT_PASSWORD: my-sekrit-password
ports:
- "9000"
- "9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
services:
minio1:
<<: *minio-common
volumes:
- s3-1-1:/data1
- s3-1-2:/data2
minio2:
<<: *minio-common
volumes:
- s3-2-1:/data1
- s3-2-2:/data2
minio3:
<<: *minio-common
volumes:
- s3-3-1:/data1
- s3-3-2:/data2
minio4:
<<: *minio-common
volumes:
- s3-4-1:/data1
- s3-4-2:/data2
minio-service-loadbalancer:
image: redemonbr/simple-load-balancer:latest
environment:
SLB_FROM_HOST: ":9000"
SLB_TO_UPSTREAMS: minio1:9000,minio2:9000,minio3:9000,minio4:9000
SLB_LB_POLICY: round_robin
SLB_LB_TRY_DURATION: 1s
SLB_LB_TRY_INTERVAL: 250ms
SLB_EXPOSE_PORT: 9000
depends_on:
- minio1
- minio2
- minio3
- minio4
ports:
- "9000:9000"
minio-console-loadbalancer:
image: redemonbr/simple-load-balancer:latest
environment:
SLB_FROM_HOST: ":9001"
SLB_EXPOSE_PORT: 9001
SLB_TO_UPSTREAMS: minio1:9001,minio2:9001,minio3:9001,minio4:9001
SLB_LB_POLICY: round_robin
SLB_LB_TRY_DURATION: 1s
SLB_LB_TRY_INTERVAL: 250ms
depends_on:
- minio1
- minio2
- minio3
- minio4
ports:
- "9001:9001"
volumes:
s3-1-1: {}
s3-1-2: {}
s3-2-1: {}
s3-2-2: {}
s3-3-1: {}
s3-3-2: {}
s3-4-1: {}
s3-4-2: {}
Using K6 load testing tool for testing an application with 3 replicas that will run on port 5566. Consider that the application will have an endpoint at /health for active healthchecking that returns HTTP status 200 if OK and will be checked at every 500ms. The Simple Load Balancer will be set to run on port 12345 in this example.
load-testing:
stage: test
image:
- name: loadimpact/k6:0.34.1
entrypoint: ["/bin/sh", "-c"]
services:
- name: my-app-container:latest
alias: api-replica-1
- name: my-app-container:latest
alias: api-replica-2
- name: my-app-container:latest
alias: api-replica-3
- name: redemonbr/simple-load-balancer:latest
alias: api-lb
variables:
SLB_EXPOSE_PORT: 12345
SLB_FROM_HOST: ":12345" ## it will listen on port "12345"
SLB_TO_UPSTREAMS: api-replica-1:5566,api-replica-2:5566,api-replica-3:5566
SLB_LB_POLICY: round_robin
SLB_HEALTH_URI: /health
SLB_HEALTH_STATUS: 200
SLB_HEALTH_INTERVAL: 500ms
script:
## tests with 1000 virtual users for 20s on address "api-lb:12345" which is the load balance address
- k6 run --vus 1000 --duration 20s --address api-lb:12345 load-test.js
artifacts:
name: shiftleft-$CI_COMMIT_SHORT_SHA
paths:
- shiftleft.md
expire_in: 7 days
public: false
As mentioned before, this image has the objective to be a simple load balancer and it is built on top of Caddy v2. So it has some limitations, then please read them below.
SLB_TO_UPSTREAMS, SLB_HEALTH_HEADERS, SLB_HEADER_UP and SLB_HEADER_DOWN environment variablesWe use comma-separated values in SLB_TO_UPSTREAMS, SLB_HEADER_UP and SLB_HEADER_DOWN environment variables, so the commas are already used as delimiters for the values.
This means that if any of the upstream addresses (or header keys or header values) contain a comma, then the values will be split there and cause an unwanted behavior.
So please, double check if the addresses, header keys or header values contain commas.
This image disables by default the admin API in Caddy's global options. This is to avoid exposing an API that is able to change the configuration
All other global options remain unchanged, intentionally for loading default configurations. This means that this image does not provide an easy interface for you to:
The transport and handle_response keywords are not set by this image so they remain with the default behavior.
Also, intercepting responses is not supported.
Content type
Unrecognized
Digest
sha256:f81d04ba9…
Size
416.7 kB
Last updated
1 day ago
docker pull redemonbr/simple-load-balancer:sha256-eb7f274194e2f16954b227132e28d3d062b50e7c6265dcb60ad3ddc0bf257862.sbom