Merge pull request #2043 from Poor12/test

Add health probe for Karmada-agent
This commit is contained in:
karmada-bot 2022-06-24 16:24:16 +08:00 committed by GitHub
commit 61072d117c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 58 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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.")

View 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"))
}

View File

@ -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")},
},
}

View File

@ -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