Skip to content

Commit

Permalink
feat(kic 2.0) add profiling
Browse files Browse the repository at this point in the history
Signed-off-by: Tharun <rajendrantharun@live.com>
  • Loading branch information
tharun208 committed Jun 10, 2021
1 parent b7d67dd commit 7f42e5b
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ released and the release notes may change significantly before then.

#### Added

- added support for profiling in KIC 2.0.
[#1408](https://github.com/Kong/kubernetes-ingress-controller/pull/1408)
- support for [UDP][kong-udp] via the new `UDPIngress` API.
- `--watch-namespace` now supports multiple distinct namespaces versus simply
supporting all namespaces (the default) or a single namespace. To watch
Expand Down
54 changes: 54 additions & 0 deletions railgun/internal/diagnostics/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package diagnostics

import (
"context"
"fmt"
"net/http"

"github.com/kong/kubernetes-ingress-controller/railgun/internal/mgrutils"
"github.com/kong/kubernetes-ingress-controller/railgun/pkg/config"
"github.com/sirupsen/logrus"
)

type diagnosticsServer struct {
logger logrus.FieldLogger
mux *http.ServeMux
}

func NewDiagnosticsServer(enableProfiling bool, log logrus.FieldLogger) *diagnosticsServer {
mux := http.NewServeMux()
if enableProfiling {
mgrutils.Install(mux)
}
return &diagnosticsServer{
logger: log,
mux: mux,
}
}

func (s *diagnosticsServer) Start(ctx context.Context) error {
httpServer := &http.Server{Addr: fmt.Sprintf(":%d", config.DiagnosticsPort), Handler: s.mux}
errChan := make(chan error)
go func() {
err := httpServer.ListenAndServe()
if err != nil {
switch err {
case http.ErrServerClosed:
s.logger.Info("shutting down diagnostics server")
default:
s.logger.Error(err, "could not start a diagnostics server")
errChan <- err
}
}
}()

s.logger.Info("started diagnostics server at port ", config.DiagnosticsPort)

select {
case <-ctx.Done():
s.logger.Info("stopping down diagnostics server")
return httpServer.Shutdown(context.Background())
case err := <-errChan:
return err
}
}
28 changes: 28 additions & 0 deletions railgun/internal/mgrutils/profiling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mgrutils

import (
"net/http"
"net/http/pprof"
)

// Install adds the Profiling webservice to the given mux.
func Install(mux *http.ServeMux) {
mux.HandleFunc("/debug/pprof", redirectTo("/debug/pprof/"))
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/heap", pprof.Index)
mux.HandleFunc("/debug/pprof/mutex", pprof.Index)
mux.HandleFunc("/debug/pprof/goroutine", pprof.Index)
mux.HandleFunc("/debug/pprof/threadcreate", pprof.Index)
mux.HandleFunc("/debug/pprof/block", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
}

// redirectTo redirects request to a certain destination.
func redirectTo(to string) func(http.ResponseWriter, *http.Request) {
return func(rw http.ResponseWriter, req *http.Request) {
http.Redirect(rw, req, to, http.StatusFound)
}
}
8 changes: 8 additions & 0 deletions railgun/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
configurationv1beta1 "github.com/kong/kubernetes-ingress-controller/railgun/apis/configuration/v1beta1"
"github.com/kong/kubernetes-ingress-controller/railgun/controllers/configuration"
kongctrl "github.com/kong/kubernetes-ingress-controller/railgun/controllers/configuration"
"github.com/kong/kubernetes-ingress-controller/railgun/internal/diagnostics"
"github.com/kong/kubernetes-ingress-controller/railgun/internal/mgrutils"
"github.com/kong/kubernetes-ingress-controller/railgun/internal/proxy"
"github.com/kong/kubernetes-ingress-controller/railgun/pkg/config"
Expand Down Expand Up @@ -268,6 +269,13 @@ func Run(ctx context.Context, c *config.Config) error {
setupLog.Info("anonymous reports disabled, skipping")
}

diagnosticsServer := diagnostics.NewDiagnosticsServer(c.EnableProfiling, deprecatedLogger.WithField("component", "metadata-server"))
go func() {
setupLog.Info("starting diagnostics server")
if err := diagnosticsServer.Start(ctx); err != nil {
setupLog.Error(err, "unable to start diagnostics server")
}
}()
setupLog.Info("starting manager")
return mgr.Start(ctx)
}
6 changes: 6 additions & 0 deletions railgun/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ type Config struct {

// Admission Webhook server config
AdmissionServer admission.ServerConfig

// Performance
EnableProfiling bool
}

// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -157,6 +160,9 @@ func (c *Config) FlagSet() *pflag.FlagSet {
flagSet.StringVar(&c.AdmissionServer.Key, "admission-webhook-key", "",
`admission server PEM private key value`)

// Misc
flagSet.BoolVar(&c.EnableProfiling, "profiling", false, "Enable profiling via web interface host:port/debug/pprof/")

return &flagSet.FlagSet
}

Expand Down
3 changes: 3 additions & 0 deletions railgun/pkg/config/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ const HealthzPort = 10254
// Similar to HealthzPort, it may be used in existing user deployment configurations, and its
// literal value is used in several stock manifests, which must be updated along with this value.
const MetricsPort = 10255

// DiagnosticsPort is the default port of the manager's diagnostics service listens on.
const DiagnosticsPort = 10256
17 changes: 17 additions & 0 deletions railgun/test/integration/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,20 @@ func TestMetricsEndpoint(t *testing.T) {
return len(v) > 0
}, ingressWait, waitTick)
}

func TestProfilingEndpoint(t *testing.T) {
if useLegacyKIC() {
t.Skip("profiling endpoint behaves differently in legacy KIC")
}
_ = proxyReady()
assert.Eventually(t, func() bool {
profilingURL := fmt.Sprintf("http://localhost:%v/debug/pprof/", config.DiagnosticsPort)
resp, err := httpc.Get(profilingURL)
if err != nil {
t.Logf("WARNING: error while waiting for %s: %v", profilingURL, err)
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}, ingressWait, waitTick)
}
1 change: 1 addition & 0 deletions railgun/test/integration/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ func deployControllers(ctx context.Context, ready chan ktfkind.ProxyReadinessEve
"--admission-webhook-listen=172.17.0.1:49023",
fmt.Sprintf("--admission-webhook-cert=%s", admissionWebhookCert),
fmt.Sprintf("--admission-webhook-key=%s", admissionWebhookKey),
"--profiling",
})
fmt.Fprintf(os.Stderr, "config: %+v\n", config)

Expand Down

0 comments on commit 7f42e5b

Please sign in to comment.