diff --git a/README.md b/README.md index e9497811..77db0790 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ core applications: https://status.twinnation.org/ - [Conditions](#conditions) - [Placeholders](#placeholders) - [Functions](#functions) - - [Kubernetes Autodiscovery](#kubernetes-autodiscovery) + - [Kubernetes](#kubernetes-alpha) + - [Auto Discovery](#auto-discovery) - [Alerting](#alerting) - [Configuring Slack alerts](#configuring-slack-alerts) - [Configuring PagerDuty alerts](#configuring-pagerduty-alerts) @@ -49,7 +50,7 @@ The main features of Gatus are: - **Alerting**: While having a pretty visual dashboard is useful to keep track of the state of your application(s), you probably don't want to stare at it all day. Thus, notifications via Slack, PagerDuty and Twilio are supported out of the box with the ability to configure a custom alerting provider for any needs you might have, whether it be a different provider or a custom application that manages automated rollbacks. - **Metrics** - **Low resource consumption**: As with most Go applications, the resource footprint that this application requires is negligibly small. -- Auto discover services in Kubernetes. +- **Service auto discovery in Kubernetes** (ALPHA) ## Usage @@ -126,6 +127,8 @@ Note that you can also add environment variables in the configuration file (i.e. | `security.basic.password-sha512` | Password's SHA512 hash for Basic authentication | Required `""` | | `disable-monitoring-lock` | Whether to [disable the monitoring lock](#disable-monitoring-lock) | `false` | +For Kubernetes configuration, see [Kubernetes](#kubernetes-alpha) + ### Conditions @@ -170,33 +173,6 @@ Here are some examples of conditions you can use: **NOTE**: Use `pat` only when you need to. `[STATUS] == pat(2*)` is a lot more expensive than `[STATUS] < 300`. -### Kubernetes Autodiscovery -Autodiscovery works by reading all `Service` object from the configured `Namespaces` and appending the `Suffix` and configured `health-api` to the Service name and making an http call. -All auto-discovered services will have the service configuration populated from the `service-template`. - -You Can exclude certain services from the dashboard by using the `exclude-suffix`. - -```yaml -kubernetes: - cluster-mode: "out" - auto-discover: true - service-suffix: ".services.svc.cluster.local" - exclude-suffix: - - primary - - canary - service-template: - interval: 30s - conditions: - - "[STATUS] == 200" - namespaces: - - name: website - service-suffix: "website.svc.cluster.local" - health-api: "/health" - - name: services - service-suffix: "services.svc.cluster.local" - health-api: "/health" -``` - ### Alerting @@ -329,6 +305,57 @@ services: - "[RESPONSE_TIME] < 300" ``` +### Kubernetes (ALPHA) + +> **WARNING**: This feature is in ALPHA. This means that it is very likely to change in the near future, which means that +> while you can use this feature as you see fit, there may be breaking changes in future releases. + +| Parameter | Description | Default | +|:------------------------------------------- |:----------------------------------------------------------------------------- |:-------------- | +| `kubernetes` | Kubernetes configuration | `{}` | +| `kubernetes.auto-discover` | Whether to enable auto discovery | `false` | +| `kubernetes.cluster-mode` | Cluster mode to use for authenticating. Supported values: `in`, `out` | Required `` | +| `kubernetes.service-template` | Service template. See `services[]` in [Configuration](#configuration) | Required `nil` | +| `kubernetes.excluded-service-suffixes` | List of service suffixes to not monitor (e.g. `canary`) | `[]` | +| `kubernetes.namespaces` | List of configurations for the namespaces from which services will be discovered | `[]` | +| `kubernetes.namespaces[].name` | Namespace name | Required `` | +| `kubernetes.namespaces[].hostname-suffix` | Suffix to append to the service name before calling `target-path` | Required `` | +| `kubernetes.namespaces[].target-path` | Path that will be called on the discovered service for the health check | `` | +| `kubernetes.namespaces[].excluded-services` | List of services to not monitor in the given namespace | `[]` | + + +#### Auto Discovery + +Auto discovery works by reading all `Service` resources from the configured `namespaces` and appending the `hostname-suffix` as +well as the configured `target-path` to the service name and making an HTTP call. + +All auto-discovered services will have the service configuration populated from the `service-template`. + +You can exclude certain services from the dashboard by using `kubernetes.excluded-service-suffixes` or `kubernetes.namespaces[].excluded-services`. + +```yaml +kubernetes: + auto-discover: true + cluster-mode: "out" + excluded-service-suffixes: + - canary + service-template: + interval: 30s + conditions: + - "[STATUS] == 200" + namespaces: + - name: default + hostname-suffix: ".default.svc.cluster.local" + target-path: "/health" + excluded-services: + - gatus + - kubernetes +``` + +Note that `hostname-suffix` could also be something like `.yourdomain.com`, in which case the endpoint that would be +monitored would be `potato.example.com/health`, assuming you have a service named `potato` and a matching ingress +to map `potato.example.com` to the `potato` service. + ## Docker diff --git a/config.yaml b/config.yaml index b4dc4e43..78203cff 100644 --- a/config.yaml +++ b/config.yaml @@ -18,7 +18,7 @@ services: kubernetes: cluster-mode: "out" auto-discover: true - exclude-suffix: + excluded-service-suffixes: - primary - canary service-template: @@ -27,5 +27,9 @@ kubernetes: - "[STATUS] == 200" namespaces: - name: default - service-suffix: "default.svc.cluster.local" - health-api: "/health" \ No newline at end of file + hostname-suffix: ".default.svc.cluster.local" + target-path: "/health" + excluded-services: + - gatus + - kubernetes + - twinnation \ No newline at end of file diff --git a/config/config.go b/config/config.go index 4de51161..4cc28350 100644 --- a/config/config.go +++ b/config/config.go @@ -62,6 +62,7 @@ type Config struct { // Services List of services to monitor Services []*core.Service `yaml:"services"` + // Kubernetes is the Kubernetes configuration Kubernetes *k8s.Config `yaml:"kubernetes"` } diff --git a/k8s/config.go b/k8s/config.go index 2b4679ed..f5f8702b 100644 --- a/k8s/config.go +++ b/k8s/config.go @@ -7,29 +7,32 @@ type Config struct { // AutoDiscover to discover services to monitor AutoDiscover bool `yaml:"auto-discover"` - // ServiceTemplate Template for auto discovered services - ServiceTemplate *core.Service `yaml:"service-template"` - - // ExcludeSuffix is a slice of service suffixes that should be ignored - ExcludeSuffix []string `yaml:"exclude-suffix"` - - // ClusterMode to authenticate with kubernetes + // ClusterMode is the mode to use to authenticate with Kubernetes ClusterMode ClusterMode `yaml:"cluster-mode"` - // Namespaces from which to discover services + // ServiceTemplate is the template for auto discovered services + ServiceTemplate *core.Service `yaml:"service-template"` + + // ExcludedServiceSuffixes is a list of service suffixes that should be ignored + ExcludedServiceSuffixes []string `yaml:"excluded-service-suffixes"` + + // Namespaces is a list of configurations for the namespaces from which services will be discovered Namespaces []*NamespaceConfig `yaml:"namespaces"` } // NamespaceConfig level config type NamespaceConfig struct { - // Name of namespace + // Name of the namespace Name string `yaml:"name"` - // ServiceSuffix to append to service name - ServiceSuffix string `yaml:"service-suffix"` + // ExcludedServices is a list of services to exclude from the auto discovery + ExcludedServices []string `yaml:"excluded-services"` - // HealthAPI URI to append to service to reach health check API - HealthAPI string `yaml:"health-api"` + // HostnameSuffix is a suffix to append to each service name before calling TargetPath + HostnameSuffix string `yaml:"hostname-suffix"` + + // TargetPath Path to append after the HostnameSuffix + TargetPath string `yaml:"target-path"` } // ClusterMode is the mode to use to authenticate to Kubernetes diff --git a/k8s/discovery.go b/k8s/discovery.go index 4e71df39..113ca2e3 100644 --- a/k8s/discovery.go +++ b/k8s/discovery.go @@ -19,13 +19,27 @@ func DiscoverServices(kubernetesConfig *Config) ([]*core.Service, error) { if err != nil { return nil, err } - for _, s := range kubernetesServices { - if isExcluded(kubernetesConfig.ExcludeSuffix, s.Name) { - continue + skipExcluded: + for _, service := range kubernetesServices { + for _, excludedServiceSuffix := range kubernetesConfig.ExcludedServiceSuffixes { + if strings.HasSuffix(service.Name, excludedServiceSuffix) { + continue skipExcluded + } + } + for _, excludedService := range ns.ExcludedServices { + if service.Name == excludedService { + continue skipExcluded + } + } + var url string + if strings.HasPrefix(ns.TargetPath, "/") { + url = fmt.Sprintf("http://%s%s%s", service.Name, ns.HostnameSuffix, ns.TargetPath) + } else { + url = fmt.Sprintf("http://%s%s/%s", service.Name, ns.HostnameSuffix, ns.TargetPath) } services = append(services, &core.Service{ - Name: s.Name, - URL: fmt.Sprintf("http://%s%s/%s", s.Name, ns.ServiceSuffix, ns.HealthAPI), + Name: service.Name, + URL: url, Interval: kubernetesConfig.ServiceTemplate.Interval, Conditions: kubernetesConfig.ServiceTemplate.Conditions, }) @@ -33,13 +47,3 @@ func DiscoverServices(kubernetesConfig *Config) ([]*core.Service, error) { } return services, nil } - -// TODO: don't uselessly allocate new things here, just move this inside the DiscoverServices function -func isExcluded(excludeList []string, name string) bool { - for _, x := range excludeList { - if strings.HasSuffix(name, x) { - return true - } - } - return false -}