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
|
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
|
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
|
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
|
often the health check should be executed (the default being 30 seconds).
|
||||||
backend must respond to the health check within 5 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
|
A recovering backend returning 200 OK responses again is being returned to the
|
||||||
LB rotation pool.
|
LB rotation pool.
|
||||||
|
@ -311,6 +312,16 @@ For example:
|
||||||
interval = "10s"
|
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
|
||||||
|
|
||||||
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
||||||
|
@ -439,4 +450,3 @@ Note that each command is described at the beginning of the help section:
|
||||||
```bash
|
```bash
|
||||||
$ traefik --help
|
$ traefik --help
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,10 @@ package healthcheck
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ func GetHealthCheck() *HealthCheck {
|
||||||
// Options are the public health check options.
|
// Options are the public health check options.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Path string
|
Path string
|
||||||
|
Port int
|
||||||
Interval time.Duration
|
Interval time.Duration
|
||||||
LB LoadBalancer
|
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 {
|
func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) bool {
|
||||||
client := http.Client{
|
client := http.Client{
|
||||||
Timeout: backend.requestTimeout,
|
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 {
|
if err == nil {
|
||||||
defer resp.Body.Close()
|
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 {
|
func MustParseURL(rawurl string) *url.URL {
|
||||||
u, err := url.Parse(rawurl)
|
u, err := url.Parse(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in a new issue