Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standardize the health probe and metrics arguments of scheduler. #5437

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion artifacts/deploy/karmada-scheduler.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ spec:
- /bin/karmada-scheduler
- --kubeconfig=/etc/kubeconfig
- --bind-address=0.0.0.0
- --secure-port=10351
- --metrics-bind-address=0.0.0.0:10351
- --health-probe-bind-address=0.0.0.0:10351
- --enable-scheduler-estimator=true
- --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt
- --scheduler-estimator-cert-file=/etc/karmada/pki/karmada.crt
Expand Down
20 changes: 20 additions & 0 deletions cmd/scheduler/app/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,24 @@ type Options struct {
KubeConfig string
Master string
// BindAddress is the IP address on which to listen for the --secure-port port.
// Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+.
BindAddress string
// SecurePort is the port that the server serves at.
// Deprecated: To specify the TCP address for serving health probes, use HealthProbeBindAddress instead. To specify the TCP address for serving prometheus metrics, use MetricsBindAddress instead. This will be removed in release 1.12+.
SecurePort int

// MetricsBindAddress is the TCP address that the controller should bind to
// for serving prometheus metrics.
// It can be set to "0" to disable the metrics serving.
// Defaults to ":10351".
MetricsBindAddress string

// HealthProbeBindAddress is the TCP address that the controller should bind to
// for serving health probes
// It can be set to "0" or "" to disable serving the health probe.
// Defaults to ":10351".
HealthProbeBindAddress string

// KubeAPIQPS is the QPS to use while talking with karmada-apiserver.
KubeAPIQPS float32
// KubeAPIBurst is the burst to allow while talking with karmada-apiserver.
Expand Down Expand Up @@ -139,6 +153,12 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&o.Master, "master", o.Master, "The address of the Kubernetes API server. Overrides any value in KubeConfig. Only required if out-of-cluster.")
fs.StringVar(&o.BindAddress, "bind-address", defaultBindAddress, "The IP address on which to listen for the --secure-port port.")
fs.IntVar(&o.SecurePort, "secure-port", defaultPort, "The secure port on which to serve HTTPS.")
// nolint: errcheck
fs.MarkDeprecated("bind-address", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.")
// nolint: errcheck
fs.MarkDeprecated("secure-port", "This flag is deprecated and will be removed in release 1.12+. Use --health-probe-bind-address and --metrics-bind-address instead. Note: In release 1.12+, these two addresses cannot be the same.")
fs.StringVar(&o.MetricsBindAddress, "metrics-bind-address", "", "The TCP address that the server should bind to for serving prometheus metrics(e.g. 127.0.0.1:9000, :10351). It can be set to \"0\" to disable the metrics serving. Defaults to 0.0.0.0:10351.")
fs.StringVar(&o.HealthProbeBindAddress, "health-probe-bind-address", "", "The TCP address that the server should bind to for serving health probes(e.g. 127.0.0.1:9000, :10351). It can be set to \"0\" to disable serving the health probe. Defaults to 0.0.0.0:10351.")
fs.Float32Var(&o.KubeAPIQPS, "kube-api-qps", 40.0, "QPS to use while talking with karmada-apiserver.")
fs.IntVar(&o.KubeAPIBurst, "kube-api-burst", 60, "Burst to use while talking with karmada-apiserver.")
fs.BoolVar(&o.EnableSchedulerEstimator, "enable-scheduler-estimator", false, "Enable calling cluster scheduler estimator for adjusting replicas.")
Expand Down
21 changes: 12 additions & 9 deletions cmd/scheduler/app/options/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,30 @@ package options

import (
"net"
"strconv"

"k8s.io/apimachinery/pkg/util/validation/field"
)

// Complete ensures that options are valid and marshals them if necessary.
func (o *Options) Complete() error {
if len(o.HealthProbeBindAddress) == 0 {
o.HealthProbeBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort))
}
if len(o.MetricsBindAddress) == 0 {
o.MetricsBindAddress = net.JoinHostPort(o.BindAddress, strconv.Itoa(o.SecurePort))
}
return nil
}

// Validate checks Options and return a slice of found errs.
func (o *Options) Validate() field.ErrorList {
errs := field.ErrorList{}

newPath := field.NewPath("Options")
if net.ParseIP(o.BindAddress) == nil {
errs = append(errs, field.Invalid(newPath.Child("BindAddress"), o.BindAddress, "not a valid textual representation of an IP address"))
}

if o.SecurePort < 0 || o.SecurePort > 65535 {
errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be a valid port between 0 and 65535 inclusive"))
}

if o.SchedulerEstimatorPort < 0 || o.SchedulerEstimatorPort > 65535 {
errs = append(errs, field.Invalid(newPath.Child("SchedulerEstimatorPort"), o.SchedulerEstimatorPort, "must be a valid port between 0 and 65535 inclusive"))
}

if o.SchedulerEstimatorTimeout.Duration < 0 {
errs = append(errs, field.Invalid(newPath.Child("SchedulerEstimatorTimeout"), o.SchedulerEstimatorTimeout, "must be greater than or equal to 0"))
}
Expand Down
14 changes: 0 additions & 14 deletions cmd/scheduler/app/options/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ func TestValidateKarmadaSchedulerConfiguration(t *testing.T) {
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
LeaderElect: false,
},
BindAddress: "127.0.0.1",
SecurePort: 9000,
KubeAPIQPS: 40,
KubeAPIBurst: 30,
SchedulerName: "default-scheduler",
Expand All @@ -81,18 +79,6 @@ func TestValidateKarmadaSchedulerConfiguration(t *testing.T) {
opt Options
expectedErrs field.ErrorList
}{
"invalid BindAddress": {
opt: New(func(option *Options) {
option.BindAddress = "127.0.0.1:8080"
}),
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("BindAddress"), "127.0.0.1:8080", "not a valid textual representation of an IP address")},
},
"invalid SecurePort": {
opt: New(func(option *Options) {
option.SecurePort = 90000
}),
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), 90000, "must be a valid port between 0 and 65535 inclusive")},
},
"invalid SchedulerEstimatorPort": {
opt: New(func(option *Options) {
option.SchedulerEstimatorPort = 90000
Expand Down
66 changes: 53 additions & 13 deletions cmd/scheduler/app/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ package app
import (
"context"
"fmt"
"net"
"net/http"
"os"
"strconv"
"time"

"github.com/prometheus/client_golang/prometheus/promhttp"
Expand Down Expand Up @@ -100,6 +98,10 @@ The scheduler determines which clusters are valid placements for each resource i
constraints and available resources. The scheduler then ranks each valid cluster and binds the resource to
the most suitable cluster.`,
RunE: func(_ *cobra.Command, _ []string) error {
// complete options
if err := opts.Complete(); err != nil {
return err
}
// validate options
if errs := opts.Validate(); len(errs) != 0 {
return errs.ToAggregate()
Expand Down Expand Up @@ -139,7 +141,7 @@ the most suitable cluster.`,

func run(opts *options.Options, stopChan <-chan struct{}, registryOptions ...Option) error {
klog.Infof("karmada-scheduler version: %s", version.Get())
go serveHealthzAndMetrics(net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort)))
serveHealthzAndMetrics(opts.HealthProbeBindAddress, opts.MetricsBindAddress)

profileflag.ListenAndServe(opts.ProfileOpts)

Expand Down Expand Up @@ -225,26 +227,64 @@ func run(opts *options.Options, stopChan <-chan struct{}, registryOptions ...Opt
return nil
}

func serveHealthzAndMetrics(address string) {
func serveHealthzAndMetrics(healthProbeBindAddress, metricsBindAddress string) {
if healthProbeBindAddress == metricsBindAddress {
if healthProbeBindAddress != "0" {
go serveCombined(healthProbeBindAddress)
}
} else {
if healthProbeBindAddress != "0" {
go serveHealthz(healthProbeBindAddress)
}
if metricsBindAddress != "0" {
go serveMetrics(metricsBindAddress)
}
}
}

func serveCombined(address string) {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
mux.HandleFunc("/healthz", healthzHandler)
mux.Handle("/metrics", metricsHandler())

serveHTTP(address, mux, "healthz and metrics")
}

mux.Handle("/metrics", promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{
func serveHealthz(address string) {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", healthzHandler)
serveHTTP(address, mux, "healthz")
}

func serveMetrics(address string) {
mux := http.NewServeMux()
mux.Handle("/metrics", metricsHandler())
serveHTTP(address, mux, "metrics")
}

func healthzHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
}

func metricsHandler() http.Handler {
return promhttp.HandlerFor(ctrlmetrics.Registry, promhttp.HandlerOpts{
ErrorHandling: promhttp.HTTPErrorOnError,
}))
})
}

httpServer := http.Server{
func serveHTTP(address string, handler http.Handler, name string) {
httpServer := &http.Server{
Addr: address,
Handler: mux,
Handler: handler,
ReadHeaderTimeout: ReadHeaderTimeout,
WriteTimeout: WriteTimeout,
ReadTimeout: ReadTimeout,
}

klog.Infof("Starting %s server on %s", name, address)
if err := httpServer.ListenAndServe(); err != nil {
klog.Errorf("Failed to serve healthz and metrics: %v", err)
klog.Errorf("Failed to serve %s on %s: %v", name, address, err)
os.Exit(1)
}
}
4 changes: 2 additions & 2 deletions operator/pkg/controlplane/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ spec:
command:
- /bin/karmada-scheduler
- --kubeconfig=/etc/karmada/kubeconfig
- --bind-address=0.0.0.0
- --secure-port=10351
- --metrics-bind-address=0.0.0.0:10351
- --health-probe-bind-address=0.0.0.0:10351
- --enable-scheduler-estimator=true
- --leader-elect-resource-namespace={{ .SystemNamespace }}
- --scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt
Expand Down
4 changes: 2 additions & 2 deletions pkg/karmadactl/cmdinit/kubernetes/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ func (i *CommandInitOption) makeKarmadaSchedulerDeployment() *appsv1.Deployment
Command: []string{
"/bin/karmada-scheduler",
"--kubeconfig=/etc/kubeconfig",
"--bind-address=0.0.0.0",
"--secure-port=10351",
"--metrics-bind-address=0.0.0.0:10351",
"--health-probe-bind-address=0.0.0.0:10351",
"--enable-scheduler-estimator=true",
"--leader-elect=true",
"--scheduler-estimator-ca-file=/etc/karmada/pki/ca.crt",
Expand Down