Skip to content

Commit 3ec9c7f

Browse files
authored
Merge pull request kubernetes#128811 from zhifei92/statusz
add statusz endpoint for kubelet
2 parents 80379db + 75e5bd6 commit 3ec9c7f

File tree

6 files changed

+29
-10
lines changed

6 files changed

+29
-10
lines changed

cmd/kubelet/app/server.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,9 @@ func init() {
132132
otel.SetMeterProvider(noop.NewMeterProvider())
133133
}
134134

135-
const (
136-
// Kubelet component name
137-
componentKubelet = "kubelet"
138-
)
139-
140135
// NewKubeletCommand creates a *cobra.Command object with default parameters
141136
func NewKubeletCommand() *cobra.Command {
142-
cleanFlagSet := pflag.NewFlagSet(componentKubelet, pflag.ContinueOnError)
137+
cleanFlagSet := pflag.NewFlagSet(server.ComponentKubelet, pflag.ContinueOnError)
143138
cleanFlagSet.SetNormalizeFunc(cliflag.WordSepNormalizeFunc)
144139
kubeletFlags := options.NewKubeletFlags()
145140

@@ -151,7 +146,7 @@ func NewKubeletCommand() *cobra.Command {
151146
}
152147

153148
cmd := &cobra.Command{
154-
Use: componentKubelet,
149+
Use: server.ComponentKubelet,
155150
Long: `The kubelet is the primary "node agent" that runs on each
156151
node. It can register the node with the apiserver using one of: the hostname; a flag to
157152
override the hostname; or specific logic for a cloud provider.
@@ -562,7 +557,7 @@ func makeEventRecorder(ctx context.Context, kubeDeps *kubelet.Dependencies, node
562557
return
563558
}
564559
eventBroadcaster := record.NewBroadcaster(record.WithContext(ctx))
565-
kubeDeps.Recorder = eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: componentKubelet, Host: string(nodeName)})
560+
kubeDeps.Recorder = eventBroadcaster.NewRecorder(legacyscheme.Scheme, v1.EventSource{Component: server.ComponentKubelet, Host: string(nodeName)})
566561
eventBroadcaster.StartStructuredLogging(3)
567562
if kubeDeps.EventClient != nil {
568563
klog.V(4).InfoS("Sending events to api server")
@@ -1386,7 +1381,7 @@ func newTracerProvider(s *options.KubeletServer) (oteltrace.TracerProvider, erro
13861381
}
13871382
resourceOpts := []otelsdkresource.Option{
13881383
otelsdkresource.WithAttributes(
1389-
semconv.ServiceNameKey.String(componentKubelet),
1384+
semconv.ServiceNameKey.String(server.ComponentKubelet),
13901385
semconv.HostNameKey.String(hostname),
13911386
),
13921387
}

pkg/kubelet/server/auth.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/apiserver/pkg/server/healthz"
2828
utilfeature "k8s.io/apiserver/pkg/util/feature"
2929
"k8s.io/component-base/configz"
30+
"k8s.io/component-base/zpages/statusz"
3031
"k8s.io/klog/v2"
3132
"k8s.io/kubernetes/pkg/features"
3233
)
@@ -68,6 +69,7 @@ func isSubpath(subpath, path string) bool {
6869
// /metrics/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=metrics
6970
// /logs/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=log
7071
// /checkpoint/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=checkpoint
72+
// /statusz => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=statusz
7173
// /pods/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=pods,proxy
7274
// /runningPods/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=pods,proxy
7375
// /healthz/* => verb=<api verb from request>, resource=nodes, name=<node name>, subresource(s)=healthz,proxy
@@ -116,6 +118,8 @@ func (n nodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *htt
116118
subresources = append(subresources, "log")
117119
case isSubpath(requestPath, checkpointPath):
118120
subresources = append(subresources, "checkpoint")
121+
case isSubpath(requestPath, statusz.DefaultStatuszPath):
122+
subresources = append(subresources, "statusz")
119123
default:
120124
subresources = append(subresources, "proxy")
121125
}

pkg/kubelet/server/auth_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func AuthzTestCases(fineGrained bool) []AuthzTestCase {
125125
"/attach/{podNamespace}/{podID}/{uid}/{containerName}": {"proxy"},
126126
"/checkpoint/{podNamespace}/{podID}/{containerName}": {"checkpoint"},
127127
"/configz": {"proxy"},
128+
"/statusz": {"statusz"},
128129
"/containerLogs/{podNamespace}/{podID}/{containerName}": {"proxy"},
129130
"/debug/flags/v": {"proxy"},
130131
"/debug/pprof/{subpath:*}": {"proxy"},

pkg/kubelet/server/server.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ import (
6767
metricsfeatures "k8s.io/component-base/metrics/features"
6868
"k8s.io/component-base/metrics/legacyregistry"
6969
"k8s.io/component-base/metrics/prometheus/slis"
70+
zpagesfeatures "k8s.io/component-base/zpages/features"
71+
"k8s.io/component-base/zpages/statusz"
7072
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
7173
"k8s.io/cri-client/pkg/util"
7274
podresourcesapi "k8s.io/kubelet/pkg/apis/podresources/v1"
@@ -107,6 +109,11 @@ const (
107109
runningPodsPath = "/runningpods/"
108110
)
109111

112+
const (
113+
// Kubelet component name
114+
ComponentKubelet = "kubelet"
115+
)
116+
110117
// Server is a http.Handler which exposes kubelet functionality over HTTP.
111118
type Server struct {
112119
auth AuthInterface
@@ -567,6 +574,11 @@ func (s *Server) InstallDebuggingHandlers() {
567574
s.addMetricsBucketMatcher("configz")
568575
configz.InstallHandler(s.restfulCont)
569576

577+
if utilfeature.DefaultFeatureGate.Enabled(zpagesfeatures.ComponentStatusz) {
578+
s.addMetricsBucketMatcher("statusz")
579+
statusz.Install(s.restfulCont, ComponentKubelet, statusz.NewRegistry())
580+
}
581+
570582
// The /runningpods endpoint is used for testing only.
571583
s.addMetricsBucketMatcher("runningpods")
572584
ws = new(restful.WebService)

pkg/kubelet/server/server_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import (
5757
"k8s.io/apiserver/pkg/server/healthz"
5858
utilfeature "k8s.io/apiserver/pkg/util/feature"
5959
featuregatetesting "k8s.io/component-base/featuregate/testing"
60+
zpagesfeatures "k8s.io/component-base/zpages/features"
6061
"k8s.io/kubelet/pkg/cri/streaming"
6162
"k8s.io/kubelet/pkg/cri/streaming/portforward"
6263
remotecommandserver "k8s.io/kubelet/pkg/cri/streaming/remotecommand"
@@ -572,6 +573,7 @@ func TestAuthzCoverage(t *testing.T) {
572573
func TestAuthFilters(t *testing.T) {
573574
// Enable features.ContainerCheckpoint during test
574575
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ContainerCheckpoint, true)
576+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, zpagesfeatures.ComponentStatusz, true)
575577

576578
fw := newServerTest()
577579
defer fw.testHTTPServer.Close()
@@ -1617,6 +1619,8 @@ func TestServePortForward(t *testing.T) {
16171619
}
16181620

16191621
func TestMetricBuckets(t *testing.T) {
1622+
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, zpagesfeatures.ComponentStatusz, true)
1623+
16201624
tests := map[string]struct {
16211625
url string
16221626
bucket string
@@ -1648,6 +1652,7 @@ func TestMetricBuckets(t *testing.T) {
16481652
"runningpods": {url: "/runningpods/", bucket: "runningpods"},
16491653
"stats": {url: "/stats/", bucket: "stats"},
16501654
"stats summary sub": {url: "/stats/summary", bucket: "stats"},
1655+
"statusz": {url: "/statusz", bucket: "statusz"},
16511656
"invalid path": {url: "/junk", bucket: "other"},
16521657
"invalid path starting with good": {url: "/healthzjunk", bucket: "other"},
16531658
}

staging/src/k8s.io/component-base/zpages/statusz/statusz.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ var (
3535
errUnsupportedMediaType = fmt.Errorf("media type not acceptable, must be: text/plain")
3636
)
3737

38+
const DefaultStatuszPath = "/statusz"
39+
3840
const (
3941
headerFmt = `
4042
%s statusz
@@ -73,7 +75,7 @@ func Install(m mux, componentName string, reg statuszRegistry) {
7375
klog.Errorf("error while parsing gotemplates: %v", err)
7476
return
7577
}
76-
m.Handle("/statusz", handleStatusz(componentName, dataTmpl, reg))
78+
m.Handle(DefaultStatuszPath, handleStatusz(componentName, dataTmpl, reg))
7779
}
7880

7981
func initializeTemplates() (*template.Template, error) {

0 commit comments

Comments
 (0)