Add hub to the list of containers in pprof command and add flags to pprof command (#1603)

* Add hub to the list of containers in `pprof` command and add flags to `pprof` command

* Reduce duplication

---------

Co-authored-by: Alon Girmonsky <1990761+alongir@users.noreply.github.com>
This commit is contained in:
M. Mert Yildiran 2024-09-10 00:41:01 +03:00 committed by GitHub
parent 95637bfce8
commit 1c883c73e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 154 additions and 65 deletions

View File

@ -165,7 +165,7 @@ helm-install-debug:
cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.debug=true && cd .. cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.debug=true && cd ..
helm-install-profile: helm-install-profile:
cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.misc.profile=true && cd .. cd helm-chart && helm install kubeshark . --set tap.docker.tag=$(TAG) --set tap.pprof.enabled=true && cd ..
helm-uninstall: helm-uninstall:
helm uninstall kubeshark helm uninstall kubeshark

View File

@ -1,6 +1,9 @@
package cmd package cmd
import ( import (
"github.com/creasty/defaults"
"github.com/kubeshark/kubeshark/config/configStructs"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -15,4 +18,15 @@ var pprofCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(pprofCmd) rootCmd.AddCommand(pprofCmd)
defaultTapConfig := configStructs.TapConfig{}
if err := defaults.Set(&defaultTapConfig); err != nil {
log.Debug().Err(err).Send()
}
pprofCmd.Flags().Uint16(configStructs.ProxyFrontPortLabel, defaultTapConfig.Proxy.Front.Port, "Provide a custom port for the proxy/port-forward")
pprofCmd.Flags().String(configStructs.ProxyHostLabel, defaultTapConfig.Proxy.Host, "Provide a custom host for the proxy/port-forward")
pprofCmd.Flags().StringP(configStructs.ReleaseNamespaceLabel, "s", defaultTapConfig.Release.Namespace, "Release namespace of Kubeshark")
pprofCmd.Flags().Uint16(configStructs.PprofPortLabel, defaultTapConfig.Pprof.Port, "Provide a custom port for the pprof server")
pprofCmd.Flags().String(configStructs.PprofViewLabel, defaultTapConfig.Pprof.View, "Change the default view of the pprof web interface")
} }

View File

@ -10,6 +10,7 @@ import (
"github.com/kubeshark/kubeshark/utils" "github.com/kubeshark/kubeshark/utils"
"github.com/rivo/tview" "github.com/rivo/tview"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
v1 "k8s.io/api/core/v1"
) )
func runPprof() { func runPprof() {
@ -23,7 +24,16 @@ func runPprof() {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
pods, err := provider.ListPodsByAppLabel(ctx, config.Config.Tap.Release.Namespace, map[string]string{"app.kubeshark.co/app": "worker"}) hubPods, err := provider.ListPodsByAppLabel(ctx, config.Config.Tap.Release.Namespace, map[string]string{kubernetes.AppLabelKey: "hub"})
if err != nil {
log.Error().
Err(err).
Msg("Failed to list hub pods!")
cancel()
return
}
workerPods, err := provider.ListPodsByAppLabel(ctx, config.Config.Tap.Release.Namespace, map[string]string{kubernetes.AppLabelKey: "worker"})
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
@ -40,62 +50,39 @@ func runPprof() {
var currentCmd *cmd.Cmd var currentCmd *cmd.Cmd
i := 48 i := 48
for _, pod := range pods { for _, pod := range hubPods {
for _, container := range pod.Spec.Containers {
log.Info().Str("pod", pod.Name).Str("container", container.Name).Send()
homeUrl := fmt.Sprintf("%s/debug/pprof/", kubernetes.GetHubUrl())
modal := buildNewModal(
pod,
container,
homeUrl,
app,
list,
fullscreen,
currentCmd,
)
list.AddItem(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name), pod.Spec.NodeName, rune(i), func() {
app.SetRoot(modal, fullscreen)
})
i++
}
}
for _, pod := range workerPods {
for _, container := range pod.Spec.Containers { for _, container := range pod.Spec.Containers {
log.Info().Str("pod", pod.Name).Str("container", container.Name).Send() log.Info().Str("pod", pod.Name).Str("container", container.Name).Send()
homeUrl := fmt.Sprintf("%s/pprof/%s/%s/", kubernetes.GetHubUrl(), pod.Status.HostIP, container.Name) homeUrl := fmt.Sprintf("%s/pprof/%s/%s/", kubernetes.GetHubUrl(), pod.Status.HostIP, container.Name)
modal := tview.NewModal(). modal := buildNewModal(
SetText(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name)). pod,
AddButtons([]string{ container,
"Open Debug Home Page", homeUrl,
"Profile: CPU", app,
"Profile: Memory", list,
"Profile: Goroutine", fullscreen,
"Cancel", currentCmd,
}). )
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
switch buttonLabel {
case "Open Debug Home Page":
utils.OpenBrowser(homeUrl)
case "Profile: CPU":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", ":8000", fmt.Sprintf("%sprofile", homeUrl))
currentCmd.Start()
case "Profile: Memory":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", ":8000", fmt.Sprintf("%sheap", homeUrl))
currentCmd.Start()
case "Profile: Goroutine":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", ":8000", fmt.Sprintf("%sgoroutine", homeUrl))
currentCmd.Start()
case "Cancel":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
fallthrough
default:
app.SetRoot(list, fullscreen)
}
})
list.AddItem(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name), pod.Spec.NodeName, rune(i), func() { list.AddItem(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name), pod.Spec.NodeName, rune(i), func() {
app.SetRoot(modal, fullscreen) app.SetRoot(modal, fullscreen)
}) })
@ -117,3 +104,73 @@ func runPprof() {
panic(err) panic(err)
} }
} }
func buildNewModal(
pod v1.Pod,
container v1.Container,
homeUrl string,
app *tview.Application,
list *tview.List,
fullscreen bool,
currentCmd *cmd.Cmd,
) *tview.Modal {
return tview.NewModal().
SetText(fmt.Sprintf("pod: %s container: %s", pod.Name, container.Name)).
AddButtons([]string{
"Open Debug Home Page",
"Profile: CPU",
"Profile: Memory",
"Profile: Goroutine",
"Cancel",
}).
SetDoneFunc(func(buttonIndex int, buttonLabel string) {
var err error
port := fmt.Sprintf(":%d", config.Config.Tap.Pprof.Port)
view := fmt.Sprintf("http://localhost%s/ui/%s", port, config.Config.Tap.Pprof.View)
switch buttonLabel {
case "Open Debug Home Page":
utils.OpenBrowser(homeUrl)
case "Profile: CPU":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sprofile", homeUrl))
currentCmd.Start()
utils.OpenBrowser(view)
case "Profile: Memory":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sheap", homeUrl))
currentCmd.Start()
utils.OpenBrowser(view)
case "Profile: Goroutine":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
currentCmd = cmd.NewCmd("go", "tool", "pprof", "-http", port, "-no_browser", fmt.Sprintf("%sgoroutine", homeUrl))
currentCmd.Start()
utils.OpenBrowser(view)
case "Cancel":
if currentCmd != nil {
err = currentCmd.Stop()
if err != nil {
log.Error().Err(err).Str("name", currentCmd.Name).Msg("Failed to stop process!")
}
}
fallthrough
default:
app.SetRoot(list, fullscreen)
}
})
}

View File

@ -70,6 +70,7 @@ func InitConfig(cmd *cobra.Command) error {
"pro", "pro",
"proxy", "proxy",
"scripts", "scripts",
"pprof",
}, cmdName) { }, cmdName) {
cmdName = "tap" cmdName = "tap"
} }

View File

@ -31,6 +31,8 @@ const (
IgnoreTaintedLabel = "ignoreTainted" IgnoreTaintedLabel = "ignoreTainted"
IngressEnabledLabel = "ingress-enabled" IngressEnabledLabel = "ingress-enabled"
TelemetryEnabledLabel = "telemetry-enabled" TelemetryEnabledLabel = "telemetry-enabled"
PprofPortLabel = "pprof-port"
PprofViewLabel = "pprof-view"
DebugLabel = "debug" DebugLabel = "debug"
ContainerPort = 80 ContainerPort = 80
ContainerPortStr = "80" ContainerPortStr = "80"
@ -159,6 +161,12 @@ type MetricsConfig struct {
Port uint16 `yaml:"port" json:"port" default:"49100"` Port uint16 `yaml:"port" json:"port" default:"49100"`
} }
type PprofConfig struct {
Enabled bool `yaml:"enabled" json:"enabled" default:"false"`
Port uint16 `yaml:"port" json:"port" default:"8000"`
View string `yaml:"view" json:"view" default:"flamegraph"`
}
type MiscConfig struct { type MiscConfig struct {
JsonTTL string `yaml:"jsonTTL" json:"jsonTTL" default:"5m"` JsonTTL string `yaml:"jsonTTL" json:"jsonTTL" default:"5m"`
PcapTTL string `yaml:"pcapTTL" json:"pcapTTL" default:"10s"` PcapTTL string `yaml:"pcapTTL" json:"pcapTTL" default:"10s"`
@ -167,7 +175,6 @@ type MiscConfig struct {
TcpStreamChannelTimeoutMs int `yaml:"tcpStreamChannelTimeoutMs" json:"tcpStreamChannelTimeoutMs" default:"10000"` TcpStreamChannelTimeoutMs int `yaml:"tcpStreamChannelTimeoutMs" json:"tcpStreamChannelTimeoutMs" default:"10000"`
TcpStreamChannelTimeoutShow bool `yaml:"tcpStreamChannelTimeoutShow" json:"tcpStreamChannelTimeoutShow" default:"false"` TcpStreamChannelTimeoutShow bool `yaml:"tcpStreamChannelTimeoutShow" json:"tcpStreamChannelTimeoutShow" default:"false"`
ResolutionStrategy string `yaml:"resolutionStrategy" json:"resolutionStrategy" default:"auto"` ResolutionStrategy string `yaml:"resolutionStrategy" json:"resolutionStrategy" default:"auto"`
Profile bool `yaml:"profile" json:"profile" default:"false"`
DuplicateTimeframe string `yaml:"duplicateTimeframe" json:"duplicateTimeframe" default:"200ms"` DuplicateTimeframe string `yaml:"duplicateTimeframe" json:"duplicateTimeframe" default:"200ms"`
DetectDuplicates bool `yaml:"detectDuplicates" json:"detectDuplicates" default:"false"` DetectDuplicates bool `yaml:"detectDuplicates" json:"detectDuplicates" default:"false"`
} }
@ -211,6 +218,7 @@ type TapConfig struct {
GlobalFilter string `yaml:"globalFilter" json:"globalFilter"` GlobalFilter string `yaml:"globalFilter" json:"globalFilter"`
EnabledDissectors []string `yaml:"enabledDissectors" json:"enabledDissectors"` EnabledDissectors []string `yaml:"enabledDissectors" json:"enabledDissectors"`
Metrics MetricsConfig `yaml:"metrics" json:"metrics"` Metrics MetricsConfig `yaml:"metrics" json:"metrics"`
Pprof PprofConfig `yaml:"pprof" json:"pprof"`
Misc MiscConfig `yaml:"misc" json:"misc"` Misc MiscConfig `yaml:"misc" json:"misc"`
} }

View File

@ -26,7 +26,7 @@ spec:
dnsPolicy: ClusterFirstWithHostNet dnsPolicy: ClusterFirstWithHostNet
serviceAccountName: {{ include "kubeshark.serviceAccountName" . }} serviceAccountName: {{ include "kubeshark.serviceAccountName" . }}
containers: containers:
- name: kubeshark-hub - name: hub
command: command:
- ./hub - ./hub
- -port - -port
@ -46,7 +46,7 @@ spec:
- name: KUBESHARK_CLOUD_API_URL - name: KUBESHARK_CLOUD_API_URL
value: 'https://api.kubeshark.co' value: 'https://api.kubeshark.co'
- name: PROFILING_ENABLED - name: PROFILING_ENABLED
value: '{{ .Values.tap.misc.profile }}' value: '{{ .Values.tap.pprof.enabled }}'
{{- if .Values.tap.docker.overrideTag.hub }} {{- if .Values.tap.docker.overrideTag.hub }}
image: '{{ .Values.tap.docker.registry }}/hub:{{ .Values.tap.docker.overrideTag.hub }}' image: '{{ .Values.tap.docker.registry }}/hub:{{ .Values.tap.docker.overrideTag.hub }}'
{{ else }} {{ else }}

View File

@ -97,7 +97,7 @@ spec:
- name: KUBESHARK_CLOUD_API_URL - name: KUBESHARK_CLOUD_API_URL
value: 'https://api.kubeshark.co' value: 'https://api.kubeshark.co'
- name: PROFILING_ENABLED - name: PROFILING_ENABLED
value: '{{ .Values.tap.misc.profile }}' value: '{{ .Values.tap.pprof.enabled }}'
resources: resources:
limits: limits:
cpu: {{ .Values.tap.resources.sniffer.limits.cpu }} cpu: {{ .Values.tap.resources.sniffer.limits.cpu }}
@ -169,7 +169,7 @@ spec:
{{- if .Values.tap.disableTlsLog }} {{- if .Values.tap.disableTlsLog }}
- -disable-tls-log - -disable-tls-log
{{- end }} {{- end }}
{{- if .Values.tap.misc.profile }} {{- if .Values.tap.pprof.enabled }}
- -port - -port
- '{{ add .Values.tap.proxy.worker.srvPort 1 }}' - '{{ add .Values.tap.proxy.worker.srvPort 1 }}'
{{- end }} {{- end }}
@ -190,7 +190,7 @@ spec:
fieldRef: fieldRef:
fieldPath: metadata.namespace fieldPath: metadata.namespace
- name: PROFILING_ENABLED - name: PROFILING_ENABLED
value: '{{ .Values.tap.misc.profile }}' value: '{{ .Values.tap.pprof.enabled }}'
resources: resources:
limits: limits:
cpu: {{ .Values.tap.resources.tracer.limits.cpu }} cpu: {{ .Values.tap.resources.tracer.limits.cpu }}

View File

@ -60,7 +60,7 @@ Escape double quotes in a string
Define debug docker tag suffix Define debug docker tag suffix
*/}} */}}
{{- define "kubeshark.dockerTagDebugVersion" -}} {{- define "kubeshark.dockerTagDebugVersion" -}}
{{- .Values.tap.misc.profile | ternary "-debug" "" }} {{- .Values.tap.pprof.enabled | ternary "-debug" "" }}
{{- end -}} {{- end -}}
{{/* {{/*

View File

@ -131,6 +131,10 @@ tap:
- ws - ws
metrics: metrics:
port: 49100 port: 49100
pprof:
enabled: false
port: 8000
view: flamegraph
misc: misc:
jsonTTL: 5m jsonTTL: 5m
pcapTTL: 10s pcapTTL: 10s
@ -139,7 +143,6 @@ tap:
tcpStreamChannelTimeoutMs: 10000 tcpStreamChannelTimeoutMs: 10000
tcpStreamChannelTimeoutShow: false tcpStreamChannelTimeoutShow: false
resolutionStrategy: auto resolutionStrategy: auto
profile: false
duplicateTimeframe: 200ms duplicateTimeframe: 200ms
detectDuplicates: false detectDuplicates: false
logs: logs:

View File

@ -8,4 +8,5 @@ const (
HubServiceName = HubPodName HubServiceName = HubPodName
K8sAllNamespaces = "" K8sAllNamespaces = ""
MinKubernetesServerVersion = "1.16.0" MinKubernetesServerVersion = "1.16.0"
AppLabelKey = "app.kubeshark.co/app"
) )

View File

@ -106,7 +106,7 @@ func getRerouteHttpHandlerSelfStatic(proxyHandler http.Handler, selfNamespace st
} }
func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *regexp.Regexp, srcPort uint16, dstPort uint16, ctx context.Context) (*portforward.PortForwarder, error) { func NewPortForward(kubernetesProvider *Provider, namespace string, podRegex *regexp.Regexp, srcPort uint16, dstPort uint16, ctx context.Context) (*portforward.PortForwarder, error) {
pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, namespace, map[string]string{"app.kubeshark.co/app": "front"}) pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, namespace, map[string]string{AppLabelKey: "front"})
if err != nil { if err != nil {
return nil, err return nil, err
} else if len(pods) == 0 { } else if len(pods) == 0 {

View File

@ -250,6 +250,7 @@ data:
CLOUD_LICENSE_ENABLED: 'true' CLOUD_LICENSE_ENABLED: 'true'
DUPLICATE_TIMEFRAME: '200ms' DUPLICATE_TIMEFRAME: '200ms'
ENABLED_DISSECTORS: 'amqp,dns,http,icmp,kafka,redis,sctp,syscall,tcp,ws' ENABLED_DISSECTORS: 'amqp,dns,http,icmp,kafka,redis,sctp,syscall,tcp,ws'
DISSECTORS_UPDATING_ENABLED: 'true'
DETECT_DUPLICATES: 'false' DETECT_DUPLICATES: 'false'
--- ---
# Source: kubeshark/templates/02-cluster-role.yaml # Source: kubeshark/templates/02-cluster-role.yaml
@ -669,7 +670,7 @@ spec:
dnsPolicy: ClusterFirstWithHostNet dnsPolicy: ClusterFirstWithHostNet
serviceAccountName: kubeshark-service-account serviceAccountName: kubeshark-service-account
containers: containers:
- name: kubeshark-hub - name: hub
command: command:
- ./hub - ./hub
- -port - -port
@ -685,6 +686,8 @@ spec:
fieldPath: metadata.namespace fieldPath: metadata.namespace
- name: KUBESHARK_CLOUD_API_URL - name: KUBESHARK_CLOUD_API_URL
value: 'https://api.kubeshark.co' value: 'https://api.kubeshark.co'
- name: PROFILING_ENABLED
value: 'false'
image: 'docker.io/kubeshark/hub:v52.3.79' image: 'docker.io/kubeshark/hub:v52.3.79'
imagePullPolicy: Always imagePullPolicy: Always
readinessProbe: readinessProbe:
@ -784,6 +787,8 @@ spec:
value: 'true' value: 'true'
- name: REACT_APP_SUPPORT_CHAT_ENABLED - name: REACT_APP_SUPPORT_CHAT_ENABLED
value: 'true' value: 'true'
- name: REACT_APP_DISSECTORS_UPDATING_ENABLED
value: 'true'
image: 'docker.io/kubeshark/front:v52.3.79' image: 'docker.io/kubeshark/front:v52.3.79'
imagePullPolicy: Always imagePullPolicy: Always
name: kubeshark-front name: kubeshark-front