diff --git a/charts/vela-core/README.md b/charts/vela-core/README.md index f0c86dd80..98aa01ed2 100644 --- a/charts/vela-core/README.md +++ b/charts/vela-core/README.md @@ -96,6 +96,7 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai | `featureGates.enableLegacyComponentRevision` | if disabled, only component with rollout trait will create component revisions | `false` | | `featureGates.gzipResourceTracker` | if enabled, resourceTracker will be compressed using gzip before being stored | `false` | | `featureGates.zstdResourceTracker` | if enabled, resourceTracker will be compressed using zstd before being stored. It is much faster and more efficient than gzip. If both gzip and zstd are enabled, zstd will be used. | `false` | +| `featureGates.applyOnce` | if enabled, the apply-once feature will be applied to all applications, no state-keep and no resource data storage in ResourceTracker | `false` | ### MultiCluster parameters diff --git a/charts/vela-core/templates/kubevela-controller.yaml b/charts/vela-core/templates/kubevela-controller.yaml index f6885000a..bd6b76a4e 100644 --- a/charts/vela-core/templates/kubevela-controller.yaml +++ b/charts/vela-core/templates/kubevela-controller.yaml @@ -220,6 +220,7 @@ spec: - "--feature-gates=LegacyComponentRevision={{- .Values.featureGates.enableLegacyComponentRevision | toString -}}" - "--feature-gates=GzipResourceTracker={{- .Values.featureGates.gzipResourceTracker | toString -}}" - "--feature-gates=ZstdResourceTracker={{- .Values.featureGates.zstdResourceTracker | toString -}}" + - "--feature-gates=ApplyOnce={{- .Values.featureGates.applyOnce | toString -}}" {{ if .Values.authentication.enabled }} {{ if .Values.authentication.withUser }} - "--authentication-with-user" diff --git a/charts/vela-core/values.yaml b/charts/vela-core/values.yaml index 6585a8800..bb48e3783 100644 --- a/charts/vela-core/values.yaml +++ b/charts/vela-core/values.yaml @@ -112,10 +112,12 @@ optimize: ##@param featureGates.enableLegacyComponentRevision if disabled, only component with rollout trait will create component revisions ##@param featureGates.gzipResourceTracker if enabled, resourceTracker will be compressed using gzip before being stored ##@param featureGates.zstdResourceTracker if enabled, resourceTracker will be compressed using zstd before being stored. It is much faster and more efficient than gzip. If both gzip and zstd are enabled, zstd will be used. +##@param featureGates.applyOnce if enabled, the apply-once feature will be applied to all applications, no state-keep and no resource data storage in ResourceTracker featureGates: enableLegacyComponentRevision: false gzipResourceTracker: false zstdResourceTracker: false + applyOnce: false ## @section MultiCluster parameters diff --git a/cmd/core/main.go b/cmd/core/main.go index 41388c88d..7e4bc5497 100644 --- a/cmd/core/main.go +++ b/cmd/core/main.go @@ -27,7 +27,6 @@ import ( "os" "path/filepath" "strconv" - "strings" "time" flag "github.com/spf13/pflag" @@ -47,6 +46,7 @@ import ( oamv1alpha2 "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2" "github.com/oam-dev/kubevela/pkg/controller/utils" "github.com/oam-dev/kubevela/pkg/cue/packages" + "github.com/oam-dev/kubevela/pkg/features" _ "github.com/oam-dev/kubevela/pkg/monitor/metrics" "github.com/oam-dev/kubevela/pkg/monitor/watcher" "github.com/oam-dev/kubevela/pkg/multicluster" @@ -78,7 +78,6 @@ func main() { var healthAddr string var disableCaps string var storageDriver string - var applyOnceOnly string var qps float64 var burst int var pprofAddr string @@ -86,6 +85,7 @@ func main() { var leaseDuration time.Duration var renewDeadline time.Duration var retryPeriod time.Duration + var informerSyncPeriod time.Duration var enableClusterGateway bool var enableClusterMetrics bool var clusterMetricsInterval time.Duration @@ -111,12 +111,12 @@ func main() { "custom-revision-hook-url is a webhook url which will let KubeVela core to call with applicationConfiguration and component info and return a customized component revision") flag.BoolVar(&controllerArgs.AutoGenWorkloadDefinition, "autogen-workload-definition", true, "Automatic generated workloadDefinition which componentDefinition refers to.") flag.StringVar(&healthAddr, "health-addr", ":9440", "The address the health endpoint binds to.") - flag.StringVar(&applyOnceOnly, "apply-once-only", "false", - "For the purpose of some production environment that workload or trait should not be affected if no spec change, available options: on, off, force.") flag.StringVar(&disableCaps, "disable-caps", "", "To be disabled builtin capability list.") flag.StringVar(&storageDriver, "storage-driver", "Local", "Application file save to the storage driver") flag.DurationVar(&commonconfig.ApplicationReSyncPeriod, "application-re-sync-period", 5*time.Minute, "Re-sync period for application to re-sync, also known as the state-keep interval.") + flag.DurationVar(&informerSyncPeriod, "informer-sync-period", 10*time.Hour, + "The re-sync period for informer in controller-runtime. This is a system-level configuration.") flag.DurationVar(&commonconfig.ReconcileTimeout, "reconcile-timeout", time.Minute*3, "the timeout for controller reconcile") flag.StringVar(&oam.SystemDefinitonNamespace, "system-definition-namespace", "vela-system", "define the namespace of the system-level definition") @@ -230,6 +230,10 @@ func main() { } ctrl.SetLogger(klogr.New()) + if utilfeature.DefaultMutableFeatureGate.Enabled(features.ApplyOnce) { + commonconfig.ApplicationReSyncPeriod = informerSyncPeriod + } + leaderElectionID := util.GenerateLeaderElectionID(types.KubeVelaName, controllerArgs.IgnoreAppWithoutControllerRequirement) mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, @@ -244,6 +248,7 @@ func main() { LeaseDuration: &leaseDuration, RenewDeadline: &renewDeadline, RetryPeriod: &retryPeriod, + SyncPeriod: &informerSyncPeriod, // SyncPeriod is configured with default value, aka. 10h. First, controller-runtime does not // recommend use it as a time trigger, instead, it is expected to work for failure tolerance // of controller-runtime. Additionally, set this value will affect not only application @@ -266,23 +271,6 @@ func main() { os.Exit(1) } - switch strings.ToLower(applyOnceOnly) { - case "", "false", string(oamcontroller.ApplyOnceOnlyOff): - controllerArgs.ApplyMode = oamcontroller.ApplyOnceOnlyOff - klog.Info("ApplyOnceOnly is disabled") - case "true", string(oamcontroller.ApplyOnceOnlyOn): - controllerArgs.ApplyMode = oamcontroller.ApplyOnceOnlyOn - klog.Info("ApplyOnceOnly is enabled, that means workload or trait only apply once if no spec change even they are changed by others") - case string(oamcontroller.ApplyOnceOnlyForce): - controllerArgs.ApplyMode = oamcontroller.ApplyOnceOnlyForce - klog.Info("ApplyOnceOnlyForce is enabled, that means workload or trait only apply once if no spec change even they are changed or deleted by others") - default: - klog.ErrorS(fmt.Errorf("invalid apply-once-only value: %s", applyOnceOnly), - "Unable to setup the vela core controller", - "apply-once-only", "on/off/force, by default it's off") - os.Exit(1) - } - dm, err := discoverymapper.New(mgr.GetConfig()) if err != nil { klog.ErrorS(err, "Failed to create CRD discovery client") diff --git a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go index 8ba11fc6c..e3d60b6e2 100644 --- a/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go +++ b/pkg/controller/core.oam.dev/v1alpha2/application/application_controller.go @@ -286,6 +286,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } func (r *Reconciler) stateKeep(logCtx monitorContext.Context, handler *AppHandler, app *v1beta1.Application) { + if feature.DefaultMutableFeatureGate.Enabled(features.ApplyOnce) { + return + } if err := handler.resourceKeeper.StateKeep(logCtx); err != nil { logCtx.Error(err, "Failed to run prevent-configuration-drift") r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedStateKeep, err)) diff --git a/pkg/features/controller_features.go b/pkg/features/controller_features.go index cd8af2b07..e289f9eca 100644 --- a/pkg/features/controller_features.go +++ b/pkg/features/controller_features.go @@ -70,6 +70,11 @@ const ( // If dealing with smaller ResourceTrackers (10KB - 1MB), the performance // penalties are minimal. ZstdResourceTracker featuregate.Feature = "ZstdResourceTracker" + + // ApplyOnce enable the apply-once feature for all applications + // If enabled, no StateKeep will be run, ResourceTracker will also disable the storage of all resource data, only + // metadata will be kept + ApplyOnce featuregate.Feature = "ApplyOnce" ) var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ @@ -85,6 +90,7 @@ var defaultFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{ AuthenticateApplication: {Default: false, PreRelease: featuregate.Alpha}, GzipResourceTracker: {Default: false, PreRelease: featuregate.Alpha}, ZstdResourceTracker: {Default: false, PreRelease: featuregate.Alpha}, + ApplyOnce: {Default: false, PreRelease: featuregate.Alpha}, } func init() { diff --git a/pkg/resourcekeeper/dispatch.go b/pkg/resourcekeeper/dispatch.go index be64f2abf..738fcd1d5 100644 --- a/pkg/resourcekeeper/dispatch.go +++ b/pkg/resourcekeeper/dispatch.go @@ -21,9 +21,11 @@ import ( "github.com/pkg/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + utilfeature "k8s.io/apiserver/pkg/util/feature" "github.com/oam-dev/kubevela/apis/core.oam.dev/common" "github.com/oam-dev/kubevela/pkg/auth" + "github.com/oam-dev/kubevela/pkg/features" "github.com/oam-dev/kubevela/pkg/multicluster" "github.com/oam-dev/kubevela/pkg/oam" "github.com/oam-dev/kubevela/pkg/resourcetracker" @@ -56,7 +58,8 @@ func newDispatchConfig(options ...DispatchOption) *dispatchConfig { // Dispatch dispatch resources func (h *resourceKeeper) Dispatch(ctx context.Context, manifests []*unstructured.Unstructured, applyOpts []apply.ApplyOption, options ...DispatchOption) (err error) { - if h.applyOncePolicy != nil && h.applyOncePolicy.Enable && h.applyOncePolicy.Rules == nil { + if utilfeature.DefaultMutableFeatureGate.Enabled(features.ApplyOnce) || + (h.applyOncePolicy != nil && h.applyOncePolicy.Enable && h.applyOncePolicy.Rules == nil) { options = append(options, MetaOnlyOption{}) } h.ClearNamespaceForClusterScopedResources(manifests)