Flexible HAProxy auto configuration and auto service discovery for SkyDNS or Mesos-DNS
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.gitignore
Dockerfile
LICENSE
README.md
haproxy.cfg.template
package.json
start.js

README.md

HAProxy SRV

HAProxy-SRV is a templating solution that can flexibly reconfigure HAProxy based on the regular polling of the service data from DNS (e.g. SkyDNS or Mesos-DNS) using SRV records.

HAProxy-SRV also works with Round-Robin DNS A records, like Docker Swarm Mode.

It has a very simple logic - HA Proxy is configured based on the Handlebars template that is re-evaluated every time changes in DNS are detecting. Script is polling DNS and trigger a HA Proxy configuration refresh after changes.

Made by elastic.io in Germany.

Quick start

Simplest way to start it with Docker:

docker run -d -p 8080:8080 -p 80:80 -v $PWD/haproxy.cfg.template:/src/haproxy.cfg.template elasticio/haproxy-srv:latest

if you want to see more DEBUG output then just add -e "DEBUG=*"

How it works

Script works very simple - after docker container started script parse and validates template, create a HAProxy configuration file in /src/haproxy.cfg and start HAProxy as a daemon. Every second (by default, can be configured via REFRESH_TIMEOUT env variable, default 1000) scirpt will execute a DNS lookup and re-evaluate the template, if result of evaluation is different from original configuration, original config will be overwritten and HAProxy reload will be triggered. HAProxy reload will not affect existing connections.

How to use it

Recommended way to deploy is is to use a Docker image. You would need to place your configuration file template, the simples way to do it is to build an image based on haproxy-srv image.

Create a new Dockerfile content like this:

FROM elasticio/haproxy-srv:latest

COPY haproxy.cfg.template /src/

EXPOSE 80 8880

Note the EXPOSE part here, don't forget to specify exposed ports if your HAProxy configuration listens on any port different from 80.

As a next step create a template file, it should be placed under /src/haproxy.cfg.template in resulting Docker container and should have a Handlebars syntax with one little extension (see below). Here is the sample:

global
    user root
    group root

    # Stats required for this module to work
    # https://github.com/observing/haproxy#haproxycfg
    stats socket /tmp/haproxy.sock level admin

defaults
    mode    http
    timeout connect 5000
    timeout client  50000
    timeout server  50000

{{#dns-srv "_frontend._tcp.marathon.mesos"}}
    frontend sample
        bind 0.0.0.0:80
        balance roundrobin
        option http-server-close
        option forwardfor
        {{#each this}}
            server frontend-{{@index}} {{ip}}:{{port}} check weight {{weight}}
        {{/each}}
{{/dns-srv}}

# Standard DNS Round-Robin
{{#dns-a "cluster.example.com"}}
  frontend sample2
    bind 0.0.0.0:8080
    {{#each this}}
      server {{name}} {{ip}}:80 check
    {{/each}}
{{/dns-a}}

# Docker Swarm Mode example
{{#dns-a "tasks.myservice"}}
  frontend sample3
    bind 0.0.0.0:8081
    {{#each this}}
      server {{name}} {{ip}}:80 check
    {{/each}}
{{/dns-a}}

It could be any valid HAProxy configuration with one mandatory addition:

stats socket /tmp/haproxy.sock level admin

to trigger HAProxy restart the script inside the file will communicate with HAProxy daemon via socket /tmp/haproxy.sock.

Template

Configuration template is a normal Handlebars so that you could use any of the feature of this template language. There is however one additional helper dns-srv implemented. This helper takes one string parameter and will execute a DNS SRV lookup to fetch an SRV record(s). After SRV Record lookup, for each SRV record a DNS resolution to find the IP will be made.

This template will give you an idea how to use it:

# Your usual configuration is here
{{#dns-srv "_frontend._tcp.marathon.mesos"}}
    # This block will only be rendered when _frontend._tcp.marathon.mesos was found in DNS
    {{#each this}}
        # This piece will be rendered for each SRV entry from DNS
        SRV Name is {{name}}
        SRV Weight is {{weight}}
        SRV Port is {{port}}
        IP for SRV Name is {{ip}}
    {{/each}}
{{/dns-srv}}
# rest of your configuration

Typical use-case for Msos-DNS you can see above.

Docker Swarm Mode Guide

First, create a network, and web service:

$ docker network create -d overlay --subnet 10.1.1.0/24 my_net
$ docker service create --replicas 2 --name my_web --network my_net nginx

By default, services are created as --endpoint-mode vip. If you use VIP mode, then the Round-Robin DNS name is tasks.my_web. If you use --endpoint-mode dnsrr then the my_web DNS name will work in the HAProxy dns-a template.

Follow the How to use it section above on creating a new proxy image using a custom haproxy.cfg.template. For the dns-a section use:

{{#dns-a "tasks.my_web"}}
  # other configs
  backend my_web
  {{#each this}}
    server {{name}} {{ip}}:80 check
  {{/each}}
{{/dns-a}}
$ mkdir my_proxy ; cd my_proxy
#  (make a new Dockerfile)
$ docker build -t my_proxy_image .

Fire up a new proxy, publishing port 80 to something unique on each docker host node

$ docker service create --name my_proxy --network my_net -p 8081:80 my_proxy_image

Optionally, use some other method for sharing & binding the haproxy.cfg.template file into the elasticio/haproxy-srv image.

Debugging

Just set the DEBUG environment variable into * to see detailed logging.

TODOs

PRs are welcome for

  • Bug fixes
  • Unit tests
  • Gulp or Grunt-based builds
  • CircleCI config for continous integration