From cbf3832c3fea76702fcb58c5c0ac8d009ddee6a7 Mon Sep 17 00:00:00 2001 From: Steve Wagner Date: Fri, 10 Feb 2023 16:31:36 -0800 Subject: [PATCH] Add basic probe checks Start Probez --- cmd/nginx-k8s-edge-controller/main.go | 4 ++ deployment/nkl-deployment.yaml | 16 +++++ internal/probation/check.go | 30 +++++++++ internal/probation/doc.go | 9 +++ internal/probation/server.go | 87 +++++++++++++++++++++++++++ 5 files changed, 146 insertions(+) create mode 100644 internal/probation/check.go create mode 100644 internal/probation/doc.go create mode 100644 internal/probation/server.go diff --git a/cmd/nginx-k8s-edge-controller/main.go b/cmd/nginx-k8s-edge-controller/main.go index 0014481..70ee59e 100644 --- a/cmd/nginx-k8s-edge-controller/main.go +++ b/cmd/nginx-k8s-edge-controller/main.go @@ -9,6 +9,7 @@ import ( "fmt" "github.com/nginxinc/kubernetes-nginx-ingress/internal/config" "github.com/nginxinc/kubernetes-nginx-ingress/internal/observation" + "github.com/nginxinc/kubernetes-nginx-ingress/internal/probation" "github.com/nginxinc/kubernetes-nginx-ingress/internal/synchronization" "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" @@ -68,6 +69,9 @@ func run() error { go handler.Run(ctx.Done()) go synchronizer.Run(ctx.Done()) + probeServer := probation.NewHealthServer() + probeServer.Start() + err = watcher.Watch() if err != nil { return fmt.Errorf(`error occurred watching for events: %w`, err) diff --git a/deployment/nkl-deployment.yaml b/deployment/nkl-deployment.yaml index db00339..ca72b02 100644 --- a/deployment/nkl-deployment.yaml +++ b/deployment/nkl-deployment.yaml @@ -21,4 +21,20 @@ spec: value: "http://10.1.1.4:9000/api" image: ciroque/nginx-k8s-edge-controller:latest imagePullPolicy: Always + ports: + - name: http + containerPort: 51031 + protocol: TCP + livenessProbe: + httpGet: + path: /livez + port: http + initialDelaySeconds: 5 + periodSeconds: 2 + readinessProbe: + httpGet: + path: /readyz + port: http + initialDelaySeconds: 5 + periodSeconds: 2 serviceAccountName: nginx-k8s-edge-controller diff --git a/internal/probation/check.go b/internal/probation/check.go new file mode 100644 index 0000000..8888146 --- /dev/null +++ b/internal/probation/check.go @@ -0,0 +1,30 @@ +// Copyright 2023 f5 Inc. All rights reserved. +// Use of this source code is governed by the Apache +// license that can be found in the LICENSE file. + +package probation + +type Check interface { + Check() bool +} + +type LiveCheck struct { +} + +type ReadyCheck struct { +} + +type StartupCheck struct { +} + +func (l *LiveCheck) Check() bool { + return true +} + +func (r *ReadyCheck) Check() bool { + return true +} + +func (s *StartupCheck) Check() bool { + return true +} diff --git a/internal/probation/doc.go b/internal/probation/doc.go new file mode 100644 index 0000000..90ac15a --- /dev/null +++ b/internal/probation/doc.go @@ -0,0 +1,9 @@ +// Copyright 2023 f5 Inc. All rights reserved. +// Use of this source code is governed by the Apache +// license that can be found in the LICENSE file. + +/* +Package probation includes support for Kubernetes health and wellness checks. +*/ + +package probation diff --git a/internal/probation/server.go b/internal/probation/server.go new file mode 100644 index 0000000..78a1c75 --- /dev/null +++ b/internal/probation/server.go @@ -0,0 +1,87 @@ +// Copyright 2023 f5 Inc. All rights reserved. +// Use of this source code is governed by the Apache +// license that can be found in the LICENSE file. + +package probation + +import ( + "fmt" + "github.com/sirupsen/logrus" + "net/http" +) + +const ( + Ok = "OK" + ServiceNotAvailable = "Service Not Available" + ListenPort = 51031 +) + +type HealthServer struct { + httpServer *http.Server + LiveCheck LiveCheck + ReadyCheck ReadyCheck + StartupCheck StartupCheck +} + +func NewHealthServer() *HealthServer { + return &HealthServer{ + LiveCheck: LiveCheck{}, + ReadyCheck: ReadyCheck{}, + StartupCheck: StartupCheck{}, + } +} + +func (hs *HealthServer) Start() { + logrus.Debugf("Starting probe listener on port %d", ListenPort) + + address := fmt.Sprintf(":%d", ListenPort) + + mux := http.NewServeMux() + mux.HandleFunc("/livez", hs.HandleLive) + mux.HandleFunc("/readyz", hs.HandleReady) + mux.HandleFunc("/startupz", hs.HandleStartup) + hs.httpServer = &http.Server{Addr: address, Handler: mux} + + go func() { + if err := hs.httpServer.ListenAndServe(); err != nil { + logrus.Errorf("unable to start probe listener on %s: %v", hs.httpServer.Addr, err) + } + }() + + logrus.Info("Started probe listener on", hs.httpServer.Addr) +} + +func (hs *HealthServer) Stop() { + if err := hs.httpServer.Close(); err != nil { + logrus.Errorf("unable to stop probe listener on %s: %v", hs.httpServer.Addr, err) + } +} + +func (hs *HealthServer) HandleLive(writer http.ResponseWriter, request *http.Request) { + handleProbe(writer, request, &hs.LiveCheck) +} + +func (hs *HealthServer) HandleReady(writer http.ResponseWriter, request *http.Request) { + handleProbe(writer, request, &hs.ReadyCheck) +} + +func (hs *HealthServer) HandleStartup(writer http.ResponseWriter, request *http.Request) { + handleProbe(writer, request, &hs.StartupCheck) +} + +func handleProbe(writer http.ResponseWriter, _ *http.Request, check Check) { + if check.Check() { + writer.WriteHeader(http.StatusOK) + + if _, err := fmt.Fprint(writer, Ok); err != nil { + logrus.Error(err) + } + + } else { + writer.WriteHeader(http.StatusServiceUnavailable) + + if _, err := fmt.Fprint(writer, ServiceNotAvailable); err != nil { + logrus.Error(err) + } + } +}