title | gep-number | creation-date | status | authors | reviewers | ||||
---|---|---|---|---|---|---|---|---|---|
Namespaced Cloud Profiles |
25 |
2024-02-08 |
implementable |
|
|
- GEP-25: Namespaced Cloud Profiles
CloudProfiles are non-namespaced objects that are managed centrally by Gardener operators. They usually contain not only global configuration, but options that are relevant to certain projects only (e.g. special machine types). This increases the operation burden for operators and clutters CloudProfile
objects. On the other hand, users are blocked until the requested special configuration is rolled out to the desired landscapes.
This GEP proposes a mechanism that allows project administrators to create NamespacedCloudProfile
s that are only visible in the project they belong to.
CloudProfile
s are an integral component of Gardener for managing shoot clusters. They are currently managed centrally by Gardener operators and can be consumed by any Gardener user. However, some teams require frequent changes to a CloudProfile
, mainly for the following reasons:
- Testing with different machine types than the ones present in the
CloudProfile
. - Need to use different volume types than the ones present in the
CloudProfile
. - Extending the expiration date of Kubernetes versions. Given that the
CloudProfile
is a cluster-scoped resource, it is currently not possible to extend the expiration date for shoots in one project but only centrally for all projects. - Extending the expiration date for machine images. For the same reasons as extending the expiration date of the Kubernetes versions.
CloudProfile
s are non-namespaced resources. This means that in a typical Gardener installation, only a handful of CloudProfile
s (typically one per cloud provider) exist. They can be consumed by any shoot cluster. Consequently, when a project requires changes to CloudProfile
s for any of the reasons mentioned in the context section, they are changed for the entire Gardener landscape. Since some projects might require frequent changes, this becomes quite a cumbersome process on both, the operators' and users' sides.
- Reduce load on Gardener operators for maintaining
CloudProfile
s - Possibly reduce the time a team has to wait until a change in a
CloudProfile
is reflected in the landscape. - Make it so that project-scoped information in the
CloudProfile
is only visible to the relevant project - Full backward compatibility
- Automate the approval process for changes in
CloudProfile
s - Add different, possibly unsupported Kubernetes versions or machine image versions and names
It is proposed to implement a solution that enables project administrators to create custom (namespaced) CloudProfile
s. These CloudProfile
s would be consumed by users of the project they were created in.
First of all, a new, namespaced API object NamespacedCloudProfile
is defined. Its type definition is very similar to the CloudProfile
object.
The general approach is that a NamespacedCloudProfile
inherits from a CloudProfile
using a parent
field. Fields such as machineTypes
, volumeTypes
and caBundle
are going to be merged with the parent CloudProfile
. However, a restriction needs to be defined so that the kubernetes
and machineImages
fields in a NamespacedCloudProfile
may only be adjusted by a Gardener operator to reduce the chance of a team staying on an unsupported Kubernetes version. A similar problem is already solved in Gardener using custom RBAC verbs here, see custom RBAC verb section for more information.
Currently, the shoot's reference to a CloudProfile
is immutable. This validation will be relaxed to allow updating to a NamespacedCloudProfile
whose parent is the same as the currently configured CloudProfile
. The change will also be reversible, i.e. switching from NamespacedCloudProfile
to CloudProfile
.
The NamespacedCloudProfile
will not include the providerConfig
and regions
fields. The contents of the providerConfig
field are not known to Gardener but only to the provider extensions and can therefore not be merged without consulting the appropriate extension. The regions
field typically needs some kind of entry in the providerConfig
and is therefore excluded as well.
A NamespacedCloudProfile
could look like this:
apiVersion: core.gardener.cloud/v1beta1
kind: NamespacedCloudProfile
metadata:
name: aws-profile-xyz
namespace: project-xyz
spec:
parent:
kind: CloudProfile
name: aws-central-cloud-profile
kubernetes:
versions:
- version: 1.28.6
expirationDate: 2024-06-06T01:02:03Z
machineImages:
- name: suse-chost
versions:
- version: 16.4
expirationDate: 2023-08-8T23:59:59Z
machineTypes:
- name: m5.xlarge
cpu: "8"
gpu: "0"
memory: 16Gi
volumeTypes:
- name: ab6
class: premium
usable: true
Since Gardener is designed around using the CloudProfile
object for managing infrastructure details for a shoot, the NamespacedCloudProfile
has to be rendered so that a CloudProfile
object is emitted. This rendered CloudProfile
will be written to the status of the NamespacedCloudProfile
object.
Suppose we have a simplified CloudProfile
that looks like this:
apiVersion: core.gardener.cloud/v1beta1
kind: CloudProfile
metadata:
name: aws-central-cloud-profile
spec:
type: aws
kubernetes:
versions:
- version: 1.27.1
- version: 1.26.3
- version: 1.25.8
- version: 1.24.6
- version: 1.28.6
expirationDate: 2023-02-02T01:02:03Z
machineImages:
- name: suse-chost
versions:
- version: 15.4
- version: 14.4
- version: 13.6
machineTypes:
- name: m5.large
cpu: "4"
gpu: "0"
memory: 8Gi
volumeTypes:
- name: gp3
class: standard
usable: true
and the NamespacedCloudProfile
from the manifest section.
After the rendering is done, the NamespacedCloudProfile
will look like this:
apiVersion: core.gardener.cloud/v1beta1
kind: NamespacedCloudProfile
metadata:
name: aws-profile-xyz
namespace: project-xyz
spec:
parent:
kind: CloudProfile
name: aws-central-cloud-profile
kubernetes:
versions:
- version: 1.28.6
expirationDate: 2024-06-06T01:02:03Z
machineImages:
- name: suse-chost
versions:
- version: 16.4
expirationDate: 2023-08-8T23:59:59Z
machineTypes:
- name: m5.xlarge
cpu: "8"
gpu: "0"
memory: 16Gi
volumeTypes:
- name: ab6
class: premium
usable: true
status:
cloudProfile:
apiVersion: core.gardener.cloud/v1beta1
kind: CloudProfile
spec:
type: aws
kubernetes:
versions:
- version: 1.27.1
- version: 1.26.3
- version: 1.25.8
- version: 1.24.6
- version: 1.28.6
expirationDate: 2024-06-06T01:02:03Z
machineImages:
- name: suse-chost
versions:
- version: 16.4
expirationDate: 2023-08-8T23:59:59Z
- version: 15.4
- version: 14.4
- version: 13.6
machineTypes:
- name: m5.large
cpu: "4"
gpu: "0"
memory: 8Gi
- name: m5.xlarge
cpu: "8"
gpu: "0"
memory: 16Gi
volumeTypes:
- name: ab6
class: premium
usable: true
- name: gp3
class: standard
usable: true
The rendering is done by a new custom controller registered to the gardener-controller-manager
. Merge conflicts can not arise during the merge process as they are caught by static validation and an admission plugin for validating the NamespacedCloudProfile
object.
To prevent users from entering arbitrary values in the kubernetes
and machineImages
fields, two custom RBAC verbs may be introduced. It can then be checked if the user that is creating or updating the kubernetes
or machineImages
field is authorized to do so.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespaced-cloud-profile-modify-special-fields
rules:
- apiGroups: ["core.gardener.cloud"]
resources: ["namespacedcloudprofiles"]
verbs: ["modify-spec-kubernetes", "modify-spec-machineImages"]
When a CloudProfile
is deleted it is checked if any Shoot
s exists that are still referencing it. This concept should also be applied to NamespacedCloudProfile
s. When deleting a Kubernetes version or a machine image version from a CloudProfile
, it should be ensured that no NamespacedCloudProfile
s exist that are using the versions that should be deleted. This check is performed by the CloudProfile
validation admission plugin.
Since CloudProfiles
and NamespacedCloudProfiles
are separate API objects, a CloudProfile
could have the same name as a NamespacedCloudProfile
. When the Shoot then references the CloudProfile
two possible profiles could match on the reference. To solve this issue, the Shoot
object should be extended with a cloudProfile
field that specifies both the name
and the kind
of the referenced CloudProfile
. However, the existing cloudProfileName
field should remain intact and default to a CloudProfile
for a smooth migration. Sane default will also be defined to allow for full backward compatibility with the cloudProfileName
field.
An example of the new field can be found here:
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: project-xyz
...
spec:
...
cloudProfile:
kind: NamespacedCloudProfile
name: aws-profile-xyz
...
CloudProfile
s are not just a central Gardener resource but are also used by Gardener's provider extensions. Therefore, enabling NamespacedCloudProfiles
is a multi-step process.
- Rollout
NamespacedCloudProfile
API and validations, rollout Shoot API changes, add a feature gate for both - Adjust all provider extensions to understand both
CloudProfile
s as well asNamespacedCloudProfiles
- Migrate
Shoot
scloudProfileName
to thecloudProfile
field but keepcloudProfileName
in the API for now - Enable
NamespacedCloudProfiles
in Gardener
There are a couple of key features to this GEP that fit well into Gardeners development but are not included immediately to keep the scope in line with the concrete defined use cases. These features might be implemented within future GEPs or PRs and would certainly add value to Gardener.
A use case could be defined where a NamespacedCloudProfile
might want to be shared across multiple projects and not just be used within the project it was created in. Especially when taking a broader view of Gardeners development with Private Seeds and Cloud in Country, this feature is probably going to be necessary at some point.
This GEP already modifies the cloudProfile
field in the Shoot
s spec. To implement cross-project sharing, a namespace
field could be added to the cloudProfile
field. It specifies in which project/namespace the selected CloudProfile
is. Checking if a user is allowed to select the specified CloudProfile
can be handled in multiple ways and should be specified more concretely when this feature is to be implemented.
apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
name: my-shoot
namespace: project-xyz
...
spec:
...
cloudProfile:
kind: NamespacedCloudProfile
name: aws-profile-xyz
namespace: other-project-abc
...
A NamespacedCloudProfile
could inherit from a NamespacedCloudProfile
that already inherits from a CloudProfile
. This would enable reusing NamespacedCloudProfile
s and would aid in deduplication within fields of NamespacedCloudProfiles
. This feature can be implemented easily but is also excluded for now to stick to the defined use cases.
When enabling multi-level inheritance, the NamespacedCloudProfile
s parent
field should also be adjusted to allow for a NamespacedCloudProfile
as a parent.
parent:
kind: <NamespacedCloudProfile | CloudProfile>
name: <objects name>
In combination with cross-project sharing, the parent
field should also allow for a namespace to be defined with the same reasoning as in cross-project sharing.
parent:
kind: <NamespacedCloudProfile | CloudProfile>
name: <objects name>
namespace: <(optional) objects namespace if outside project namespace>
In the future, once NamespacedCloudProfiles
have established themselves and found good use in the Gardener landscape and amongst its users, they could replace regular CloudProfile
s entirely. For this, they would have to include all fields of a CloudProfile
. Replacing CloudProfile
s with NamespacedCloudProfile
s has several benefits. Firstly, Gardener maintainers don't have to maintain, test and operate two almost identical objects. Secondly, it would allow for the central "Gardener provided" CloudProfile
s to use inheritance. This could enable deduplication in our central CloudProfiles
as common values do not have to be copied from one CloudProfile
to another CloudProfile
. Additionally, it could enable both cloud, as well as on-prem infrastructures to only be visible to defined projects and not to every landscape user.
Instead of specifying a NamespacedCloudProfile
resource, an end user could be allowed to enter arbitrary names in fields such as machineTypes
. The entry would then, if the user enters a wrong value, throw an error when provisioning the resource at the cloud provider. However, this approach does not seem feasible as the metadata that is specified in a CloudProfile
like the number of CPUs and amount of RAM is used in the trial clusters (see Shoot Quotas) to validate quotas and to enable the scale-from-zero feature. Therefore, an exception would need to be developed for this specific, and possibly other, use cases.
Instead of using a single inheritance-based approach with the parent
field, a similar approach as aggregated cluster roles in Kubernetes could be used. In this approach, CloudProfile
s would be defined without a parent and would be aggregated together. However, this approach is not well suited as it can not clearly define which CloudProfile
overwrites which fields. A restriction could be defined that when combining multiple CloudProfile
s, no merge conflicts must be introduced, making the approach more reasonable.