diff --git a/README.md b/README.md index 1ee16f43..e9497811 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ core applications: https://status.twinnation.org/ - [Conditions](#conditions) - [Placeholders](#placeholders) - [Functions](#functions) + - [Kubernetes Autodiscovery](#kubernetes-autodiscovery) - [Alerting](#alerting) - [Configuring Slack alerts](#configuring-slack-alerts) - [Configuring PagerDuty alerts](#configuring-pagerduty-alerts) @@ -48,6 +49,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. ## Usage @@ -168,6 +170,32 @@ 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 diff --git a/config.yaml b/config.yaml index 68f20ae8..f63a27e1 100644 --- a/config.yaml +++ b/config.yaml @@ -14,17 +14,21 @@ services: - "[STATUS] == 200" - "[BODY].deleted == false" - "len([BODY].text) > 0" - -auto-discover-k8s-services: true -k8s-service-suffix: ".svc.environment.local" - -k8s-service-config: - interval: 30s - conditions: - - "[STATUS] == 200" - -exclude-suffix: - - primary - - canary - -k8s-cluster-mode: "out" \ No newline at end of file +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: databases + service-suffix: "databases.svc.cluster.local" + health-api: "/health" + - name: services + service-suffix: "services.svc.cluster.local" + health-api: "/health" \ No newline at end of file diff --git a/config/config.go b/config/config.go index ddb44a79..36d46cf4 100644 --- a/config/config.go +++ b/config/config.go @@ -9,6 +9,7 @@ import ( "github.com/TwinProduction/gatus/alerting" "github.com/TwinProduction/gatus/alerting/provider" "github.com/TwinProduction/gatus/core" + "github.com/TwinProduction/gatus/k8s" "github.com/TwinProduction/gatus/security" "gopkg.in/yaml.v2" ) @@ -61,17 +62,7 @@ type Config struct { // Services List of services to monitor Services []*core.Service `yaml:"services"` - //AutoDiscoverK8SServices to discover services to monitor - AutoDiscoverK8SServices bool `yaml:"auto-discover-k8s-services"` - - //K8SServiceSuffix to append to service name - K8SServiceSuffix string `yaml:"k8s-service-suffix"` - - K8SServiceConfig core.Service `yaml:"k8s-service-config"` - - ExcludeSuffix []string `yaml:"exclude-suffix"` - - K8sClusterMode string `yaml:"k8s-cluster-mode"` + Kubernetes *k8s.Config `yaml:"kubernetes"` } // Get returns the configuration, or panics if the configuration hasn't loaded yet diff --git a/discovery/discovery.go b/discovery/discovery.go index 8a391958..133486c3 100644 --- a/discovery/discovery.go +++ b/discovery/discovery.go @@ -11,15 +11,23 @@ import ( //GetServices return discovered service func GetServices(cfg *config.Config) []*core.Service { - client := k8s.NewClient(cfg.K8sClusterMode) - services := k8s.GetServices(client, "services") + client := k8s.NewClient(cfg.Kubernetes.ClusterMode) svcs := make([]*core.Service, 0) - for _, s := range services { - if exclude(cfg.ExcludeSuffix, s.Name) { - continue + + for _, ns := range cfg.Kubernetes.Namespaces { + services := k8s.GetServices(client, ns.Name) + + for _, s := range services { + if exclude(cfg.Kubernetes.ExcludeSuffix, s.Name) { + continue + } + svc := core.Service{Name: s.Name, + URL: fmt.Sprintf("http://%s%s/%s", s.Name, ns.ServiceSuffix, ns.HealthAPI), + Interval: cfg.Kubernetes.ServiceTemplate.Interval, + Conditions: cfg.Kubernetes.ServiceTemplate.Conditions, + } + svcs = append(svcs, &svc) } - svc := core.Service{Name: s.Name, URL: fmt.Sprintf("http://%s%s/health", s.Name, cfg.K8SServiceSuffix), Interval: cfg.K8SServiceConfig.Interval, Conditions: cfg.K8SServiceConfig.Conditions} - svcs = append(svcs, &svc) } return svcs } diff --git a/k8s/config.go b/k8s/config.go new file mode 100644 index 00000000..65130441 --- /dev/null +++ b/k8s/config.go @@ -0,0 +1,31 @@ +package k8s + +import "github.com/TwinProduction/gatus/core" + +//Config for Kubernetes auto-discovery +type Config struct { + //AutoDiscover to discover services to monitor + AutoDiscover bool `yaml:"auto-discover"` + + //ServiceTemplate Template for auto disocovered services + ServiceTemplate core.Service `yaml:"service-template"` + + //ExcludeSuffix Ignore services with this suffix + ExcludeSuffix []string `yaml:"exclude-suffix"` + + //ClusterMode to authenticate with kubernetes + ClusterMode string `yaml:"cluster-mode"` + + //Namespaces from which to discover services + Namespaces []Namespace `yaml:"namespaces"` +} + +//Namespace level config +type Namespace struct { + //Name of namespace + Name string `yaml:"name"` + //ServiceSuffix to append to service name + ServiceSuffix string `yaml:"service-suffix"` + //HealthAPI URI to append to service to reach health check API + HealthAPI string `yaml:"health-api"` +} diff --git a/main.go b/main.go index ea626ac2..eb55ef42 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,7 @@ var ( func main() { cfg := loadConfiguration() - if cfg.AutoDiscoverK8SServices { + if cfg.Kubernetes.AutoDiscover { discoveredServices := discovery.GetServices(cfg) cfg.Services = append(cfg.Services, discoveredServices...) }