Use the HAProxy Data Plane API to dynamically control the load balancer configuration using HTTP commands.


Designing for high availability almost always means having a high proxy/load balancer. The proxy server provides basic services, such as:


  • detection and removal of faulty servers
  • connection queue
  • TLS encryption offload
  • compression
  • caching

The task is to keep your configurations up to date, which is especially difficult as services are moved to containers and these containers become ephemeral. Available from HAProxy 2.0 you can use the new HAProxy Data Plane API (Translation: https://habr.com/en/post/508132/ ), which is a modern REST API.


HAProxy Data Plane API complements the flexible language configuration HAProxy, which provides building blocks for defining simple and complex routing rules. It is also the perfect complement to the existing Runtime API that allows you to run, stop and pass traffic from servers, change server weight and manage health checks.


The new Data Plane API gives you the ability to dynamically add and configure external interfaces, internal interfaces, and traffic routing logic. You can also use it to update logging endpoints and create SPOE filters. In fact, almost the entire load balancer can be configured using HTTP commands. In this article, you'll learn how to use it better.


Configuration Management


Normally, when configuring HAProxy, you need to manually edit the CDMY0CDMY configuration file. This file is used to manage all the functions of the load balancer. It is mainly divided into CDMY1CDMY sections that define the public IP addresses to which clients connect, and CDMY2CDMY sections containing upstream servers to which traffic is directed. But you can do much more, including set global parameters that affect the working process, set default values, add traffic analysis using flash tables, read map files, define filtering rules using ACLs and much more.


Although editing a file manually is quite simple, it is not always advisable, especially when working with dozens or even hundreds of services and proxies. This allows all traffic to go from proxy to proxy, essentially abstracting the network and its inconsistency from related application services. Proxies at this level can add retry logic, authorization, and TLS encryption to your services. However, the number of proxies will grow rapidly, as each service has its own proxy.


In this case, it is extremely important to be able to call the HTTP API to dynamically update proxy definitions. In the service grid, Data Plane software controls proxies and dynamically invokes the configuration API. The HAProxy Data Plane API allows you to integrate HAProxy with these platforms. Moreover, the API uses the runtime API to make changes that, if possible, do not require a reboot.


The

Data Plane API uses Go packages config-parser and client-native to parse the HAProxy configuration and invoke the Runtime API commands, respectively. You can use them in your own projects to integrate with HAProxy.


HAProxy dynamic configuration


You can do a lot with the Data Plane API. In this section, you will learn how to create CDMY3CDMY with servers and CDMY4CDMY, which directs traffic to it.But first, follow the official documentation to install and configure the API.


After it is installed and running, call GET at the endpoint /v1/services/haproxy/configuration/backends to see the already defined CDMY5CDMY sections, for example:


$ curl --get --user admin:mypassword \ http://localhost:5555/v1/services/haproxy/configuration/backends 

If you want to add a new CDMY6CDMY, call the same endpoint using POST. There are two ways to make changes to this state — individual calls or batch commands within a transaction. Since we want to make some related changes, let's start by creating a transaction.


Call endpoint /v1/services/haproxy/transactions to create a new transaction. This will require a version parameter in the URL, but commands within the transaction do not need it. Whenever a POST, PUT, or DELETE command is called, a version must be included, which is then written to the HAProxy configuration file. This ensures that if multiple clients use the API, they will avoid conflicts. If the version you are submitting does not match the version specified in the configuration file, you will receive an error message. When using a transaction, this version is specified in advance when it is created.


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ http://localhost:5555/v1/services/haproxy/transactions?version=1 

You will find the transaction ID in the returned JSON document:


{"_version":5,"id":"9663c384-5052-4776-a968-abcef032aeef","status":"in_progress"} 

Then use endpoint /v1/services/haproxy/configuration/backends to create a new backend by sending the transaction ID as a URL parameter:


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "test_backend", "mode":"http", "balance": {"algorithm":"roundrobin"}, "httpchk": {"method": "HEAD", "uri": "/", "version": "HTTP/1.1"}}' \ http://localhost:5555/v1/services/haproxy/configuration/backends?transaction_id=9663c384-5052-4776-a968-abcef032aeef 

Then call endpoint /v1/services/haproxy/configuration/servers to add the servers to CDMY7CDMY:


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "server1", "address": "127.0.0.1", "port": 8080, "check": "enabled", "maxconn": 30, "weight": 100}' \ "http://localhost:5555/v1/services/haproxy/configuration/servers?backend=test_backend&transaction_id=9663c384-5052-4776-a968-abcef032aeef" 

Then add CDMY8CDMY using endpoint /v1/services/haproxy/configuration/frontends :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "test_frontend", "mode": "http", "default_backend": "test_backend", "maxconn": 2000}' \ http://localhost:5555/v1/services/haproxy/configuration/frontends?transaction_id=9663c384-5052-4776-a968-abcef032aeef 

This CDMY9CDMY does not yet have any CDMY10CDMY statements. Add one using endpoint /v1/services/haproxy/configuration/binds , as in the example:


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "http", "address": "*", "port": 80}' \ "http://localhost:5555/v1/services/haproxy/configuration/binds?frontend=test_frontend&transaction_id=9663c384-5052-4776-a968-abcef032aeef" 

Then, to commit the transaction and apply all the changes, call endpoint /v1/services/haproxy/transactions/[transaction ID] using PUT, for example:


$ curl -X PUT --user admin:mypassword \ -H "Content-Type: application/json" \ http://localhost:5555/v1/services/haproxy/transactions/9663c384-5052-4776-a968-abcef032aeef 

Here's what the configuration looks like now:


frontend test_frontend mode http maxconn 2000 bind *:80 name http default_backend test_backend backend test_backend mode http balance roundrobin option httpchk HEAD/HTTP/1.1 server server1 127.0.0.1:8080 check maxconn 30 weight 100 

This load balancer is ready to receive traffic and redirect it to a higher server.


Since the Data Plane API specification uses the OpenAPI, it can be used to generate client code on many supported programming languages.


During this exercise, we packed all the commands inside a transaction. You can also call them one by one. In this case, instead of including the URL parameter named CDMY11CDMY, you should include one CDMY12CDMY, which will increase with each call.


Another example


You saw the simplicity and power of the HAProxy Data Plane API. With a few HTTP commands, you can dynamically change the configuration. Let's look at another example. We will create an ACL that will check if the Host header has the value example.com . If so, then the string use_backend will be directed to another server named example_servers . We will also add the http-request deny rule, which will reject any requests for the URL path /admin.php if the source IP address of the client is not on the network 192.168.50.20/24 .


First, use endpoint /v1/services/haproxy/transactions to create a new transaction and get its identifier:


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ http://localhost:5555/v1/services/haproxy/transactions?version=2 {"_version":2,"id":"7d0d6737-655e-4489-92eb-6d29cdd69827","status":"in_progress"} 

Then use endpoint /v1/services/haproxy/configuration/backends along with the transaction ID to create a new CDMY13CDMY named example_servers :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "example_servers", "mode":"http", "balance": {"algorithm":"roundrobin"}}' \ http://localhost:5555/v1/services/haproxy/configuration/backends?transaction_id=7d0d6737-655e-4489-92eb-6d29cdd69827 

Use endpoint /v1/services/haproxy/configuration/servers to add the server to the backend :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"name": "server1", "address": "127.0.0.1", "port": 8081, "check": "enabled", "maxconn": 30, "weight": 100}' \ "http://localhost:5555/v1/services/haproxy/configuration/servers?backend=example_servers&transaction_id=7d0d6737-655e-4489-92eb-6d29cdd69827" 

Use endpoint /v1/services/haproxy/configuration/acls to define an ACL named is_example that checks if the host header is set to example. com :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"id": 0, "acl_name": "is_example", "criterion": "req.hdr(Host)", "value": "example.com"}' \ "http://localhost:5555/v1/services/haproxy/configuration/acls?parent_type=frontend&parent_name=test_frontend&transaction_id=7d0d6737-655e-4489-92eb-6d29cdd69827" 

Use /v1/services/haproxy/configuration/backend_switching_rules to add the string use_backend , which evaluates the ACL is_example :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"id": 0, "cond": "if", "cond_test": "is_example", "name": "example_servers"}' \ "http://localhost:5555/v1/services/haproxy/configuration/backend_switching_rules?frontend=test_frontend&transaction_id=7d0d6737-655e-4489-92eb-6d29cdd69827" 

Use endpoint /v1/services/haproxy/configuration/http_request_rules to add a http-request deny rule that checks if the path is /admin. php and the source IP address of the client is not on the network 192.168.50.20/24 :


$ curl -X POST --user admin:mypassword \ -H "Content-Type: application/json" \ -d '{"id": 0, "cond": "if", "cond_test": "{ path/admin.php } !{ src 192.168.50.20/24 }", "type": "deny"}' \ "http://localhost:5555/v1/services/haproxy/configuration/http_request_rules?parent_type=frontend&parent_name=test_frontend&transaction_id=7d0d6737-655e-4489-92eb-6d29cdd69827" 

Then confirm the transaction for the change to take effect:


$ curl -X PUT --user admin:mypassword \ -H "Content-Type: application/json" \ http://localhost:5555/v1/services/haproxy/transactions/7d0d6737-655e-4489-92eb-6d29cdd69827 

Your HAProxy configuration now looks like this:


frontend test_frontend mode http maxconn 2000 bind *:80 name http acl is_example req.hdr(Host) example.com http-request deny deny_status 0 if { path/admin.php } !{ src 192.168.50.20/24 } use_backend example_servers if is_example default_backend test_backend backend example_servers mode http balance roundrobin server server1 127.0.0.1:8081 check maxconn 30 weight 100 backend test_backend mode http balance roundrobin option httpchk HEAD/HTTP/1.1 server server1 127.0.0.1:8080 check maxconn 30 weight 100 

Conclusion


In this article, you familiarized yourself with the HAProxy Data Plane API, which allows you to fully configure HAProxy using the modern REST API. More information can be found in the official documentation (Translation: https://habr.com/en/post/508132/ ). It has three powerful features that include the flexible HAProxy configuration language and the runtime API. The Data Plane API opens the door to multilateral use, in particular, using HAProxy as the proxy level in the service grid.


We are excited about the future use of the new API to create new partnerships and diverse functions. HAProxy continues to provide high performance and resilience in any environment and at any scale.


If you liked this article and want to keep up with similar topics, subscribe to this blog. You can also follow us on Twitter and join the conversation on Slack . HAProxy Enterprise makes it easy to get started with the Data Plane API, as it can be installed as a convenient system package. It also includes a reliable and advanced code base, a corporate set of add-ons, expert support and professional services. Want to know more? Contact us today and download a free trial.


P.S. Telegram chat HAproxy https://t.me/haproxy_ru

.

Source