Merge pull request #1132 from Juliens/healthcheck

Healthcheck tests and doc
This commit is contained in:
Emile Vauge
2017-02-21 14:03:13 +01:00
committed by GitHub
7 changed files with 161 additions and 6 deletions

View File

@@ -235,6 +235,20 @@ For example:
[backends.backend1.loadbalancer]
sticky = true
```
Healthcheck URL can be configured with a relative URL for `healthcheck.URL`.
Interval between healthcheck can be configured by using `healthcheck.interval`
(default: 30s)
For example:
```toml
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
URL = "/health"
interval = "10s"
```
## 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).

View File

@@ -26,6 +26,7 @@ func GetHealthCheck() *HealthCheck {
// BackendHealthCheck HealthCheck configuration for a backend
type BackendHealthCheck struct {
URL string
Interval time.Duration
DisabledURLs []*url.URL
lb loadBalancer
}
@@ -49,8 +50,8 @@ func newHealthCheck() *HealthCheck {
}
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
func NewBackendHealthCheck(URL string, lb loadBalancer) *BackendHealthCheck {
return &BackendHealthCheck{URL, nil, lb}
func NewBackendHealthCheck(URL string, interval time.Duration, lb loadBalancer) *BackendHealthCheck {
return &BackendHealthCheck{URL, interval, nil, lb}
}
//SetBackendsConfiguration set backends configuration
@@ -70,7 +71,7 @@ func (hc *HealthCheck) execute(ctx context.Context) {
currentBackendID := backendID
safe.Go(func() {
for {
ticker := time.NewTicker(time.Second * 30)
ticker := time.NewTicker(currentBackend.Interval)
select {
case <-ctx.Done():
log.Debugf("Stopping all current Healthcheck goroutines")

View File

@@ -0,0 +1,27 @@
defaultEntryPoints = ["http"]
logLevel = "DEBUG"
[entryPoints]
[entryPoints.http]
address = ":8000"
[web]
address = ":8080"
[file]
[backends]
[backends.backend1]
[backends.backend1.healthcheck]
url = "/health"
interval = "1s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
[backends.backend1.servers.server2]
url = "http://{{.Server2}}:80"
[frontends]
[frontends.frontend1]
backend = "backend1"
[frontends.frontend1.routes.test_1]
rule = "Host:test.localhost"

View File

@@ -0,0 +1,91 @@
package main
import (
"bytes"
"errors"
"io/ioutil"
"net/http"
"os"
"os/exec"
"strings"
"time"
"github.com/containous/traefik/integration/utils"
"github.com/go-check/check"
checker "github.com/vdemeester/shakers"
)
// HealchCheck test suites (using libcompose)
type HealchCheckSuite struct{ BaseSuite }
func (s *HealchCheckSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "healthcheck")
s.composeProject.Start(c)
}
func (s *HealchCheckSuite) TestSimpleConfiguration(c *check.C) {
whoami1Host := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
whoami2Host := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/healthcheck/simple.toml", struct {
Server1 string
Server2 string
}{whoami1Host, whoami2Host})
defer os.Remove(file)
cmd := exec.Command(traefikBinary, "--configFile="+file)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// wait for traefik
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
if !strings.Contains(string(body), "Host:test.localhost") {
return errors.New("Incorrect traefik config: " + string(body))
}
return nil
})
c.Assert(err, checker.IsNil)
client := &http.Client{}
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/health", nil)
c.Assert(err, checker.IsNil)
req.Host = "test.localhost"
resp, err := client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
resp, err = client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
healthReq, err := http.NewRequest("POST", "http://"+whoami1Host+"/health", bytes.NewBuffer([]byte("500")))
c.Assert(err, checker.IsNil)
_, err = client.Do(healthReq)
c.Assert(err, checker.IsNil)
time.Sleep(time.Second * 3)
resp, err = client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
resp, err = client.Do(req)
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 200)
// TODO validate : run on 80
resp, err = http.Get("http://127.0.0.1:8000/")
// Expected a 404 as we did not configure anything
c.Assert(err, checker.IsNil)
c.Assert(resp.StatusCode, checker.Equals, 404)
}

View File

@@ -0,0 +1,5 @@
whoami1:
image: emilevauge/whoami
whoami2:
image: emilevauge/whoami

View File

@@ -658,7 +658,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
continue frontend
}
if configuration.Backends[frontend.Backend].HealthCheck != nil {
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rebalancer)
var interval time.Duration
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
if err != nil {
log.Errorf("Wrong healthcheck interval: %s", err)
interval = time.Second * 30
}
}
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rebalancer)
}
}
case types.Wrr:
@@ -684,7 +692,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
}
}
if configuration.Backends[frontend.Backend].HealthCheck != nil {
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rr)
var interval time.Duration
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
if err != nil {
log.Errorf("Wrong healthcheck interval: %s", err)
interval = time.Second * 30
}
}
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rr)
}
}
maxConns := configuration.Backends[frontend.Backend].MaxConn

View File

@@ -39,7 +39,8 @@ type CircuitBreaker struct {
// HealthCheck holds HealthCheck configuration
type HealthCheck struct {
URL string `json:"url,omitempty"`
URL string `json:"url,omitempty"`
Interval string `json:"interval,omitempty"`
}
// Server holds server configuration.