Introduction
Fabio is a load balancer and proxy server for TCP and HTTP-based applications. Unlike the traditional load balancers and the reverse proxies, it configures itself without the need for configuration files. If there is a change in Consul, Fabio updates its routing table directly from the data stored in Consul, without restart or loading.
The main use-case for Fabio is to distribute incoming HTTP(S) and TCP requests from the internet)to frontend services which can handle these requests.
When registering a service in Consul all is needed to add a tag that announces the paths the upstream service accepts, e.g. urlprefix-/user or urlprefix-/order and Fabio will do the rest. To learn more about getting started with fabio you can visit this quick-start guide.
Procedure
Starting a backend service
You will first need to register a backend service in your Consul cluster. Since service registration happens on client agents, you will run your backend service on your Consul agents. The example you will use is a simple counting-service. On a Linux system, you can download the counting-service here. If you are on Darwin, you can compile the counting service from this source code.
Once you have a working counting-service
binary, you can run it:
$ ./counting-service
The counting service is accessible over http://<the ip of the host where the service is running>:<port configured to run the service>
. In this example, we will be using http://172.20.20.28:5000
.
Registering a service and health check with Consul
Here is the service definition for our counting service:
{
"service": {
"name": "counting",
"id": "counting-1",
"port": 5000,
"check": {
"http": "http://localhost:5000/health",
"method": "GET",
"interval": "1s",
"timeout": "1s"
}
}
}
Fabio will only watch the services which have a passing health check. So you need to make sure that the health check is passing in Consul after you register the service:
~$ curl -s http://localhost:8500/v1/health/checks/counting | jq .
[
{
"Node": "n2",
"CheckID": "service:counting-1",
"Name": "Service 'counting' check",
"Status": "passing",
"Notes": "",
"Output": "HTTP GET http://localhost:5000/health: 200 OK Output: Hello, you've hit /health\n",
"ServiceID": "counting-1",
"ServiceName": "counting",
"ServiceTags": [],
"Type": "http",
"Definition": {},
"CreateIndex": 63,
"ModifyIndex": 75
}
]
Starting Fabio
To start Fabio, The Connsul agent should be running on the localhost and will connect to it to query the service catalog. No special Fabio configuration is necessary for this to work. You can install fabio by following the quickstart guide.
Once Fabio is installed on your system, you can start it:
$ fabio
Now you can check Consul’s catalog to verify the Fabio service is registered with Consul:
$ consul catalog services
consul
counting
Fabio
In your browser, Fabio’s health can be checked via http://<IP address of your Fabio host>:9998/health
. For this example we will use http://172.20.20.28:9998
as the Fabio service is running on the same node as our counting service.
To have the fabio to monitor the service, in the service config file counting.json, you will need to add a tag that announces the paths the service accepts, e.g. urlprefix-/user
or urlprefix-/order
.
In this example, I have added "tags": ["urlprefix-/foo"]
in the configuration file as shown below:
{
"service": {
"name": "counting",
"tags": ["urlprefix-/foo"],
"id": "counting-1",
"port": 5000,
"check": {
"http": "http://localhost:5000/health",
"method": "GET",
"interval": "1s",
"timeout": "1s"
}
}
}
Next, test that you can access the counting service via Fabio:
$ curl -i http://localhost:9999/foo
HTTP/1.1 200 OK
Content-Length: 28
Content-Type: text/plain; charset=utf-8
Date: Fri, 17 Apr 2020 21:37:23 GMT
{"count":9,"hostname":"n2"}
You should also be able to see the counting service in both Consul and Fabio’s user interface. For Fabio, you can access http://172.20.20.28:9998/routes
Checking Fabio’s health in Consul:
You can curl your Consul cluster to check for Fabio’s health using Consul’s API: https://www.consul.io/api/health.html
.
$ curl -s http://localhost:8500/v1/health/checks/fabio | jq .
The output of the above curl command should look like this:
[
{
"Node": "n2",
"CheckID": "fabio-n2-9998-ttl",
"Name": "Service 'fabio' check",
"Status": "passing",
"Notes": "",
"Output": "",
"ServiceID": "fabio-n2-9998",
"ServiceName": "fabio",
"ServiceTags": [],
"Type": "ttl",
"Definition": {},
"CreateIndex": 31359,
"ModifyIndex": 31360
},
{
"Node": "n2",
"CheckID": "service:fabio-n2-9998:2",
"Name": "Service 'fabio' check",
"Status": "passing",
"Notes": "",
"Output": "HTTP GET http://[10.0.2.15]:9998/health: 200 OK Output: OK\n",
"ServiceID": "fabio-n2-9998",
"ServiceName": "fabio",
"ServiceTags": [],
"Type": "http",
"Definition": {},
"CreateIndex": 31359,
"ModifyIndex": 31361
}
]
Stopping Your Backend Service:
When you stop your counting service, you will observe that it no longer exists in Fabio’s routing table.
$ ps -ef | grep counting
vagrant 10906 10383 0 00:06 pts/0 00:00:00 ./counting-service
vagrant 10913 10383 0 00:12 pts/0 00:00:00 grep counting
$ kill -9 10906
You can check to see if your service (e.g here counting
service) is failing by using curl
to hit Consul’s health check API:
$ curl -s http://localhost:8500/v1/health/checks/counting | jq .
[
{
"Node": "n2",
"CheckID": "service:counting-1",
"Name": "Service 'counting' check",
"Status": "critical",
"Notes": "",
"Output": "Get http://localhost:5000/health: dial tcp [::1]:5000: connect: connection refused",
"ServiceID": "counting-1",
"ServiceName": "counting",
"ServiceTags": [
"urlprefix-/foo"
],
"Type": "http",
"Definition": {},
"CreateIndex": 63,
"ModifyIndex": 9037
}
]
Or by using curl
to hit the same endpoint that we used earlier for Fabio:
$ curl -i http://localhost:9999/foo
2020/04/20 18:12:58 [WARN] No route for localhost:9999/foo
HTTP/1.1 404 Not Found
Date: Mon, 20 Apr 2020 18:12:58 GMT
Content-Length: 0
$ curl -i http://localhost:9998/foo
HTTP/1.1 303 See Other
Content-Type: text/html; charset=utf-8
Location: /routes
Date: Mon, 20 Apr 2020 17:21:19 GMT
Content-Length: 34
<a href="/routes">See Other</a>.
$
Additional Information
For references, please check the below links:
- https://www.hashicorp.com/resources/fabio-a-stateless-load-balancer
- https://learn.hashicorp.com/consul/developer-discovery/health-checks
- https://github.com/fabiolb/fabio
- https://learn.hashicorp.com/consul/getting-started/services
- https://fabiolb.net/quickstart/
- https://www.hashicorp.com/resources/fabio-a-stateless-load-balancer