Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add internal provider #5815

Merged
merged 11 commits into from
Nov 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
192 changes: 153 additions & 39 deletions cmd/traefik/traefik.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package main
import (
"context"
"encoding/json"
"fmt"
stdlog "log"
"net/http"
"os"
Expand All @@ -20,12 +19,17 @@ import (
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/log"
"github.com/containous/traefik/v2/pkg/metrics"
"github.com/containous/traefik/v2/pkg/middlewares/accesslog"
"github.com/containous/traefik/v2/pkg/provider/acme"
"github.com/containous/traefik/v2/pkg/provider/aggregator"
"github.com/containous/traefik/v2/pkg/provider/traefik"
"github.com/containous/traefik/v2/pkg/safe"
"github.com/containous/traefik/v2/pkg/server"
"github.com/containous/traefik/v2/pkg/server/router"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/server/service"
traefiktls "github.com/containous/traefik/v2/pkg/tls"
"github.com/containous/traefik/v2/pkg/types"
"github.com/containous/traefik/v2/pkg/version"
"github.com/coreos/go-systemd/daemon"
assetfs "github.com/elazarl/go-bindata-assetfs"
Expand Down Expand Up @@ -77,7 +81,7 @@ func runCmd(staticConfiguration *static.Configuration) error {
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment

if err := roundrobin.SetDefaultWeight(0); err != nil {
log.WithoutContext().Errorf("Could not set roundrobin default weight: %v", err)
log.WithoutContext().Errorf("Could not set round robin default weight: %v", err)
}

staticConfiguration.SetEffectiveConfiguration()
Expand Down Expand Up @@ -105,43 +109,11 @@ func runCmd(staticConfiguration *static.Configuration) error {

stats(staticConfiguration)

providerAggregator := aggregator.NewProviderAggregator(*staticConfiguration.Providers)

tlsManager := traefiktls.NewManager()

acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager)

serverEntryPointsTCP := make(server.TCPEntryPoints)
for entryPointName, config := range staticConfiguration.EntryPoints {
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
serverEntryPointsTCP[entryPointName], err = server.NewTCPEntryPoint(ctx, config)
if err != nil {
return fmt.Errorf("error while building entryPoint %s: %v", entryPointName, err)
}
serverEntryPointsTCP[entryPointName].RouteAppenderFactory = router.NewRouteAppenderFactory(*staticConfiguration, entryPointName, acmeProviders)
}

svr := server.NewServer(*staticConfiguration, providerAggregator, serverEntryPointsTCP, tlsManager)

resolverNames := map[string]struct{}{}

for _, p := range acmeProviders {
resolverNames[p.ResolverName] = struct{}{}
svr.AddListener(p.ListenConfiguration)
svr, err := setupServer(staticConfiguration)
if err != nil {
return err
}

svr.AddListener(func(config dynamic.Configuration) {
for rtName, rt := range config.HTTP.Routers {
if rt.TLS == nil || rt.TLS.CertResolver == "" {
continue
}

if _, ok := resolverNames[rt.TLS.CertResolver]; !ok {
log.WithoutContext().Errorf("the router %s uses a non-existent resolver: %s", rtName, rt.TLS.CertResolver)
}
}
})

ctx := cmd.ContextWithSignal(context.Background())

if staticConfiguration.Ping != nil {
Expand All @@ -168,7 +140,7 @@ func runCmd(staticConfiguration *static.Configuration) error {
for range tick {
resp, errHealthCheck := healthcheck.Do(*staticConfiguration)
if resp != nil {
resp.Body.Close()
_ = resp.Body.Close()
}

if staticConfiguration.Ping == nil || errHealthCheck == nil {
Expand All @@ -188,6 +160,94 @@ func runCmd(staticConfiguration *static.Configuration) error {
return nil
}

func setupServer(staticConfiguration *static.Configuration) (*server.Server, error) {
providerAggregator := aggregator.NewProviderAggregator(*staticConfiguration.Providers)

// adds internal provider
err := providerAggregator.AddProvider(traefik.New(*staticConfiguration))
if err != nil {
return nil, err
}

tlsManager := traefiktls.NewManager()

acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager)

serverEntryPointsTCP, err := server.NewTCPEntryPoints(*staticConfiguration)
if err != nil {
return nil, err
}

ctx := context.Background()
routinesPool := safe.NewPool(ctx)

metricsRegistry := registerMetricClients(staticConfiguration.Metrics)
accessLog := setupAccessLog(staticConfiguration.AccessLog)
chainBuilder := middleware.NewChainBuilder(*staticConfiguration, metricsRegistry, accessLog)
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry)
tcpRouterFactory := server.NewTCPRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder)

watcher := server.NewConfigurationWatcher(routinesPool, providerAggregator, time.Duration(staticConfiguration.Providers.ProvidersThrottleDuration))

watcher.AddListener(func(conf dynamic.Configuration) {
ctx := context.Background()
tlsManager.UpdateConfigs(ctx, conf.TLS.Stores, conf.TLS.Options, conf.TLS.Certificates)
})

watcher.AddListener(func(_ dynamic.Configuration) {
metricsRegistry.ConfigReloadsCounter().Add(1)
metricsRegistry.LastConfigReloadSuccessGauge().Set(float64(time.Now().Unix()))
})

watcher.AddListener(switchRouter(tcpRouterFactory, acmeProviders, serverEntryPointsTCP))

watcher.AddListener(func(conf dynamic.Configuration) {
if metricsRegistry.IsEpEnabled() || metricsRegistry.IsSvcEnabled() {
var eps []string
for key := range serverEntryPointsTCP {
eps = append(eps, key)
}

metrics.OnConfigurationUpdate(conf, eps)
}
})

resolverNames := map[string]struct{}{}
for _, p := range acmeProviders {
resolverNames[p.ResolverName] = struct{}{}
watcher.AddListener(p.ListenConfiguration)
}

watcher.AddListener(func(config dynamic.Configuration) {
for rtName, rt := range config.HTTP.Routers {
if rt.TLS == nil || rt.TLS.CertResolver == "" {
continue
}

if _, ok := resolverNames[rt.TLS.CertResolver]; !ok {
log.WithoutContext().Errorf("the router %s uses a non-existent resolver: %s", rtName, rt.TLS.CertResolver)
}
}
})

return server.NewServer(routinesPool, serverEntryPointsTCP, watcher, chainBuilder, accessLog), nil
}

func switchRouter(tcpRouterFactory *server.TCPRouterFactory, acmeProviders []*acme.Provider, serverEntryPointsTCP server.TCPEntryPoints) func(conf dynamic.Configuration) {
return func(conf dynamic.Configuration) {
routers := tcpRouterFactory.CreateTCPRouters(conf)
for entryPointName, rt := range routers {
for _, p := range acmeProviders {
if p != nil && p.HTTPChallenge != nil && p.HTTPChallenge.EntryPoint == entryPointName {
rt.HTTPHandler(p.CreateHandler(rt.GetHTTPHandler()))
break
}
}
}
serverEntryPointsTCP.Switch(routers)
}
}

// initACMEProvider creates an acme provider from the ACME part of globalConfiguration
func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.ProviderAggregator, tlsManager *traefiktls.Manager) []*acme.Provider {
challengeStore := acme.NewLocalChallengeStore()
Expand Down Expand Up @@ -222,6 +282,60 @@ func initACMEProvider(c *static.Configuration, providerAggregator *aggregator.Pr
return resolvers
}

func registerMetricClients(metricsConfig *types.Metrics) metrics.Registry {
if metricsConfig == nil {
return metrics.NewVoidRegistry()
}

var registries []metrics.Registry

if metricsConfig.Prometheus != nil {
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "prometheus"))
prometheusRegister := metrics.RegisterPrometheus(ctx, metricsConfig.Prometheus)
if prometheusRegister != nil {
registries = append(registries, prometheusRegister)
log.FromContext(ctx).Debug("Configured Prometheus metrics")
}
}

if metricsConfig.Datadog != nil {
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "datadog"))
registries = append(registries, metrics.RegisterDatadog(ctx, metricsConfig.Datadog))
log.FromContext(ctx).Debugf("Configured Datadog metrics: pushing to %s once every %s",
metricsConfig.Datadog.Address, metricsConfig.Datadog.PushInterval)
}

if metricsConfig.StatsD != nil {
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "statsd"))
registries = append(registries, metrics.RegisterStatsd(ctx, metricsConfig.StatsD))
log.FromContext(ctx).Debugf("Configured StatsD metrics: pushing to %s once every %s",
metricsConfig.StatsD.Address, metricsConfig.StatsD.PushInterval)
}

if metricsConfig.InfluxDB != nil {
ctx := log.With(context.Background(), log.Str(log.MetricsProviderName, "influxdb"))
registries = append(registries, metrics.RegisterInfluxDB(ctx, metricsConfig.InfluxDB))
log.FromContext(ctx).Debugf("Configured InfluxDB metrics: pushing to %s once every %s",
metricsConfig.InfluxDB.Address, metricsConfig.InfluxDB.PushInterval)
}

return metrics.NewMultiRegistry(registries)
}

func setupAccessLog(conf *types.AccessLog) *accesslog.Handler {
if conf == nil {
return nil
}

accessLoggerMiddleware, err := accesslog.NewHandler(conf)
if err != nil {
log.WithoutContext().Warnf("Unable to create access logger : %v", err)
return nil
}

return accessLoggerMiddleware
}

func configureLogging(staticConfiguration *static.Configuration) {
// configure default log flags
stdlog.SetFlags(stdlog.Lshortfile | stdlog.LstdFlags)
Expand Down
22 changes: 22 additions & 0 deletions docs/content/observability/metrics/prometheus.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,25 @@ metrics:
--entryPoints.metrics.address=":8082"
--metrics.prometheus.entryPoint="metrics"
```

#### `manualRouting`

_Optional, Default=false_

If `manualRouting` is `true`, it disables the default internal router in order to allow one to create a custom router for the `prometheus@internal` service.

```toml tab="File (TOML)"
[metrics]
[metrics.prometheus]
manualRouting = true
```

```yaml tab="File (YAML)"
metrics:
prometheus:
manualRouting: true
```

```bash tab="CLI"
--metrics.prometheus.manualrouting=true
```
20 changes: 20 additions & 0 deletions docs/content/operations/ping.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,23 @@ ping:
--entryPoints.ping.address=":8082"
--ping.entryPoint="ping"
```

#### `manualRouting`

_Optional, Default=false_

If `manualRouting` is `true`, it disables the default internal router in order to allow one to create a custom router for the `ping@internal` service.

```toml tab="File (TOML)"
[ping]
manualRouting = true
```

```yaml tab="File (YAML)"
ping:
manualRouting: true
```

```bash tab="CLI"
--ping.manualrouting=true
```
6 changes: 6 additions & 0 deletions docs/content/reference/static-configuration/cli-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000
`--metrics.prometheus.entrypoint`:
EntryPoint (Default: ```traefik```)

`--metrics.prometheus.manualrouting`:
Manual routing (Default: ```false```)

`--metrics.statsd`:
StatsD metrics exporter type. (Default: ```false```)

Expand All @@ -237,6 +240,9 @@ Enable ping. (Default: ```false```)
`--ping.entrypoint`:
EntryPoint (Default: ```traefik```)

`--ping.manualrouting`:
Manual routing (Default: ```false```)

`--providers.consulcatalog.cache`:
Use local agent caching for catalog reads. (Default: ```false```)

Expand Down
6 changes: 6 additions & 0 deletions docs/content/reference/static-configuration/env-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000
`TRAEFIK_METRICS_PROMETHEUS_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)

`TRAEFIK_METRICS_PROMETHEUS_MANUALROUTING`:
Manual routing (Default: ```false```)

`TRAEFIK_METRICS_STATSD`:
StatsD metrics exporter type. (Default: ```false```)

Expand All @@ -237,6 +240,9 @@ Enable ping. (Default: ```false```)
`TRAEFIK_PING_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)

`TRAEFIK_PING_MANUALROUTING`:
Manual routing (Default: ```false```)

`TRAEFIK_PROVIDERS_CONSULCATALOG_CACHE`:
Use local agent caching for catalog reads. (Default: ```false```)

Expand Down
2 changes: 2 additions & 0 deletions docs/content/reference/static-configuration/file.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
addEntryPointsLabels = true
addServicesLabels = true
entryPoint = "foobar"
manualRouting = true
[metrics.datadog]
address = "foobar"
pushInterval = "10s"
Expand All @@ -165,6 +166,7 @@

[ping]
entryPoint = "foobar"
manualRouting = true

[log]
level = "foobar"
Expand Down
2 changes: 2 additions & 0 deletions docs/content/reference/static-configuration/file.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ metrics:
addEntryPointsLabels: true
addServicesLabels: true
entryPoint: foobar
manualRouting: true
datadog:
address: foobar
pushInterval: 42
Expand All @@ -171,6 +172,7 @@ metrics:
addServicesLabels: true
ping:
entryPoint: foobar
manualRouting: true
log:
level: foobar
filePath: foobar
Expand Down