open-nomad/website/source/guides/load-balancing/fabio.html.md

234 lines
7.5 KiB
Markdown
Raw Normal View History

---
layout: "guides"
page_title: "Load Balancing with Nomad"
sidebar_current: "guides-load-balancing"
description: |-
There are multiple approaches to load balancing within a Nomad cluster.
One approach involves using [fabio][fabio]. Fabio integrates natively
with Consul and provides rich features with an optional Web UI.
---
# Load Balancing with Fabio
[Fabio][fabio] integrates natively with Consul and provides an optional Web UI
to visualize routing.
The main use case for fabio is to distribute incoming HTTP(S) and TCP requests
from the internet to frontend services that can handle these requests. This
guide will show you one such example using [Apache][apache] web server.
## Reference Material
- [Fabio](https://github.com/fabiolb/fabio) on GitHub
- [Load Balancing Strategies for Consul](https://www.hashicorp.com/blog/load-balancing-strategies-for-consul)
- [Elastic Load Balancing][elb]
## Estimated Time to Complete
20 minutes
## Challenge
Think of a scenario where a Nomad operator needs to configure an environment to
make Apache web server highly available behind an endpoint and distribute
incoming traffic evenly.
## Solution
Deploy fabio as a
[system][system]
scheduler so that it can route incoming traffic evenly to the Apache web server
group regardless of which client nodes Apache is running on. Place all client nodes
behind an [AWS load balancer][elb] to
provide the end user with a single endpoint for access.
## Prerequisites
To perform the tasks described in this guide, you need to have a Nomad
environment with Consul installed. You can use this
[repo](https://github.com/hashicorp/nomad/tree/master/terraform#provision-a-nomad-cluster-in-the-cloud)
to easily provision a sandbox environment. This guide will assume a cluster with
one server node and three client nodes.
-> **Please Note:** This guide is for demo purposes and is only using a single server
node. In a production cluster, 3 or 5 server nodes are recommended.
## Steps
### Step 1: Create a Job for Fabio
Create a job for Fabio and name it `fabio.nomad`
```hcl
job "fabio" {
datacenters = ["dc1"]
type = "system"
group "fabio" {
task "fabio" {
driver = "docker"
config {
image = "fabiolb/fabio"
network_mode = "host"
}
resources {
cpu = 200
memory = 128
network {
mbits = 20
port "lb" {
static = 9999
}
port "ui" {
static = 9998
}
}
}
}
}
}
```
Setting `type` to [system][system] will ensure that fabio is run on all clients.
Please note that the `network_mode` option is set to `host` so that fabio can
communicate with Consul which is also running on the client nodes.
### Step 2: Run the Fabio Job
We can now register our fabio job:
```shell
$ nomad job run fabio.nomad
==> Monitoring evaluation "fba4f04a"
Evaluation triggered by job "fabio"
Allocation "6e6367d4" created: node "f3739267", group "fabio"
Allocation "d17573b4" created: node "28d7f859", group "fabio"
Allocation "f3ad9b16" created: node "510898b6", group "fabio"
Evaluation status changed: "pending" -> "complete"
==> Evaluation "fba4f04a" finished with status "complete"
```
At this point, you should be able to visit any one of your client nodes at port
`9998` and see the web interface for fabio. The routing table will be empty
since we have not yet deployed anything that fabio can route to.
Accordingly, if you visit any of the client nodes at port `9999` at this
point, you will get a `404` HTTP response. That will change soon.
### Step 3: Create a Job for Apache Web Server
Create a job for Apache and name it `webserver.nomad`
```hcl
job "webserver" {
datacenters = ["dc1"]
type = "service"
group "webserver" {
count = 3
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
ephemeral_disk {
size = 300
}
task "apache" {
driver = "docker"
config {
image = "httpd:latest"
port_map {
http = 80
}
}
resources {
network {
mbits = 10
port "http" {}
}
}
service {
name = "apache-webserver"
tags = ["urlprefix-/"]
port = "http"
check {
name = "alive"
type = "http"
path = "/"
interval = "10s"
timeout = "2s"
}
}
}
}
}
```
Notice the tag in the service stanza begins with `urlprefix-`. This is how a
path is registered with fabio. In this case, we are registering the path '/'
with fabio (which will route us to the default page for Apache web server).
### Step 4: Run the Job for Apache Web Server
We can now register our job for Apache:
```shell
$ nomad job run webserver.nomad
==> Monitoring evaluation "c7bcaf40"
Evaluation triggered by job "webserver"
Evaluation within deployment: "e3603b50"
Allocation "20951ad4" created: node "510898b6", group "webserver"
Allocation "43807686" created: node "28d7f859", group "webserver"
Allocation "7b60eb24" created: node "f3739267", group "webserver"
Evaluation status changed: "pending" -> "complete"
==> Evaluation "c7bcaf40" finished with status "complete"
```
You have now deployed and registered your web servers with fabio! At this point,
you should be able to visit any of the Nomad clients at port `9999` and
see the default web page for Apache web server. If you visit fabio's web
interface by going to any of the client nodes at port `9998`, you will see that
the routing table has been populated as shown below (**Note:** your destination IP
addresses will be different).
[![Routing Table][routing-table]][routing-table]
Feel free to reduce the `count` in `webserver.nomad` for testing purposes. You
will see that you still get routed to the Apache home page by accessing
any client node on port `9999`. Accordingly, the routing table
in the web interface on port `9999` will reflect the changes.
### Step 5: Place Nomad Client Nodes Behing AWS Load Balancer
At this point, you are ready to place your Nomad client nodes behind an AWS load
balancer. Your Nomad client nodes may change over time, and it is important
to provide your end users with a single endpoint to access your services. This guide will use the [Classic Load Balancer][classic-lb].
The AWS [documentation][classic-lb-doc] provides instruction on how to create a
load balancer. The basic steps involve creating a load balancer, registering
instances behind the load balancer (in our case these will be the Nomad client
nodes), creating listeners, and configuring health checks.
Once you are done
with this, you should be able to hit the DNS name of your load balancer at port
80 (or whichever port you configured in your listener) and see the home page of
2018-10-04 22:26:51 +00:00
Apache web server. If you configured your listener to also forward traffic to
the web interface at port `9998`, you should be able to access that as well.
[![Home Page][lb-homepage]][lb-homepage]
[![Routing Table][lb-routing-table]][lb-routing-table]
[apache]: https://httpd.apache.org/
[classic-lb]: https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/introduction.html
[classic-lb-doc]: https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-getting-started.html
[elb]: https://aws.amazon.com/elasticloadbalancing/
[fabio]: https://fabiolb.net/
[lb-homepage]: /assets/images/lb-homepage.png
[lb-routing-table]: /assets/images/lb-routing-table.png
[routing-table]: /assets/images/routing-table.png
[system]: /docs/runtime/schedulers.html#system