feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -1,76 +1,127 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package app
import (
"context"
"fmt"
"os"
"github.com/google/gops/agent"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/runtime"
cliflag "k8s.io/component-base/cli/flag"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/conversion"
alertingv2beta1 "kubesphere.io/api/alerting/v2beta1"
"kubesphere.io/kubesphere/cmd/controller-manager/app/options"
"kubesphere.io/kubesphere/pkg/apis"
controllerconfig "kubesphere.io/kubesphere/pkg/apiserver/config"
"kubesphere.io/kubesphere/pkg/config"
"kubesphere.io/kubesphere/pkg/controller"
"kubesphere.io/kubesphere/pkg/controller/application"
"kubesphere.io/kubesphere/pkg/controller/certificatesigningrequest"
"kubesphere.io/kubesphere/pkg/controller/cluster"
"kubesphere.io/kubesphere/pkg/controller/network/webhooks"
"kubesphere.io/kubesphere/pkg/controller/clusterlabel"
"kubesphere.io/kubesphere/pkg/controller/clusterrole"
"kubesphere.io/kubesphere/pkg/controller/clusterrolebinding"
ksconfig "kubesphere.io/kubesphere/pkg/controller/config"
"kubesphere.io/kubesphere/pkg/controller/conversion"
"kubesphere.io/kubesphere/pkg/controller/core"
"kubesphere.io/kubesphere/pkg/controller/extension"
"kubesphere.io/kubesphere/pkg/controller/globalrole"
"kubesphere.io/kubesphere/pkg/controller/globalrolebinding"
"kubesphere.io/kubesphere/pkg/controller/job"
"kubesphere.io/kubesphere/pkg/controller/k8sapplication"
"kubesphere.io/kubesphere/pkg/controller/ksserviceaccount"
"kubesphere.io/kubesphere/pkg/controller/kubeconfig"
"kubesphere.io/kubesphere/pkg/controller/kubectl"
"kubesphere.io/kubesphere/pkg/controller/loginrecord"
"kubesphere.io/kubesphere/pkg/controller/namespace"
"kubesphere.io/kubesphere/pkg/controller/quota"
storagewebhooks "kubesphere.io/kubesphere/pkg/controller/storage/webhooks"
"kubesphere.io/kubesphere/pkg/controller/role"
"kubesphere.io/kubesphere/pkg/controller/rolebinding"
"kubesphere.io/kubesphere/pkg/controller/roletemplate"
"kubesphere.io/kubesphere/pkg/controller/secret"
"kubesphere.io/kubesphere/pkg/controller/serviceaccount"
"kubesphere.io/kubesphere/pkg/controller/storageclass"
"kubesphere.io/kubesphere/pkg/controller/telemetry"
"kubesphere.io/kubesphere/pkg/controller/user"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/utils/metrics"
"kubesphere.io/kubesphere/pkg/controller/workspace"
"kubesphere.io/kubesphere/pkg/controller/workspacerole"
"kubesphere.io/kubesphere/pkg/controller/workspacerolebinding"
"kubesphere.io/kubesphere/pkg/controller/workspacetemplate"
"kubesphere.io/kubesphere/pkg/utils/term"
"kubesphere.io/kubesphere/pkg/version"
)
func init() {
// core
runtime.Must(controller.Register(&core.ExtensionReconciler{}))
runtime.Must(controller.Register(&core.CategoryReconciler{}))
runtime.Must(controller.Register(&core.RepositoryReconciler{}))
runtime.Must(controller.Register(&core.InstallPlanReconciler{}))
runtime.Must(controller.Register(&core.InstallPlanWebhook{}))
// extension
runtime.Must(controller.Register(&extension.JSBundleWebhook{}))
runtime.Must(controller.Register(&extension.APIServiceWebhook{}))
runtime.Must(controller.Register(&extension.ReverseProxyWebhook{}))
runtime.Must(controller.Register(&extension.ExtensionEntryWebhook{}))
// rbac
runtime.Must(controller.Register(&globalrole.Reconciler{}))
runtime.Must(controller.Register(&globalrolebinding.Reconciler{}))
runtime.Must(controller.Register(&workspacerole.Reconciler{}))
runtime.Must(controller.Register(&workspacerolebinding.Reconciler{}))
runtime.Must(controller.Register(&clusterrole.Reconciler{}))
runtime.Must(controller.Register(&clusterrolebinding.Reconciler{}))
runtime.Must(controller.Register(&role.Reconciler{}))
runtime.Must(controller.Register(&rolebinding.Reconciler{}))
runtime.Must(controller.Register(&roletemplate.Reconciler{}))
runtime.Must(controller.Register(&namespace.Reconciler{}))
// user management
runtime.Must(controller.Register(&user.Reconciler{}))
runtime.Must(controller.Register(&user.Webhook{}))
runtime.Must(controller.Register(&loginrecord.Reconciler{}))
// multi cluster
runtime.Must(controller.Register(&cluster.Reconciler{}))
runtime.Must(controller.Register(&cluster.Webhook{}))
runtime.Must(controller.Register(&clusterlabel.Reconciler{}))
// multi tenancy
runtime.Must(controller.Register(&workspace.Reconciler{}))
runtime.Must(controller.Register(&workspacetemplate.Reconciler{}))
// kubesphere service account
runtime.Must(controller.Register(&ksserviceaccount.Reconciler{}))
runtime.Must(controller.Register(&ksserviceaccount.Webhook{}))
runtime.Must(controller.Register(&secret.ServiceAccountSecretReconciler{}))
// additional capabilities
runtime.Must(controller.Register(&serviceaccount.Reconciler{}))
runtime.Must(controller.Register(&job.Reconciler{}))
runtime.Must(controller.Register(&storageclass.Reconciler{}))
runtime.Must(controller.Register(&telemetry.Runnable{}))
runtime.Must(controller.Register(&ksconfig.Webhook{}))
runtime.Must(controller.Register(&conversion.Webhook{}))
// kubeconfig
runtime.Must(controller.Register(&kubeconfig.Reconciler{}))
runtime.Must(controller.Register(&certificatesigningrequest.Reconciler{}))
// resource quota
runtime.Must(controller.Register(&quota.Reconciler{}))
runtime.Must(controller.Register(&quota.Webhook{}))
// app store
runtime.Must(controller.Register(&application.AppReleaseReconciler{}))
runtime.Must(controller.Register(&application.RepoReconciler{}))
runtime.Must(controller.Register(&application.AppCategoryReconciler{}))
runtime.Must(controller.Register(&application.AppVersionReconciler{}))
// k8s application
runtime.Must(controller.Register(&k8sapplication.Reconciler{}))
// kubectl
runtime.Must(controller.Register(&kubectl.Reconciler{}))
}
func NewControllerManagerCommand() *cobra.Command {
s := options.NewKubeSphereControllerManagerOptions()
conf, err := controllerconfig.TryLoadFromDisk()
if err == nil {
// make sure LeaderElection is not nil
s = &options.KubeSphereControllerManagerOptions{
KubernetesOptions: conf.KubernetesOptions,
DevopsOptions: conf.DevopsOptions,
AuthenticationOptions: conf.AuthenticationOptions,
LdapOptions: conf.LdapOptions,
OpenPitrixOptions: conf.OpenPitrixOptions,
NetworkOptions: conf.NetworkOptions,
MultiClusterOptions: conf.MultiClusterOptions,
ServiceMeshOptions: conf.ServiceMeshOptions,
GatewayOptions: conf.GatewayOptions,
MonitoringOptions: conf.MonitoringOptions,
AlertingOptions: conf.AlertingOptions,
LeaderElection: s.LeaderElection,
LeaderElect: s.LeaderElect,
WebhookCertDir: s.WebhookCertDir,
}
s := options.NewControllerManagerOptions()
if conf, err := config.TryLoadFromDisk(); err == nil {
s.Merge(conf)
} else {
klog.Fatalf("Failed to load configuration from disk: %v", err)
}
@@ -78,33 +129,26 @@ func NewControllerManagerCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "controller-manager",
Long: `KubeSphere controller manager is a daemon that embeds the control loops shipped with KubeSphere.`,
Run: func(cmd *cobra.Command, args []string) {
if errs := s.Validate(allControllers); len(errs) != 0 {
klog.Error(utilerrors.NewAggregate(errs))
os.Exit(1)
RunE: func(cmd *cobra.Command, args []string) error {
if errs := s.Validate(); len(errs) != 0 {
return utilerrors.NewAggregate(errs)
}
if s.GOPSEnabled {
if s.DebugMode {
// Add agent to report additional information such as the current stack trace, Go version, memory stats, etc.
// Bind to a random port on address 127.0.0.1
if err := agent.Listen(agent.Options{}); err != nil {
klog.Fatal(err)
klog.Fatalln(err)
}
}
if err = Run(s, controllerconfig.WatchConfigChange(), signals.SetupSignalHandler()); err != nil {
klog.Error(err)
os.Exit(1)
}
return Run(signals.SetupSignalHandler(), s)
},
SilenceUsage: true,
}
fs := cmd.Flags()
namedFlagSets := s.Flags(allControllers)
namedFlagSets := s.Flags()
for _, f := range namedFlagSets.FlagSets {
fs.AddFlagSet(f)
cmd.Flags().AddFlagSet(f)
}
usageFmt := "Usage:\n %s\n"
@@ -123,155 +167,16 @@ func NewControllerManagerCommand() *cobra.Command {
}
cmd.AddCommand(versionCmd)
return cmd
}
func Run(s *options.KubeSphereControllerManagerOptions, configCh <-chan controllerconfig.Config, ctx context.Context) error {
ictx, cancelFunc := context.WithCancel(context.TODO())
errCh := make(chan error)
defer close(errCh)
go func() {
if err := run(s, ictx); err != nil {
errCh <- err
}
}()
// The ctx (signals.SetupSignalHandler()) is to control the entire program life cycle,
// The ictx(internal context) is created here to control the life cycle of the controller-manager(all controllers, sharedInformer, webhook etc.)
// when config changed, stop server and renew context, start new server
for {
select {
case <-ctx.Done():
cancelFunc()
return nil
case cfg := <-configCh:
cancelFunc()
s.MergeConfig(&cfg)
ictx, cancelFunc = context.WithCancel(context.TODO())
go func() {
if err := run(s, ictx); err != nil {
errCh <- err
}
}()
case err := <-errCh:
cancelFunc()
return err
}
}
}
func run(s *options.KubeSphereControllerManagerOptions, ctx context.Context) error {
kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions)
func Run(ctx context.Context, s *options.ControllerManagerOptions) error {
cm, err := s.NewControllerManager()
if err != nil {
klog.Errorf("Failed to create kubernetes clientset %v", err)
return err
return fmt.Errorf("failed to create controller manager: %v", err)
}
informerFactory := informers.NewInformerFactories(
kubernetesClient.Kubernetes(),
kubernetesClient.KubeSphere(),
kubernetesClient.Istio(),
kubernetesClient.Snapshot(),
kubernetesClient.ApiExtensions(),
kubernetesClient.Prometheus())
mgrOptions := manager.Options{
CertDir: s.WebhookCertDir,
Port: 8443,
if err := cm.Run(ctx, controller.Controllers); err != nil {
return fmt.Errorf("failed to run controller manager: %v", err)
}
if s.LeaderElect {
mgrOptions = manager.Options{
CertDir: s.WebhookCertDir,
Port: 8443,
LeaderElection: s.LeaderElect,
LeaderElectionNamespace: "kubesphere-system",
LeaderElectionID: "ks-controller-manager-leader-election",
LeaseDuration: &s.LeaderElection.LeaseDuration,
RetryPeriod: &s.LeaderElection.RetryPeriod,
RenewDeadline: &s.LeaderElection.RenewDeadline,
}
}
klog.V(0).Info("setting up manager")
ctrl.SetLogger(klog.NewKlogr())
// Use 8443 instead of 443 cause we need root permission to bind port 443
mgr, err := manager.New(kubernetesClient.Config(), mgrOptions)
if err != nil {
klog.Fatalf("unable to set up overall controller manager: %v", err)
}
if err = apis.AddToScheme(mgr.GetScheme()); err != nil {
klog.Fatalf("unable add APIs to scheme: %v", err)
}
// register common meta types into schemas.
metav1.AddToGroupVersion(mgr.GetScheme(), metav1.SchemeGroupVersion)
// TODO(jeff): refactor config with CRD
// install all controllers
if err = addAllControllers(mgr,
kubernetesClient,
informerFactory,
s,
ctx.Done()); err != nil {
klog.Fatalf("unable to register controllers to the manager: %v", err)
}
// Start cache data after all informer is registered
klog.V(0).Info("Starting cache resource from apiserver...")
informerFactory.Start(ctx.Done())
// Setup webhooks
klog.V(2).Info("setting up webhook server")
hookServer := mgr.GetWebhookServer()
klog.V(2).Info("registering webhooks to the webhook server")
if s.IsControllerEnabled("cluster") && s.MultiClusterOptions.Enable {
hookServer.Register("/validate-cluster-kubesphere-io-v1alpha1", &webhook.Admission{Handler: &cluster.ValidatingHandler{Client: mgr.GetClient()}})
}
hookServer.Register("/validate-email-iam-kubesphere-io-v1alpha2", &webhook.Admission{Handler: &user.EmailValidator{Client: mgr.GetClient()}})
hookServer.Register("/validate-network-kubesphere-io-v1alpha1", &webhook.Admission{Handler: &webhooks.ValidatingHandler{C: mgr.GetClient()}})
hookServer.Register("/mutate-network-kubesphere-io-v1alpha1", &webhook.Admission{Handler: &webhooks.MutatingHandler{C: mgr.GetClient()}})
pvcAdmission, err := storagewebhooks.NewAccessorHandler()
if err != nil {
klog.Fatalf("unable to create pvc admission: %v", err)
}
hookServer.Register("/persistentvolumeclaims", &webhook.Admission{Handler: pvcAdmission})
resourceQuotaAdmission, err := quota.NewResourceQuotaAdmission(mgr.GetClient(), mgr.GetScheme())
if err != nil {
klog.Fatalf("unable to create resource quota admission: %v", err)
}
hookServer.Register("/validate-quota-kubesphere-io-v1alpha2", &webhook.Admission{Handler: resourceQuotaAdmission})
hookServer.Register("/convert", &conversion.Webhook{})
rulegroup := alertingv2beta1.RuleGroup{}
if err := rulegroup.SetupWebhookWithManager(mgr); err != nil {
klog.Fatalf("Unable to setup RuleGroup webhook: %v", err)
}
clusterrulegroup := alertingv2beta1.ClusterRuleGroup{}
if err := clusterrulegroup.SetupWebhookWithManager(mgr); err != nil {
klog.Fatalf("Unable to setup ClusterRuleGroup webhook: %v", err)
}
globalrulegroup := alertingv2beta1.GlobalRuleGroup{}
if err := globalrulegroup.SetupWebhookWithManager(mgr); err != nil {
klog.Fatalf("Unable to setup GlobalRuleGroup webhook: %v", err)
}
klog.V(2).Info("registering metrics to the webhook server")
// Add an extra metric endpoint, so we can use the the same metric definition with ks-apiserver
// /kapis/metrics is independent of controller-manager's built-in /metrics
mgr.AddMetricsExtraHandler("/kapis/metrics", metrics.Handler())
klog.V(0).Info("Starting the controllers.")
if err = mgr.Start(ctx); err != nil {
klog.Fatalf("unable to run the manager: %v", err)
}
return nil
}