4
votes

I am attempting to perform load-balancing with HAProxy with services registered in Consul, using Consul's DNS SRV records.

My Consul DNS is properly configured to resolve the following:

$ dig my-service.service.consul SRV

...

;; ANSWER SECTION:
my-service.service.consul. 0 IN SRV 1 1 8000 node1.node.dc.consul.

;; ADDITIONAL SECTION:
node1.node.dc.consul. 10 IN A   X.X.X.X
node1.node.dc.consul. 10 IN TXT "consul-network-segment="

And also with a Consul prepared query:

$ dig geo-my-service.query.consul SRV

...

;; ANSWER SECTION:
geo-my-service.query.consul. 10 IN SRV 1 1 8000 node1.node.dc.consul.

;; ADDITIONAL SECTION:
node1.node.dc.consul. 10 IN A   X.X.X.X
node1.node.dc.consul. 10 IN TXT "consul-network-segment="

I successfully configured the barebone service query in HAProxy with the following block:

backend my-service

    balance roundrobin
    server-template my-service-api 1 _my-service._tcp.service.consul check resolvers consul

However, when I use the Consul prepared query, I get a Socket error: No port available for the TCP connection error on the given service in HAProxy:

backend companion_authnz

    balance roundrobin
    server-template my-service-api 1 _geo-my-service._tcp.query.consul check resolvers consul

I cannot find any information in neither HAProxy nor Consul documentation about resolving prepared queries in HAProxy.

Has anyone ever had experience with Consul prepared queries and plugging them in HAProxy using SRV records?

I am using Consul 1.1.0 and HAProxy 1.8.9. Thanks!

EDIT:

I successfully plugged a prepared query in HAProxy by using A records and specifying the service port in the config file:

backend my-service

    balance roundrobin
    server-template my-service-api 1 geo-my-service.query.consul:8000 check resolvers consul

However, that would be nice to use SRV records in order for the port to be dynamically resolved by HAProxy.

1

1 Answers

3
votes

Ok I figured it out.

First of all, the service (_my-service._tcp.service.consul) resolution is expected, as stated in this section of Consul's DNS interface documentation. Consul's DNS is configured to resolve services with this form (RFC 2782):

_service._protocol[.service][.datacenter][.consul]

This is why _my-service._tcp.service.consul was working properly.

However, my prepared query was also configured to match this regex: ^geo-(.*?)$, so when I was running dig _geo-my-service._tcp.query.consul, it wasn't matchin the regex, thus no resolution. That explains why I couldn't resolve the prepared query while respecting the RFC 2782 standard address.

That being said, HAProxy requires an RFC 2782 compliant address to resolve a SRV record. To deal with these constraints, I had to do two changes to my setup:

  1. I changed my prepared query regex to ^_geo-(.*?)$ so the RFC 2782 address would match
  2. I omitted the protocol (._tcp.) in the HAProxy configuration file so that Consul would find the query

Here are the results:

$ dig _geo-my-service.query.consul SRV

...

;; ANSWER SECTION:
_geo-my-service.query.consul. 10 IN SRV 1 1 8000 node1.node.dc.consul.

;; ADDITIONAL SECTION:
node1.node.dc.consul. 10 IN A   X.X.X.X
node1.node.dc.consul. 10 IN TXT "consul-network-segment="

And for the HAProxy configuration:

backend my-service

    balance roundrobin
    server-template my-service-api 1 _geo-my-service.query.consul check resolvers consul

In conclusion, I think that this behavior is a bit odd and that RFC 2782 standard should work the same for both Consul services and prepared queries.