Allow overriding port for backend healthchecks
This commit is contained in:
parent
c7281df230
commit
13e8a875cf
3 changed files with 114 additions and 13 deletions
|
@ -296,8 +296,9 @@ A health check can be configured in order to remove a backend from LB rotation
|
|||
as long as it keeps returning HTTP status codes other than 200 OK to HTTP GET
|
||||
requests periodically carried out by Traefik. The check is defined by a path
|
||||
appended to the backend URL and an interval (given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration)) specifying how
|
||||
often the health check should be executed (the default being 30 seconds). Each
|
||||
backend must respond to the health check within 5 seconds.
|
||||
often the health check should be executed (the default being 30 seconds).
|
||||
Each backend must respond to the health check within 5 seconds.
|
||||
By default, the port of the backend server is used, however, this may be overridden.
|
||||
|
||||
A recovering backend returning 200 OK responses again is being returned to the
|
||||
LB rotation pool.
|
||||
|
@ -311,6 +312,16 @@ For example:
|
|||
interval = "10s"
|
||||
```
|
||||
|
||||
To use a different port for the healthcheck:
|
||||
```toml
|
||||
[backends]
|
||||
[backends.backend1]
|
||||
[backends.backend1.healthcheck]
|
||||
path = "/health"
|
||||
interval = "10s"
|
||||
port = 8080
|
||||
```
|
||||
|
||||
## Servers
|
||||
|
||||
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
||||
|
@ -346,17 +357,17 @@ Here is an example of backends and servers definition:
|
|||
|
||||
# Configuration
|
||||
|
||||
Træfik's configuration has two parts:
|
||||
Træfik's configuration has two parts:
|
||||
|
||||
- The [static Træfik configuration](/basics#static-trfk-configuration) which is loaded only at the beginning.
|
||||
- The [static Træfik configuration](/basics#static-trfk-configuration) which is loaded only at the beginning.
|
||||
- The [dynamic Træfik configuration](/basics#dynamic-trfk-configuration) which can be hot-reloaded (no need to restart the process).
|
||||
|
||||
|
||||
## Static Træfik configuration
|
||||
|
||||
The static configuration is the global configuration which is setting up connections to configuration backends and entrypoints.
|
||||
The static configuration is the global configuration which is setting up connections to configuration backends and entrypoints.
|
||||
|
||||
Træfik can be configured using many configuration sources with the following precedence order.
|
||||
Træfik can be configured using many configuration sources with the following precedence order.
|
||||
Each item takes precedence over the item below it:
|
||||
|
||||
- [Key-value Store](/basics/#key-value-stores)
|
||||
|
@ -398,18 +409,18 @@ Træfik supports several Key-value stores:
|
|||
|
||||
- [Consul](https://consul.io)
|
||||
- [etcd](https://coreos.com/etcd/)
|
||||
- [ZooKeeper](https://zookeeper.apache.org/)
|
||||
- [ZooKeeper](https://zookeeper.apache.org/)
|
||||
- [boltdb](https://github.com/boltdb/bolt)
|
||||
|
||||
Please refer to the [User Guide Key-value store configuration](/user-guide/kv-config/) section to get documentation on it.
|
||||
|
||||
## Dynamic Træfik configuration
|
||||
|
||||
The dynamic configuration concerns :
|
||||
The dynamic configuration concerns :
|
||||
|
||||
- [Frontends](/basics/#frontends)
|
||||
- [Backends](/basics/#backends)
|
||||
- [Servers](/basics/#servers)
|
||||
- [Backends](/basics/#backends)
|
||||
- [Servers](/basics/#servers)
|
||||
|
||||
Træfik can hot-reload those rules which could be provided by [multiple configuration backends](/toml/#configuration-backends).
|
||||
|
||||
|
@ -427,7 +438,7 @@ List of Træfik available commands with description :
|
|||
- `version` : Print version
|
||||
- `storeconfig` : Store the static traefik configuration into a Key-value stores. Please refer to the [Store Træfik configuration](/user-guide/kv-config/#store-trfk-configuration) section to get documentation on it.
|
||||
|
||||
Each command may have related flags.
|
||||
Each command may have related flags.
|
||||
All those related flags will be displayed with :
|
||||
|
||||
```bash
|
||||
|
@ -439,4 +450,3 @@ Note that each command is described at the beginning of the help section:
|
|||
```bash
|
||||
$ traefik --help
|
||||
```
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ package healthcheck
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -27,6 +29,7 @@ func GetHealthCheck() *HealthCheck {
|
|||
// Options are the public health check options.
|
||||
type Options struct {
|
||||
Path string
|
||||
Port int
|
||||
Interval time.Duration
|
||||
LB LoadBalancer
|
||||
}
|
||||
|
@ -127,11 +130,32 @@ func checkBackend(currentBackend *BackendHealthCheck) {
|
|||
}
|
||||
}
|
||||
|
||||
func (backend *BackendHealthCheck) newRequest(serverURL *url.URL) (*http.Request, error) {
|
||||
if backend.Options.Port == 0 {
|
||||
return http.NewRequest("GET", serverURL.String()+backend.Path, nil)
|
||||
}
|
||||
|
||||
// copy the url and add the port to the host
|
||||
u := &url.URL{}
|
||||
*u = *serverURL
|
||||
u.Host = net.JoinHostPort(u.Hostname(), strconv.Itoa(backend.Options.Port))
|
||||
u.Path = u.Path + backend.Path
|
||||
|
||||
return http.NewRequest("GET", u.String(), nil)
|
||||
}
|
||||
|
||||
func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) bool {
|
||||
client := http.Client{
|
||||
Timeout: backend.requestTimeout,
|
||||
}
|
||||
resp, err := client.Get(serverURL.String() + backend.Path)
|
||||
req, err := backend.newRequest(serverURL)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create HTTP request [%s] for healthcheck: %s", serverURL, err)
|
||||
return false
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
|
|
@ -193,6 +193,73 @@ func TestSetBackendsConfiguration(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
host string
|
||||
port int
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
desc: "no port override",
|
||||
host: "backend1:80",
|
||||
port: 0,
|
||||
path: "/test",
|
||||
expected: "http://backend1:80/test",
|
||||
},
|
||||
{
|
||||
desc: "port override",
|
||||
host: "backend2:80",
|
||||
port: 8080,
|
||||
path: "/test",
|
||||
expected: "http://backend2:8080/test",
|
||||
},
|
||||
{
|
||||
desc: "no port override with no port in host",
|
||||
host: "backend1",
|
||||
port: 0,
|
||||
path: "/health",
|
||||
expected: "http://backend1/health",
|
||||
},
|
||||
{
|
||||
desc: "port override with no port in host",
|
||||
host: "backend2",
|
||||
port: 8080,
|
||||
path: "/health",
|
||||
expected: "http://backend2:8080/health",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
backend := NewBackendHealthCheck(
|
||||
Options{
|
||||
Path: test.path,
|
||||
Port: test.port,
|
||||
})
|
||||
|
||||
u := &url.URL{
|
||||
Scheme: "http",
|
||||
Host: test.host,
|
||||
}
|
||||
|
||||
req, err := backend.newRequest(u)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new backend request: %s", err)
|
||||
}
|
||||
|
||||
actual := req.URL.String()
|
||||
if actual != test.expected {
|
||||
t.Fatalf("got %s for healthcheck URL, wanted %s", actual, test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func MustParseURL(rawurl string) *url.URL {
|
||||
u, err := url.Parse(rawurl)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue