From db2d6a5df0fa2de5c83331d176fa96b6e47479d9 Mon Sep 17 00:00:00 2001 From: Martin Necas Date: Fri, 13 Dec 2024 16:12:21 +0100 Subject: [PATCH] MTV-1493 | Add missing resource limits and requests Issue: If the user sets ClusterResourceQuota the Forklift will start failing as it does not have the limits or requests on the pods which are created form the Forklift Controller. Fix: Add a new parameters to Forklift operator which can be configured depedning on the user env. Ref: https://issues.redhat.com/browse/MTV-1493 Signed-off-by: Martin Necas --- .../forkliftcontroller/defaults/main.yml | 14 ++ .../controller/deployment-controller.yml.j2 | 24 ++++ pkg/controller/plan/hook.go | 11 ++ pkg/controller/plan/kubevirt.go | 30 +++++ pkg/controller/plan/validation.go | 23 +++- pkg/controller/provider/ova-setup.go | 10 ++ pkg/settings/migration.go | 127 +++++++++++++++--- 7 files changed, 217 insertions(+), 22 deletions(-) diff --git a/operator/roles/forkliftcontroller/defaults/main.yml b/operator/roles/forkliftcontroller/defaults/main.yml index 86f7c8b39..ef6492b07 100644 --- a/operator/roles/forkliftcontroller/defaults/main.yml +++ b/operator/roles/forkliftcontroller/defaults/main.yml @@ -111,12 +111,26 @@ populator_controller_container_name: "{{ app_name }}-populator-controller" populator_openstack_image_fqin: "{{ lookup( 'env', 'OPENSTACK_POPULATOR_IMAGE') or lookup( 'env', 'RELATED_IMAGE_OPENSTACK_POPULATOR') }}" must_gather_image_fqin: "{{ lookup( 'env', 'MUST_GATHER_IMAGE') or lookup( 'env', 'RELATED_IMAGE_MUST_GATHER') }}" + virt_v2v_image_fqin: "{{ lookup( 'env', 'VIRT_V2V_IMAGE') or lookup( 'env', 'RELATED_IMAGE_VIRT_V2V') }}" virt_v2v_dont_request_kvm: "{{ lookup( 'env', 'VIRT_V2V_DONT_REQUEST_KVM') }}" virt_v2v_extra_args: "{{ lookup( 'env', 'VIRT_V2V_EXTRA_ARGS') }}" virt_v2v_extra_conf_config_map: "{{ lookup( 'env', 'VIRT_V2V_EXTRA_CONF_CONFIG_MAP') }}" +virt_v2v_container_limits_cpu: "4000m" +virt_v2v_container_limits_memory: "8Gi" +virt_v2v_container_requests_cpu: "1000m" +virt_v2v_container_requests_memory: "1Gi" + +hooks_container_limits_cpu: "1000m" +hooks_container_limits_memory: "1Gi" +hooks_container_requests_cpu: "100m" +hooks_container_requests_memory: "150Mi" ova_provider_server_fqin: "{{ lookup( 'env', 'OVA_PROVIDER_SERVER_IMAGE') or lookup( 'env', 'RELATED_IMAGE_OVA_PROVIDER_SERVER') }}" +ova_container_limits_cpu: "1000m" +ova_container_limits_memory: "1Gi" +ova_container_requests_cpu: "100m" +ova_container_requests_memory: "150Mi" metric_service_name: "{{ app_name }}-metrics" metric_servicemonitor_name: "{{ app_name }}-metrics" diff --git a/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 b/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 index 28bfbcc77..090409114 100644 --- a/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 +++ b/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 @@ -143,6 +143,30 @@ spec: value: "{{ virt_v2v_extra_args }}" - name: VIRT_V2V_EXTRA_CONF_CONFIG_MAP value: "{{ virt_v2v_extra_conf_config_map }}" + - name: VIRT_V2V_CONTAINER_LIMITS_CPU + value: "{{ virt_v2v_container_limits_cpu }}" + - name: VIRT_V2V_CONTAINER_LIMITS_MEMORY + value: "{{ virt_v2v_container_limits_memory }}" + - name: VIRT_V2V_CONTAINER_REQUESTS_CPU + value: "{{ virt_v2v_container_requests_cpu }}" + - name: VIRT_V2V_CONTAINER_REQUESTS_MEMORY + value: "{{ virt_v2v_container_requests_memory }}" + - name: HOOKS_CONTAINER_LIMITS_CPU + value: "{{ hooks_container_limits_cpu }}" + - name: HOOKS_CONTAINER_LIMITS_MEMORY + value: "{{ hooks_container_limits_memory }}" + - name: HOOKS_CONTAINER_REQUESTS_CPU + value: "{{ hooks_container_requests_cpu }}" + - name: HOOKS_CONTAINER_REQUESTS_MEMORY + value: "{{ hooks_container_requests_memory }}" + - name: OVA_CONTAINER_LIMITS_CPU + value: "{{ ova_container_limits_cpu }}" + - name: OVA_CONTAINER_LIMITS_MEMORY + value: "{{ ova_container_limits_memory }}" + - name: OVA_CONTAINER_REQUESTS_CPU + value: "{{ ova_container_requests_cpu }}" + - name: OVA_CONTAINER_REQUESTS_MEMORY + value: "{{ ova_container_requests_memory }}" envFrom: - configMapRef: name: {{ controller_configmap_name }} diff --git a/pkg/controller/plan/hook.go b/pkg/controller/plan/hook.go index 296b6e5b9..ccc97e0a1 100644 --- a/pkg/controller/plan/hook.go +++ b/pkg/controller/plan/hook.go @@ -14,6 +14,7 @@ import ( "gopkg.in/yaml.v2" batch "k8s.io/api/batch/v1" core "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/kubernetes/scheme" @@ -181,6 +182,16 @@ func (r *HookRunner) template(mp *core.ConfigMap) (template *core.PodTemplateSpe { Name: "hook", Image: r.hook.Spec.Image, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.HooksContainerRequestsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.HooksContainerRequestsMemory), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.HooksContainerLimitsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.HooksContainerLimitsMemory), + }, + }, VolumeMounts: []core.VolumeMount{ { Name: "hook", diff --git a/pkg/controller/plan/kubevirt.go b/pkg/controller/plan/kubevirt.go index 74dfd8317..06cb04e87 100644 --- a/pkg/controller/plan/kubevirt.go +++ b/pkg/controller/plan/kubevirt.go @@ -773,6 +773,16 @@ func (r *KubeVirt) createPodToBindPVCs(vm *plan.VMStatus, pvcNames []string) (er // In that case, we could benefit from pulling the image of the conversion pod, so it will be present on the node. Image: Settings.Migration.VirtV2vImage, Command: []string{"/bin/sh"}, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.VirtV2vContainerRequestsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.VirtV2vContainerRequestsMemory), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.VirtV2vContainerLimitsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.VirtV2vContainerLimitsMemory), + }, + }, SecurityContext: &core.SecurityContext{ AllowPrivilegeEscalation: &allowPrivilageEscalation, RunAsNonRoot: &nonRoot, @@ -1738,6 +1748,16 @@ func (r *KubeVirt) guestConversionPod(vm *plan.VMStatus, vmVolumes []cnv.Volume, MountPath: "/opt", }, }, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse("100m"), + core.ResourceMemory: resource.MustParse("150Mi"), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse("1000m"), + core.ResourceMemory: resource.MustParse("500Mi"), + }, + }, SecurityContext: &core.SecurityContext{ AllowPrivilegeEscalation: &allowPrivilageEscalation, Capabilities: &core.Capabilities{ @@ -1823,6 +1843,16 @@ func (r *KubeVirt) guestConversionPod(vm *plan.VMStatus, vmVolumes []cnv.Volume, Name: "virt-v2v", Env: environment, ImagePullPolicy: core.PullAlways, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.VirtV2vContainerRequestsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.VirtV2vContainerRequestsMemory), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.Migration.VirtV2vContainerLimitsCpu), + core.ResourceMemory: resource.MustParse(Settings.Migration.VirtV2vContainerLimitsMemory), + }, + }, EnvFrom: []core.EnvFromSource{ { Prefix: "V2V_", diff --git a/pkg/controller/plan/validation.go b/pkg/controller/plan/validation.go index cbdb61dec..224859f12 100644 --- a/pkg/controller/plan/validation.go +++ b/pkg/controller/plan/validation.go @@ -26,6 +26,7 @@ import ( core "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" k8serr "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" k8svalidation "k8s.io/apimachinery/pkg/util/validation" @@ -1016,6 +1017,16 @@ func createVddkCheckJob(plan *api.Plan) *batchv1.Job { Drop: []core.Capability{"ALL"}, }, }, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse("100m"), + core.ResourceMemory: resource.MustParse("150Mi"), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse("1000m"), + core.ResourceMemory: resource.MustParse("500Mi"), + }, + }, }, } @@ -1057,7 +1068,17 @@ func createVddkCheckJob(plan *api.Plan) *batchv1.Job { InitContainers: initContainers, Containers: []core.Container{ { - Name: "validator", + Name: "validator", + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse("100m"), + core.ResourceMemory: resource.MustParse("150Mi"), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse("1000m"), + core.ResourceMemory: resource.MustParse("500Mi"), + }, + }, Image: Settings.Migration.VirtV2vImage, SecurityContext: &core.SecurityContext{ AllowPrivilegeEscalation: ptr.To(false), diff --git a/pkg/controller/provider/ova-setup.go b/pkg/controller/provider/ova-setup.go index 03b562b73..d137beb6f 100644 --- a/pkg/controller/provider/ova-setup.go +++ b/pkg/controller/provider/ova-setup.go @@ -224,6 +224,16 @@ func (r *Reconciler) makeOvaProviderPodSpec(pvcName, providerName, providerNames MountPath: mountPath, }, }, + Resources: core.ResourceRequirements{ + Requests: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.OvaContainerRequestsCpu), + core.ResourceMemory: resource.MustParse(Settings.OvaContainerRequestsMemory), + }, + Limits: core.ResourceList{ + core.ResourceCPU: resource.MustParse(Settings.OvaContainerLimitsCpu), + core.ResourceMemory: resource.MustParse(Settings.OvaContainerRequestsMemory), + }, + }, SecurityContext: securityContext, } diff --git a/pkg/settings/migration.go b/pkg/settings/migration.go index 354eadd18..e8a76db7c 100644 --- a/pkg/settings/migration.go +++ b/pkg/settings/migration.go @@ -12,26 +12,38 @@ import ( // Environment variables. const ( - MaxVmInFlight = "MAX_VM_INFLIGHT" - HookRetry = "HOOK_RETRY" - ImporterRetry = "IMPORTER_RETRY" - VirtV2vImage = "VIRT_V2V_IMAGE" - PrecopyInterval = "PRECOPY_INTERVAL" - VirtV2vDontRequestKVM = "VIRT_V2V_DONT_REQUEST_KVM" - SnapshotRemovalTimeout = "SNAPSHOT_REMOVAL_TIMEOUT" - SnapshotStatusCheckRate = "SNAPSHOT_STATUS_CHECK_RATE" - CDIExportTokenTTL = "CDI_EXPORT_TOKEN_TTL" - FileSystemOverhead = "FILESYSTEM_OVERHEAD" - BlockOverhead = "BLOCK_OVERHEAD" - CleanupRetries = "CLEANUP_RETRIES" - DvStatusCheckRetries = "DV_STATUS_CHECK_RETRIES" - SnapshotRemovalCheckRetries = "SNAPSHOT_REMOVAL_CHECK_RETRIES" - OvirtOsConfigMap = "OVIRT_OS_MAP" - VsphereOsConfigMap = "VSPHERE_OS_MAP" - VirtCustomizeConfigMap = "VIRT_CUSTOMIZE_MAP" - VddkJobActiveDeadline = "VDDK_JOB_ACTIVE_DEADLINE" - VirtV2vExtraArgs = "VIRT_V2V_EXTRA_ARGS" - VirtV2vExtraConfConfigMap = "VIRT_V2V_EXTRA_CONF_CONFIG_MAP" + MaxVmInFlight = "MAX_VM_INFLIGHT" + HookRetry = "HOOK_RETRY" + ImporterRetry = "IMPORTER_RETRY" + VirtV2vImage = "VIRT_V2V_IMAGE" + PrecopyInterval = "PRECOPY_INTERVAL" + VirtV2vDontRequestKVM = "VIRT_V2V_DONT_REQUEST_KVM" + SnapshotRemovalTimeout = "SNAPSHOT_REMOVAL_TIMEOUT" + SnapshotStatusCheckRate = "SNAPSHOT_STATUS_CHECK_RATE" + CDIExportTokenTTL = "CDI_EXPORT_TOKEN_TTL" + FileSystemOverhead = "FILESYSTEM_OVERHEAD" + BlockOverhead = "BLOCK_OVERHEAD" + CleanupRetries = "CLEANUP_RETRIES" + DvStatusCheckRetries = "DV_STATUS_CHECK_RETRIES" + SnapshotRemovalCheckRetries = "SNAPSHOT_REMOVAL_CHECK_RETRIES" + OvirtOsConfigMap = "OVIRT_OS_MAP" + VsphereOsConfigMap = "VSPHERE_OS_MAP" + VirtCustomizeConfigMap = "VIRT_CUSTOMIZE_MAP" + VddkJobActiveDeadline = "VDDK_JOB_ACTIVE_DEADLINE" + VirtV2vExtraArgs = "VIRT_V2V_EXTRA_ARGS" + VirtV2vExtraConfConfigMap = "VIRT_V2V_EXTRA_CONF_CONFIG_MAP" + VirtV2vContainerLimitsCpu = "VIRT_V2V_CONTAINER_LIMITS_CPU" + VirtV2vContainerLimitsMemory = "VIRT_V2V_CONTAINER_LIMITS_MEMORY" + VirtV2vContainerRequestsCpu = "VIRT_V2V_CONTAINER_REQUESTS_CPU" + VirtV2vContainerRequestsMemory = "VIRT_V2V_CONTAINER_REQUESTS_MEMORY" + HooksContainerLimitsCpu = "HOOKS_CONTAINER_LIMITS_CPU" + HooksContainerLimitsMemory = "HOOKS_CONTAINER_LIMITS_MEMORY" + HooksContainerRequestsCpu = "HOOKS_CONTAINER_REQUESTS_CPU" + HooksContainerRequestsMemory = "HOOKS_CONTAINER_REQUESTS_MEMORY" + OvaContainerLimitsCpu = "OVA_CONTAINER_LIMITS_CPU" + OvaContainerLimitsMemory = "OVA_CONTAINER_LIMITS_MEMORY" + OvaContainerRequestsCpu = "OVA_CONTAINER_REQUESTS_CPU" + OvaContainerRequestsMemory = "OVA_CONTAINER_REQUESTS_MEMORY" ) // Migration settings @@ -75,7 +87,19 @@ type Migration struct { // Additional arguments for virt-v2v VirtV2vExtraArgs string // Additional configuration for virt-v2v - VirtV2vExtraConfConfigMap string + VirtV2vExtraConfConfigMap string + VirtV2vContainerLimitsCpu string + VirtV2vContainerLimitsMemory string + VirtV2vContainerRequestsCpu string + VirtV2vContainerRequestsMemory string + HooksContainerLimitsCpu string + HooksContainerLimitsMemory string + HooksContainerRequestsCpu string + HooksContainerRequestsMemory string + OvaContainerLimitsCpu string + OvaContainerLimitsMemory string + OvaContainerRequestsCpu string + OvaContainerRequestsMemory string } // Load settings. @@ -157,5 +181,66 @@ func (r *Migration) Load() (err error) { if val, found := os.LookupEnv(VirtV2vExtraConfConfigMap); found { r.VirtV2vExtraConfConfigMap = val } + // Containers configurations + if val, found := os.LookupEnv(VirtV2vContainerLimitsCpu); found { + r.VirtV2vContainerLimitsCpu = val + } else { + r.VirtV2vContainerLimitsCpu = "4000m" + } + if val, found := os.LookupEnv(VirtV2vContainerLimitsMemory); found { + r.VirtV2vContainerLimitsMemory = val + } else { + r.VirtV2vContainerLimitsMemory = "8Gi" + } + if val, found := os.LookupEnv(VirtV2vContainerRequestsCpu); found { + r.VirtV2vContainerRequestsCpu = val + } else { + r.VirtV2vContainerRequestsCpu = "1000m" + } + if val, found := os.LookupEnv(VirtV2vContainerRequestsMemory); found { + r.VirtV2vContainerRequestsMemory = val + } else { + r.VirtV2vContainerRequestsMemory = "1Gi" + } + if val, found := os.LookupEnv(HooksContainerLimitsCpu); found { + r.HooksContainerLimitsCpu = val + } else { + r.HooksContainerLimitsCpu = "1000m" + } + if val, found := os.LookupEnv(HooksContainerLimitsMemory); found { + r.HooksContainerLimitsMemory = val + } else { + r.HooksContainerLimitsMemory = "1Gi" + } + if val, found := os.LookupEnv(HooksContainerRequestsCpu); found { + r.HooksContainerRequestsCpu = val + } else { + r.HooksContainerRequestsCpu = "100m" + } + if val, found := os.LookupEnv(HooksContainerRequestsMemory); found { + r.HooksContainerRequestsMemory = val + } else { + r.HooksContainerRequestsMemory = "150Mi" + } + if val, found := os.LookupEnv(OvaContainerLimitsCpu); found { + r.OvaContainerLimitsCpu = val + } else { + r.OvaContainerLimitsCpu = "1000m" + } + if val, found := os.LookupEnv(OvaContainerLimitsMemory); found { + r.OvaContainerLimitsMemory = val + } else { + r.OvaContainerLimitsMemory = "1Gi" + } + if val, found := os.LookupEnv(OvaContainerRequestsCpu); found { + r.OvaContainerRequestsCpu = val + } else { + r.OvaContainerRequestsCpu = "100m" + } + if val, found := os.LookupEnv(OvaContainerRequestsMemory); found { + r.OvaContainerRequestsMemory = val + } else { + r.OvaContainerRequestsMemory = "150Mi" + } return }