Merge pull request #2043 from Poor12/test
Add health probe for Karmada-agent
This commit is contained in:
commit
61072d117c
|
|
@ -30,7 +30,18 @@ spec:
|
|||
- --cluster-name={{member_cluster_name}}
|
||||
- --cluster-api-endpoint={{member_cluster_api_endpoint}}
|
||||
- --cluster-status-update-frequency=10s
|
||||
- --bind-address=0.0.0.0
|
||||
- --secure-port=10357
|
||||
- --v=4
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10357
|
||||
scheme: HTTP
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
volumeMounts:
|
||||
- name: kubeconfig
|
||||
mountPath: /etc/kubeconfig
|
||||
|
|
|
|||
|
|
@ -111,7 +111,18 @@ spec:
|
|||
- --cluster-name={{ .Values.agent.clusterName }}
|
||||
- --cluster-status-update-frequency=10s
|
||||
- --leader-elect-resource-namespace={{ include "karmada.namespace" . }}
|
||||
- --bind-address=0.0.0.0
|
||||
- --secure-port=10357
|
||||
- --v=4
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10357
|
||||
scheme: HTTP
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
volumeMounts:
|
||||
- name: kubeconfig
|
||||
mountPath: /etc/kubeconfig
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
|
|
@ -18,6 +20,7 @@ import (
|
|||
"k8s.io/klog/v2"
|
||||
controllerruntime "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/config/v1alpha1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
|
||||
"github.com/karmada-io/karmada/cmd/agent/app/options"
|
||||
clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1"
|
||||
|
|
@ -144,6 +147,8 @@ func run(ctx context.Context, karmadaConfig karmadactl.KarmadaConfig, opts *opti
|
|||
LeaderElectionID: fmt.Sprintf("karmada-agent-%s", opts.ClusterName),
|
||||
LeaderElectionNamespace: opts.LeaderElection.ResourceNamespace,
|
||||
LeaderElectionResourceLock: opts.LeaderElection.ResourceLock,
|
||||
HealthProbeBindAddress: net.JoinHostPort(opts.BindAddress, strconv.Itoa(opts.SecurePort)),
|
||||
LivenessEndpointName: "/healthz",
|
||||
MetricsBindAddress: opts.MetricsBindAddress,
|
||||
Controller: v1alpha1.ControllerConfigurationSpec{
|
||||
GroupKindConcurrency: map[string]int{
|
||||
|
|
@ -156,6 +161,11 @@ func run(ctx context.Context, karmadaConfig karmadactl.KarmadaConfig, opts *opti
|
|||
return fmt.Errorf("failed to build controller manager: %w", err)
|
||||
}
|
||||
|
||||
if err := controllerManager.AddHealthzCheck("ping", healthz.Ping); err != nil {
|
||||
klog.Errorf("failed to add health check endpoint: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = setupControllers(controllerManager, opts, ctx.Done()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,14 +14,23 @@ import (
|
|||
"github.com/karmada-io/karmada/pkg/util"
|
||||
)
|
||||
|
||||
// DefaultKarmadaClusterNamespace defines the default namespace where the member cluster secrets are stored.
|
||||
const DefaultKarmadaClusterNamespace = "karmada-cluster"
|
||||
const (
|
||||
// DefaultKarmadaClusterNamespace defines the default namespace where the member cluster secrets are stored.
|
||||
DefaultKarmadaClusterNamespace = "karmada-cluster"
|
||||
defaultBindAddress = "0.0.0.0"
|
||||
defaultPort = 10357
|
||||
)
|
||||
|
||||
// Options contains everything necessary to create and run controller-manager.
|
||||
type Options struct {
|
||||
// Controllers contains all controller names.
|
||||
Controllers []string
|
||||
LeaderElection componentbaseconfig.LeaderElectionConfiguration
|
||||
Controllers []string
|
||||
LeaderElection componentbaseconfig.LeaderElectionConfiguration
|
||||
// BindAddress is the IP address on which to listen for the --secure-port port.
|
||||
BindAddress string
|
||||
// SecurePort is the port that the the server serves at.
|
||||
// Note: We hope support https in the future once controller-runtime provides the functionality.
|
||||
SecurePort int
|
||||
KarmadaKubeConfig string
|
||||
// ClusterContext is the name of the cluster context in control plane KUBECONFIG file.
|
||||
// Default value is the current-context.
|
||||
|
|
@ -96,6 +105,10 @@ func (o *Options) AddFlags(fs *pflag.FlagSet, allControllers []string) {
|
|||
"A list of controllers to enable. '*' enables all on-by-default controllers, 'foo' enables the controller named 'foo', '-foo' disables the controller named 'foo'. All controllers: %s.",
|
||||
strings.Join(allControllers, ", "),
|
||||
))
|
||||
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.")
|
||||
fs.BoolVar(&o.LeaderElection.LeaderElect, "leader-elect", true, "Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability.")
|
||||
fs.StringVar(&o.LeaderElection.ResourceNamespace, "leader-elect-resource-namespace", util.NamespaceKarmadaSystem, "The namespace of resource object that is used for locking during leader election.")
|
||||
fs.StringVar(&o.KarmadaKubeConfig, "karmada-kubeconfig", o.KarmadaKubeConfig, "Path to karmada control plane kubeconfig file.")
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ func (o *Options) Validate() field.ErrorList {
|
|||
errs = append(errs, field.Invalid(newPath.Child("ClusterName"), o.ClusterName, strings.Join(errMsgs, ",")))
|
||||
}
|
||||
|
||||
if o.SecurePort < 0 || o.SecurePort > 65535 {
|
||||
errs = append(errs, field.Invalid(newPath.Child("SecurePort"), o.SecurePort, "must be between 0 and 65535 inclusive"))
|
||||
}
|
||||
|
||||
if o.ClusterStatusUpdateFrequency.Duration < 0 {
|
||||
errs = append(errs, field.Invalid(newPath.Child("ClusterStatusUpdateFrequency"), o.ClusterStatusUpdateFrequency, "must be greater than or equal to 0"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,26 +9,34 @@ import (
|
|||
componentbaseconfig "k8s.io/component-base/config"
|
||||
)
|
||||
|
||||
// a callback function to modify options
|
||||
type ModifyOptions func(option *Options)
|
||||
|
||||
// New an Options with default parameters
|
||||
func New(modifyOptions ModifyOptions) Options {
|
||||
option := Options{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
SecurePort: 8090,
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
}
|
||||
|
||||
if modifyOptions != nil {
|
||||
modifyOptions(&option)
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
func TestValidateKarmadaAgentConfiguration(t *testing.T) {
|
||||
successCases := []Options{
|
||||
{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
},
|
||||
{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: true,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
},
|
||||
New(nil),
|
||||
New(func(options *Options) {
|
||||
options.LeaderElection.LeaderElect = true
|
||||
}),
|
||||
}
|
||||
|
||||
for _, successCase := range successCases {
|
||||
|
|
@ -43,51 +51,33 @@ func TestValidateKarmadaAgentConfiguration(t *testing.T) {
|
|||
expectedErrs field.ErrorList
|
||||
}{
|
||||
"invalid ClusterName": {
|
||||
opt: Options{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
},
|
||||
opt: New(func(options *Options) {
|
||||
options.ClusterName = ""
|
||||
}),
|
||||
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterName"), "", "must be not empty")},
|
||||
},
|
||||
"invalid SecurePort": {
|
||||
opt: New(func(options *Options) {
|
||||
options.SecurePort = -10
|
||||
}),
|
||||
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("SecurePort"), -10, "must be between 0 and 65535 inclusive")},
|
||||
},
|
||||
"invalid ClusterStatusUpdateFrequency": {
|
||||
opt: Options{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: -10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
},
|
||||
opt: New(func(options *Options) {
|
||||
options.ClusterStatusUpdateFrequency = metav1.Duration{Duration: -10 * time.Second}
|
||||
}),
|
||||
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterStatusUpdateFrequency"), metav1.Duration{Duration: -10 * time.Second}, "must be greater than or equal to 0")},
|
||||
},
|
||||
"invalid ClusterLeaseDuration": {
|
||||
opt: Options{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: -40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0.25,
|
||||
},
|
||||
opt: New(func(options *Options) {
|
||||
options.ClusterLeaseDuration = metav1.Duration{Duration: -40 * time.Second}
|
||||
}),
|
||||
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterLeaseDuration"), metav1.Duration{Duration: -40 * time.Second}, "must be greater than or equal to 0")},
|
||||
},
|
||||
"invalid ClusterLeaseRenewIntervalFraction": {
|
||||
opt: Options{
|
||||
LeaderElection: componentbaseconfig.LeaderElectionConfiguration{
|
||||
LeaderElect: false,
|
||||
},
|
||||
ClusterName: "demo",
|
||||
ClusterStatusUpdateFrequency: metav1.Duration{Duration: 10 * time.Second},
|
||||
ClusterLeaseDuration: metav1.Duration{Duration: 40 * time.Second},
|
||||
ClusterLeaseRenewIntervalFraction: 0,
|
||||
},
|
||||
opt: New(func(options *Options) {
|
||||
options.ClusterLeaseRenewIntervalFraction = 0
|
||||
}),
|
||||
expectedErrs: field.ErrorList{field.Invalid(newPath.Child("ClusterLeaseRenewIntervalFraction"), 0, "must be greater than 0")},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,18 @@ spec:
|
|||
- --karmada-context=%s
|
||||
- --cluster-name={member_cluster_name}
|
||||
- --cluster-status-update-frequency=10s
|
||||
- --bind-address=0.0.0.0
|
||||
- --secure-port=10357
|
||||
- --v=4
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 10357
|
||||
scheme: HTTP
|
||||
failureThreshold: 3
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 15
|
||||
timeoutSeconds: 5
|
||||
volumeMounts:
|
||||
- name: kubeconfig
|
||||
mountPath: /etc/kubeconfig
|
||||
|
|
|
|||
Loading…
Reference in New Issue