From 41ce3489f61c320bd02d6b2cd5dbd0356cbc4c0d Mon Sep 17 00:00:00 2001 From: Axel Schmidt Date: Thu, 11 Dec 2025 11:16:04 +0100 Subject: [PATCH 1/2] create cluster-stack for rke2 Signed-off-by: Axel Schmidt --- providers/openstack/rke2/README.md | 158 +++ .../rke2/cluster-addon/ccm/Chart.yaml | 10 + .../rke2/cluster-addon/ccm/overwrite.yaml | 4 + .../rke2/cluster-addon/ccm/values.yaml | 21 + .../rke2/cluster-addon/csi/Chart.yaml | 10 + .../rke2/cluster-addon/csi/overwrite.yaml | 3 + .../rke2/cluster-addon/csi/values.yaml | 41 + .../openstack/rke2/cluster-class/.helmignore | 23 + .../openstack/rke2/cluster-class/Chart.yaml | 9 + .../rke2/cluster-class/templates/_helpers.tpl | 62 ++ .../templates/cluster-class.yaml | 958 ++++++++++++++++++ .../templates/openstack-cluster-template.yaml | 101 ++ ...nstack-machine-template-control-plane.yaml | 12 + .../openstack-machine-template-worker.yaml | 12 + ...rke2-config-template-worker-openstack.yaml | 16 + .../rke2-control-plane-template.yaml | 24 + .../openstack/rke2/cluster-class/values.yaml | 0 providers/openstack/rke2/clusteraddon.yaml | 13 + providers/openstack/rke2/csctl.yaml | 7 + providers/openstack/rke2/versions.yaml | 3 + 20 files changed, 1487 insertions(+) create mode 100644 providers/openstack/rke2/README.md create mode 100644 providers/openstack/rke2/cluster-addon/ccm/Chart.yaml create mode 100644 providers/openstack/rke2/cluster-addon/ccm/overwrite.yaml create mode 100644 providers/openstack/rke2/cluster-addon/ccm/values.yaml create mode 100644 providers/openstack/rke2/cluster-addon/csi/Chart.yaml create mode 100644 providers/openstack/rke2/cluster-addon/csi/overwrite.yaml create mode 100644 providers/openstack/rke2/cluster-addon/csi/values.yaml create mode 100644 providers/openstack/rke2/cluster-class/.helmignore create mode 100644 providers/openstack/rke2/cluster-class/Chart.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/_helpers.tpl create mode 100644 providers/openstack/rke2/cluster-class/templates/cluster-class.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/openstack-cluster-template.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/openstack-machine-template-control-plane.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/openstack-machine-template-worker.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/rke2-config-template-worker-openstack.yaml create mode 100644 providers/openstack/rke2/cluster-class/templates/rke2-control-plane-template.yaml create mode 100644 providers/openstack/rke2/cluster-class/values.yaml create mode 100644 providers/openstack/rke2/clusteraddon.yaml create mode 100644 providers/openstack/rke2/csctl.yaml create mode 100644 providers/openstack/rke2/versions.yaml diff --git a/providers/openstack/rke2/README.md b/providers/openstack/rke2/README.md new file mode 100644 index 00000000..c07ceddf --- /dev/null +++ b/providers/openstack/rke2/README.md @@ -0,0 +1,158 @@ +# Cluster Stacks + +## Getting started + +At first you need a Ready installed Rancher Management Dashboard (without any existing Downstreamclusters installed via custom-cluster. The cso will breake the management). + +For Rancher Version < 2.13 you must install the Rancher Turtles to open the preinstalled capi. https://ranchermanager.docs.rancher.com/integrations-in-rancher/cluster-api/overview + +For Rancher Version >= 2.13 the Rancher Turtles is preinstalled and enabled by default. Only the Rancher Turtles UI must be installed sepratly. https://turtles.docs.rancher.com/turtles/v0.24/en/tutorials/quickstart.html#_capi_ui_extension_installation + +Now you must install following providers (via GUI Cluster Management > CAPI > Provider > Create) + +|Key|Value bootstrap|Value controlplane|Value infrastructure| +|---|---|---|--| +|Namespace|rke2-bootstrap|rke2-controlplane|capo-system| +|Name|rke2-bootstrap|rke2-controlplane|infrastructure-openstack| +|Provider|rke2|rke2|openstack| +|Provider type|bootstrap|controlPlane|infrastructure| +|Features Enable cluster resource set|yes|yes|yes| +|Features Enable cluster topology|yes|yes|yes| +|Features Enable machine pool|yes|yes|yes| +|Variables|EXP_RUNTIME_SDK=true|EXP_RUNTIME_SDK=true|EXP_RUNTIME_SDK=true| + + + +```sh +# Init openstack resource controller +kubectl apply -f https://github.com/k-orc/openstack-resource-controller/releases/latest/download/install.yaml + +``` + +``` +# Install CSO and CSPO +helm upgrade -i cso \ +-n cso-system \ +--create-namespace \ +oci://registry.scs.community/cluster-stacks/cso +``` + +```sh +export CLUSTER_NAMESPACE=cluster +export CLUSTER_NAME=my-cluster +export CLUSTERSTACK_NAMESPACE=cluster +export CLUSTERSTACK_VERSION=v6 +export OS_CLIENT_CONFIG_FILE=${PWD}/clouds.yaml +kubectl create namespace $CLUSTER_NAMESPACE --dry-run=client -o yaml | kubectl apply -f - +kubectl label namespace $CLUSTER_NAMESPACE cluster-api.cattle.io/rancher-auto-import=true +``` + +```sh +# Create secret for CAPO +kubectl create secret -n $CLUSTER_NAMESPACE generic openstack --from-file=clouds.yaml=$OS_CLIENT_CONFIG_FILE --dry-run=client -oyaml | kubectl apply -f - + +# Prepare the Secret as it will be deployed in the Workload Cluster +kubectl create secret -n kube-system generic clouds-yaml --from-file=clouds.yaml=$OS_CLIENT_CONFIG_FILE --dry-run=client -oyaml > clouds-yaml-secret + +# Add the Secret to the ClusterResourceSet Secret in the Management Cluster +kubectl create -n $CLUSTER_NAMESPACE secret generic clouds-yaml --from-file=clouds-yaml-secret --type=addons.cluster.x-k8s.io/resource-set --dry-run=client -oyaml | kubectl apply -f - +``` + +```yaml +cat < /tmp/kubeconfig +kubectl get nodes --kubeconfig /tmp/kubeconfig +# Enable rke2-ingress-loadbalancer +kubectl --kubeconfig /tmp/kubeconfig -n kube-system patch HelmChart.helm.cattle.io rke2-ingress-nginx --type='json' -p '[{"op": "add", "path": "/spec/set/'controller.service.enabled'", "value":"true"}]' +# Set rke2-ingress-loadbalancer-IP +kubectl --kubeconfig /tmp/kubeconfig -n kube-system patch HelmChart.helm.cattle.io rke2-ingress-nginx --type='json' -p '[{"op": "add", "path": "/spec/set/'controller.service.loadBalancerIP'", "value":"xxx.xxx.xxx.xxx"}]' + +``` diff --git a/providers/openstack/rke2/cluster-addon/ccm/Chart.yaml b/providers/openstack/rke2/cluster-addon/ccm/Chart.yaml new file mode 100644 index 00000000..541cecd0 --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/ccm/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: CCM +name: CCM +version: v1 +dependencies: + - alias: openstack-cloud-controller-manager + name: openstack-cloud-controller-manager + repository: https://kubernetes.github.io/cloud-provider-openstack + version: 2.33.1 diff --git a/providers/openstack/rke2/cluster-addon/ccm/overwrite.yaml b/providers/openstack/rke2/cluster-addon/ccm/overwrite.yaml new file mode 100644 index 00000000..39076ecd --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/ccm/overwrite.yaml @@ -0,0 +1,4 @@ +values: | + openstack-cloud-controller-manager: + cluster: + name: {{ .Cluster.metadata.name }} diff --git a/providers/openstack/rke2/cluster-addon/ccm/values.yaml b/providers/openstack/rke2/cluster-addon/ccm/values.yaml new file mode 100644 index 00000000..3f290366 --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/ccm/values.yaml @@ -0,0 +1,21 @@ +openstack-cloud-controller-manager: + secret: + enabled: true + name: ccm-cloud-config + create: true + nodeSelector: + tolerations: + - key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + effect: NoSchedule + extraVolumes: + - name: clouds-yaml + secret: + secretName: clouds-yaml + extraVolumeMounts: + - name: clouds-yaml + readOnly: true + mountPath: /etc/openstack + cloudConfig: + global: + use-clouds: true diff --git a/providers/openstack/rke2/cluster-addon/csi/Chart.yaml b/providers/openstack/rke2/cluster-addon/csi/Chart.yaml new file mode 100644 index 00000000..e275b2ff --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/csi/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +type: application +description: CSI +name: CSI +version: v1 +dependencies: + - alias: openstack-cinder-csi + name: openstack-cinder-csi + repository: https://kubernetes.github.io/cloud-provider-openstack + version: 2.33.1 diff --git a/providers/openstack/rke2/cluster-addon/csi/overwrite.yaml b/providers/openstack/rke2/cluster-addon/csi/overwrite.yaml new file mode 100644 index 00000000..d191a115 --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/csi/overwrite.yaml @@ -0,0 +1,3 @@ +values: | + openstack-cinder-csi: + clusterID: "{{ .Cluster.metadata.name }}" diff --git a/providers/openstack/rke2/cluster-addon/csi/values.yaml b/providers/openstack/rke2/cluster-addon/csi/values.yaml new file mode 100644 index 00000000..4e648a4f --- /dev/null +++ b/providers/openstack/rke2/cluster-addon/csi/values.yaml @@ -0,0 +1,41 @@ +openstack-cinder-csi: + secret: + enabled: true + name: csi-cloud-config + create: true + filename: cloud.conf + data: + cloud.conf: |- + [Global] + use-clouds = "true" + clouds-file = /etc/openstack/clouds.yaml + storageClass: + delete: + isDefault: true + csi: + plugin: + volumes: + - name: clouds-yaml + secret: + secretName: clouds-yaml + - name: cloud-conf + secret: + secretName: csi-cloud-config + volumeMounts: + - name: clouds-yaml + readOnly: true + mountPath: /etc/openstack + - name: cloud-conf + readOnly: true + mountPath: /etc/kubernetes + - name: cloud-conf + readOnly: true + mountPath: /etc/config + nodeSelector: + node-role.kubernetes.io/control-plane: "" + tolerations: + - key: node.cloudprovider.kubernetes.io/uninitialized + value: "true" + effect: NoSchedule + - key: node-role.kubernetes.io/control-plane + effect: NoSchedule diff --git a/providers/openstack/rke2/cluster-class/.helmignore b/providers/openstack/rke2/cluster-class/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/providers/openstack/rke2/cluster-class/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/providers/openstack/rke2/cluster-class/Chart.yaml b/providers/openstack/rke2/cluster-class/Chart.yaml new file mode 100644 index 00000000..efc367c1 --- /dev/null +++ b/providers/openstack/rke2/cluster-class/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +description: "This chart installs and configures: + + * Openstack rke2 Cluster Class + + " +name: openstack-rke2-1-33-cluster-class +type: application +version: v1 diff --git a/providers/openstack/rke2/cluster-class/templates/_helpers.tpl b/providers/openstack/rke2/cluster-class/templates/_helpers.tpl new file mode 100644 index 00000000..2339c125 --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "cluster-class.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cluster-class.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cluster-class.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cluster-class.labels" -}} +helm.sh/chart: {{ include "cluster-class.chart" . }} +{{ include "cluster-class.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cluster-class.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cluster-class.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "cluster-class.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "cluster-class.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/providers/openstack/rke2/cluster-class/templates/cluster-class.yaml b/providers/openstack/rke2/cluster-class/templates/cluster-class.yaml new file mode 100644 index 00000000..aa4beb22 --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/cluster-class.yaml @@ -0,0 +1,958 @@ +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }} +spec: + controlPlane: + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: RKE2ControlPlaneTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane + machineInfrastructure: + ref: + kind: OpenStackMachineTemplate + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-cluster + workers: + machineDeployments: + - class: default-worker + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: RKE2ConfigTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker + variables: + # Image variables + - name: imageName + required: false + schema: + openAPIV3Schema: + type: string + description: | + The base name of the OpenStack image used for provisioning servers. + If `imageIsOrc` is enabled, this name refers to an ORC image resource. + If `imageIsOrc` is disabled, the name is used to filter images available in the OpenStack project. In this case, the specified image must already exist within the project. + If `imageAddVersion` is enabled, the Kubernetes version will be appended to form the complete image name (e.g., imageName-v1.33.6+rke2r1) + default: "ubuntu-capi-image" + - name: imageIsOrc + required: false + schema: + openAPIV3Schema: + type: boolean + description: | + Indicates whether the image name refers to an ORC image resource. + If set to true (default), the `imageName` is interpreted as a reference to an ORC image. + If set to false, the `imageName` is used to filter images in the OpenStack project instead. + default: false + - name: imageAddVersion + required: false + schema: + openAPIV3Schema: + type: boolean + description: | + Add a suffix with the Kubernetes version to the imageName. E.g. imageName-v1.33.6+rke2r1. + default: true + - name: disableAPIServerFloatingIP + required: false + schema: + openAPIV3Schema: + type: boolean + default: false + example: false + description: "DisableAPIServerFloatingIP controls whether a floating IP should be attached to the API server." + # Network variables + - name: networkExternalID + required: false + schema: + openAPIV3Schema: + type: string + example: "ebfe5546-f09f-4f42-ab54-094e457d42ec" + format: "uuid4" + description: "networkExternalID is the ID of an external OpenStack Network. This is necessary to get public internet to the VMs in case there are several external networks." + - name: networkMTU + required: false + schema: + openAPIV3Schema: + type: integer + example: 1500 + description: "networkMTU sets the maximum transmission unit (MTU) value to address fragmentation for the private network ID." + - name: dnsNameservers + required: false + schema: + openAPIV3Schema: + type: array + description: "dnsNameservers is the list of nameservers for the OpenStack Subnet being created. Set this value when you need to create a new network/subnet which requires access to DNS." + default: ["9.9.9.9", "149.112.112.112"] + example: ["9.9.9.9", "149.112.112.112"] + items: + type: string + - name: nodeCIDR + required: false + schema: + openAPIV3Schema: + type: string + format: "cidr" + default: "10.8.0.0/20" + example: "10.8.0.0/20" + description: |- + nodeCIDR is the OpenStack Subnet to be created. + Cluster actuator will create a network, a subnet with nodeCIDR, + and a router connected to this subnet. + If you leave this empty, no network will be created. + - name: clusterCNI + required: false + schema: + openAPIV3Schema: + type: string + default: "cilium" + example: "cilium" + description: |- + The CNI to be used for the cluster. + Supported CNIs are: cilium, canal and calico(rke2 default). + If calico is selected, following command must be run after insatall: + kubectl patch ippools.crd.projectcalico.org default-ipv4-ippool --type='json' -p '[{"op": "replace", "path": "/spec/ipipMode", "value":"CrossSubnet"}]' + # Control plane + - name: controlPlaneFlavor + required: false + schema: + openAPIV3Schema: + type: string + default: "SCS-2V-4" + example: "SCS-2V-4-20s" + description: |- + OpenStack instance flavor for control plane nodes. + (Default: SCS-2V-4, replace by SCS-2V-4-20s or specify a controlPlaneRootDisk.) + - name: controlPlaneRootDisk + required: false + schema: + openAPIV3Schema: + type: integer + minimum: 0 + example: 25 + default: 50 + description: |- + Root disk size in GiB for control-plane nodes. + OpenStack volume will be created and used instead of an ephemeral disk defined in flavor. + Should only be used for the diskless flavors (>= 20), otherwise set to 0. + - name: controlPlaneServerGroupID + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "3adf4e92-bb33-4e44-8ad3-afda9dfe8ec3" + description: "The server group to assign the control plane nodes to (can be used for anti-affinity)." + - name: controlPlaneAvailabilityZones + required: false + schema: + openAPIV3Schema: + type: array + example: ["nova"] + description: "controlPlaneAvailabilityZones is the set of availability zones which control plane machines may be deployed to." + items: + type: string + - name: controlPlaneOmitAvailabilityZone + required: false + schema: + openAPIV3Schema: + type: boolean + example: true + description: |- + controlPlaneOmitAvailabilityZone causes availability zone to be omitted when creating control plane nodes, + allowing the Nova scheduler to make a decision on which availability zone to use based on other scheduling constraints. + # Workers + - name: workerFlavor + required: false + schema: + openAPIV3Schema: + type: string + default: "SCS-4V-8" + example: "SCS-4V-8" + description: "OpenStack instance flavor for worker nodes (default: SCS-4V-8, which requires workerRootDisk)." + - name: workerRootDisk + required: false + schema: + openAPIV3Schema: + type: integer + minimum: 0 + example: 25 + default: 50 + description: |- + Root disk size in GiB for worker nodes. + OpenStack volume will be created and used instead of an ephemeral disk defined in flavor. + Should be used for the diskless flavors (>= 20), otherwise set to 0. + - name: workerServerGroupID + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "869fe071-1e56-46a9-9166-47c9f228e297" + description: "The server group to assign the worker nodes to." + - name: workerAdditionalBlockDevices + required: false + schema: + openAPIV3Schema: + type: array + default: [] + items: + type: object + properties: + name: + type: string + sizeGiB: + type: integer + default: 20 + type: + type: string + default: "__DEFAULT__" + required: ["name"] + # Bastion + - name: bastionEnabled + required: false + schema: + openAPIV3Schema: + type: boolean + default: false + example: false + description: "Enable or disable the bastion host." + - name: bastionFlavor + required: false + schema: + openAPIV3Schema: + type: string + default: "SCS-2V-4" + example: "SCS-2V-4-20s" + description: |- + OpenStack instance flavor for bastion nodes. + (Default: SCS-2V-4, replace by SCS-2V-4-20s or specify a bastionRootDisk.) + - name: bastionRootDisk + required: false + schema: + openAPIV3Schema: + type: integer + minimum: 0 + example: 25 + default: 25 + description: |- + Root disk size in GiB for bastion nodes. + OpenStack volume will be created and used instead of an ephemeral disk defined in flavor. + Should only be used for the diskless flavors (>= 20), otherwise set to 0. + - name: bastionServerGroupID + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "3adf4e92-bb33-4e44-8ad3-afda9dfe8ec3" + description: "The server group to assign the bastion nodes to (can be used for anti-affinity)." + # Access management + - name: sshKeyName + required: false + schema: + openAPIV3Schema: + type: string + default: "" + example: "capi-keypair" + description: "The ssh key name to inject in the nodes (for debugging)." + - name: securityGroups + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["security-group-1"] + description: |- + The names of extra security groups to assign to worker and control plane nodes. + Will be ignored if `securityGroupIDs` is used. + items: + type: string + - name: securityGroupIDs + required: false + schema: + openAPIV3Schema: + format: "uuid4" + type: array + default: [] + example: ["9ae2f488-30a3-4629-bd51-07acb8eb4278"] + description: "The UUIDs of extra security groups to assign to worker and control plane nodes" + items: + type: string + - name: workerSecurityGroups + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["security-group-1"] + description: |- + The names of extra security groups to assign to the worker nodes. + Will be ignored if `workerSecurityGroupIDs` is used. + items: + type: string + - name: workerSecurityGroupIDs + required: false + schema: + openAPIV3Schema: + format: "uuid4" + type: array + default: [] + example: ["9ae2f488-30a3-4629-bd51-07acb8eb4278"] + description: "The UUIDs of extra security groups to assign to the worker nodes" + items: + type: string + - name: identityRef + required: false + schema: + openAPIV3Schema: + type: object + default: {} + properties: + name: + type: string + example: "openstack" + default: "openstack" + description: "The name of the secret that carries the OpenStack clouds.yaml" + cloudName: + type: string + example: "openstack" + default: "openstack" + description: "The name of the cloud to use from the clouds.yaml" + # Kubernetes API server + - name: certSANs + required: false + schema: + openAPIV3Schema: + type: array + default: [] + example: ["mydomain.example"] + description: "certSANs sets extra Subject Alternative Names for the API Server signing cert." + items: + type: string + - name: apiServerLoadBalancer + required: false + schema: + openAPIV3Schema: + type: string + default: "octavia-ovn" + example: "none, octavia-amphora, octavia-ovn" + description: | + Cluster-API by default places a LoadBalancer in front of the kubernetes API server. + (There are also LBs that the CCM creates for a service type LoadBalancer which are configured independently.) + This setting here is to configure the LoadBalancer that is placed in front of the apiServer. + You can choose from 3 options: + + none: + No LoadBalancer solution will be deployed + + octavia-amphora: + Uses OpenStack's LoadBalancer service Octavia (provider:amphora) + + octavia-ovn: + (default) Uses OpenStack's LoadBalancer service Octavia (provider:ovn) + - name: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + required: false + schema: + openAPIV3Schema: + type: array + example: ["192.168.10.0/24"] + description: |- + apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs restrict access to the Kubernetes API server on a network level. + Ensure that at least the outgoing IP of your Management Cluster is added to the list of allowed CIDRs. + Otherwise CAPO can’t reconcile the target Cluster correctly. + This requires amphora as load balancer provider in version >= v2.12. + items: + type: string + - name: oidcConfig + required: false + schema: + openAPIV3Schema: + type: object + properties: + clientID: + type: string + example: "kubectl" + description: "A client id that all tokens must be issued for." + issuerURL: + type: string + example: "https://dex.k8s.scs.community" + description: >- + URL of the provider that allows the API server to + discover public signing keys. Only URLs that use the https:// scheme are + accepted. This is typically the provider's discovery URL, changed to have an + empty path. + usernameClaim: + type: string + example: "preferred_username" + default: "preferred_username" + description: >- + JWT claim to use as the user name. By default sub, + which is expected to be a unique identifier of the end user. Admins can choose + other claims, such as email or name, depending on their provider. However, + claims other than email will be prefixed with the issuer URL to prevent naming + clashes with other plugins. + groupsClaim: + type: string + example: "groups" + default: "groups" + description: "JWT claim to use as the user's group. If the claim is present it must be an array of strings." + usernamePrefix: + type: string + example: "oidc:" + default: "oidc:" + description: >- + Prefix prepended to username claims to prevent + clashes with existing names (such as system: users). For example, the value + oidc: will create usernames like oidc:jane.doe. If this flag isn't provided and + --oidc-username-claim is a value other than email the prefix defaults to ( + Issuer URL )# where ( Issuer URL ) is the value of --oidc-issuer-url. The value + - can be used to disable all prefixing. + groupsPrefix: + type: string + example: "oidc:" + default: "oidc:" + description: >- + Prefix prepended to group claims to prevent clashes + with existing names (such as system: groups). For example, the value oidc: will + create group names like oidc:engineering and oidc:infra. + # + # Patches + # + patches: + # + # Patches for OpenStackClusterTemplate resource. + # + - name: apiServerLoadBalancerOctaviaAmphora + description: "Takes care of the patches that should be applied when variable apiServerLoadBalancer is set to octavia-amphora." + enabledIf: {{ `'{{ eq .apiServerLoadBalancer "octavia-amphora" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: replace + path: "/spec/template/spec/apiServerLoadBalancer/enabled" + value: true + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/provider" + value: "amphora" + - name: apiServerLoadBalancerOctaviaOVN + description: "Takes care of the patches that should be applied when variable apiServerLoadBalancer is set to octavia-ovn." + enabledIf: {{ `'{{ eq .apiServerLoadBalancer "octavia-ovn" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: replace + path: "/spec/template/spec/apiServerLoadBalancer/enabled" + value: true + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/provider" + value: "ovn" + - name: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + description: "Takes care of the patches that should be applied when variable allowedCIDRs is set." + enabledIf: {{ `'{{ and .apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs (eq .apiServerLoadBalancer "octavia-amphora") }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/apiServerLoadBalancer/allowedCIDRs" + valueFrom: + variable: apiServerLoadBalancerOctaviaAmphoraAllowedCIDRs + - name: networkExternalID + description: "Sets the ID of an external OpenStack Network. This is necessary to get public internet to the VMs." + enabledIf: {{ `'{{ if .networkExternalID }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/externalNetwork" + value: {} + - op: add + path: "/spec/template/spec/externalNetwork/id" + valueFrom: + variable: networkExternalID + - name: networkMTU + description: "Sets the network MTU when variable networkMTU exist in cluster resource." + enabledIf: {{ `'{{ if .networkMTU }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/networkMTU" + valueFrom: + variable: networkMTU + - name: controlPlaneAvailabilityZones + description: "Sets the availability zones which control plane machines may be deployed to." + enabledIf: {{ `'{{ if .controlPlaneAvailabilityZones }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/controlPlaneAvailabilityZones" + valueFrom: + variable: controlPlaneAvailabilityZones + - name: controlPlaneOmitAvailabilityZone + description: "Causes availability zone to be omitted when creating control plane nodes." + enabledIf: {{ `'{{ if .controlPlaneOmitAvailabilityZone }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/controlPlaneOmitAvailabilityZone" + valueFrom: + variable: controlPlaneOmitAvailabilityZone + - name: identityRef + description: "Sets the OpenStack identity reference." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: /spec/template/spec/identityRef + valueFrom: + variable: identityRef + - name: nodeCIDRSubnet + description: |- + Sets the NodeCIDR for the OpenStack Subnet to be created. + Cluster actuator will create a network, a subnet with NodeCIDR, + and a router connected to this subnet. + enabledIf: {{ `'{{ if .nodeCIDR }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/managedSubnets" + valueFrom: + template: | + - cidr: '{{ `{{ .nodeCIDR }}` }}' + dnsNameservers: + {{ `{{- range .dnsNameservers }}` }} + - {{ `{{ . }}` }} + {{ `{{- end }}` }} + - name: disableAPIServerFloatingIP + description: "DisableAPIServerFloatingIP controls whether a floating IP should be attached to the API server." + enabledIf: {{ `"{{ if .disableAPIServerFloatingIP }}true{{end}}"` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/disableAPIServerFloatingIP" + valueFrom: + variable: disableAPIServerFloatingIP + - name: bastionEnabled + description: "Enables or disables the bastion host." + enabledIf: {{ `'{{ if .bastionEnabled }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/bastion/enabled" + valueFrom: + variable: bastionEnabled + - name: bastionImage + description: "Sets the OpenStack image name that is used for creating the bastion servers." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: /spec/template/spec/bastion/spec/image + valueFrom: + template: | + {{ `{{ if .imageIsOrc }}imageRef{{ else }}filter{{ end }}` }}: + name: {{ `{{ .imageName }}{{ if .imageAddVersion }}-{{ .builtin.controlPlane.version }}{{ end }}` }} + - name: bastionFlavor + description: "Sets the openstack instance flavor for the bastion." + enabledIf: {{ `'{{ ne .bastionFlavor "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: replace + path: "/spec/template/spec/bastion/spec/flavor" + valueFrom: + variable: bastionFlavor + - name: bastionRootDisk + description: "Sets the root disk size in GiB for bastion node." + enabledIf: {{ `'{{ if .bastionRootDisk }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/bastion/spec/rootVolume" + valueFrom: + template: | + sizeGiB: {{ `{{ .bastionRootDisk }}` }} + - name: bastionServerGroupID + description: "Sets the server group to assign the control plane nodes to." + enabledIf: {{ `'{{ ne .bastionServerGroupID "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/bastion/spec/serverGroup" + valueFrom: + template: | + id: {{ `{{ .bastionServerGroupID }}` }} + - name: clusterCNI + description: "Sets the CNI to be used for the cluster." + enabledIf: {{ `'{{ ne .clusterCNI "" }}'` }} + definitions: + - selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: RKE2ControlPlaneTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/serverConfig/cni" + valueFrom: + variable: clusterCNI + # + # Patches for control plane's OpenStackMachineTemplate resources. + # Note: Control plane patches are only applied when the control plane is managed by Kubeadm. + - name: controlPlaneImage + description: "Sets the OpenStack image name that is used for creating the control plane servers." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: /spec/template/spec/image + valueFrom: + template: | + {{ `{{ if .imageIsOrc }}imageRef{{ else }}filter{{ end }}` }}: + name: {{ `{{ .imageName }}{{ if .imageAddVersion }}-{{ .builtin.controlPlane.version }}{{ end }}` }} + - name: controlPlaneFlavor + description: "Sets the openstack instance flavor for the KubeadmControlPlane." + enabledIf: {{ `'{{ ne .controlPlaneFlavor "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: replace + path: "/spec/template/spec/flavor" + valueFrom: + variable: controlPlaneFlavor + - name: controlPlaneRootDisk + description: "Sets the root disk size in GiB for control-plane nodes." + enabledIf: {{ `'{{ if .controlPlaneRootDisk }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/rootVolume" + valueFrom: + template: | + sizeGiB: {{ `{{ .controlPlaneRootDisk }}` }} + - name: controlPlaneServerGroupID + description: "Sets the server group to assign the control plane nodes to." + enabledIf: {{ `'{{ ne .controlPlaneServerGroupID "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/serverGroup" + valueFrom: + template: | + id: {{ `{{ .controlPlaneServerGroupID }}` }} + # + # Patches for control plane's as well as worker's OpenStackMachineTemplate resources. + # Note: Control plane patches are only applied when the control plane is managed by Kubeadm. + # + # Note: The securityGroups patch must be placed before securityGroupIDs, workerSecurityGroups, and workerSecurityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: securityGroups + description: "Sets the list of the openstack security groups for the worker and the control plane instances." + enabledIf: {{ `'{{ if .securityGroups }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .securityGroups }} { filter: { name: {{ . }}}}, {{ end }} ]'` }} + # Note: The securityGroupIDs patch must be placed before workerSecurityGroups, workerSecurityGroupIDs and after securityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: securityGroupIDs + description: "Sets the list of the openstack security groups for the worker and the control plane instances by UUID." + enabledIf: {{ `'{{ if .securityGroupIDs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .securityGroupIDs }} { id: {{ . }} }, {{ end }} ]'` }} + - name: sshKeyName + description: "Sets the ssh key to inject in the nodes." + enabledIf: {{ `'{{ ne .sshKeyName "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: true + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/sshKeyName" + valueFrom: + variable: sshKeyName + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackClusterTemplate + matchResources: + infrastructureCluster: true + jsonPatches: + - op: add + path: "/spec/template/spec/bastion/spec/sshKeyName" + valueFrom: + variable: sshKeyName + # + # Patches for worker's OpenStackMachineTemplate resources. + # + - name: workerImage + description: "Sets the OpenStack image name that is used for creating the worker servers." + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: /spec/template/spec/image + valueFrom: + template: | + {{ `{{ if .imageIsOrc }}imageRef{{ else }}filter{{ end }}` }}: + name: {{ `{{ .imageName }}{{ if .imageAddVersion }}-{{ .builtin.machineDeployment.version }}{{ end }}` }} + - name: workerFlavor + description: "Sets the openstack instance flavor for the worker nodes." + enabledIf: {{ `'{{ ne .workerFlavor "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: replace + path: "/spec/template/spec/flavor" + valueFrom: + variable: workerFlavor + - name: workerRootDisk + description: "Sets the root disk size in GiB for worker nodes." + enabledIf: {{ `'{{ if .workerRootDisk }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/rootVolume" + valueFrom: + template: | + sizeGiB: {{ `{{ .workerRootDisk }}` }} + - name: workerServerGroupID + description: "Sets the server group to assign the worker nodes to." + enabledIf: {{ `'{{ ne .workerServerGroupID "" }}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/serverGroup" + valueFrom: + template: | + id: {{ `{{ .workerServerGroupID }}` }} + - name: workerAdditionalBlockDevices + enabledIf: {{ `'{{ if .workerAdditionalBlockDevices }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: /spec/template/spec/additionalBlockDevices + valueFrom: + template: | + {{ `{{- range .workerAdditionalBlockDevices }}` }} + - name: {{ `{{ .name }}` }} + sizeGiB: {{ `{{ .sizeGiB }}` }} + storage: + type: Volume + volume: + type: {{ `{{ .type }}` }} + {{ `{{- end }}` }} + # Note: The workerSecurityGroups patch must be placed before workerSecurityGroupIDs and after securityGroups and securityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: workerSecurityGroups + description: "Sets the list of the openstack security groups for the worker instances." + enabledIf: {{ `'{{ if .workerSecurityGroups }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .workerSecurityGroups }} { filter: { name: {{ . }}}}, {{ end }} ]'` }} + # Note: The workerSecurityGroupIDs patch must be placed after securityGroups, securityGroupIDs and workerSecurityGroupIDs. + # The patch order ensures the last applied patch overwrites previous ones. + - name: workerSecurityGroupIDs + description: "Sets the list of the openstack security groups for the worker instances by UUID." + enabledIf: {{ `'{{ if .workerSecurityGroupIDs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: OpenStackMachineTemplate + matchResources: + controlPlane: false + machineDeploymentClass: + names: + - default-worker + jsonPatches: + - op: add + path: "/spec/template/spec/securityGroups" + valueFrom: + template: {{ `'[ {{ range .workerSecurityGroupIDs }} { id: {{ . }} }, {{ end }} ]'` }} + # + - name: certSANs + description: "certSANs sets extra Subject Alternative Names for the API Server signing cert." + enabledIf: {{ `'{{ if .certSANs }}true{{end}}'` }} + definitions: + - selector: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: RKE2ControlPlaneTemplate + matchResources: + controlPlane: true + jsonPatches: + - op: add + path: "/spec/template/spec/serverConfig/tlsSAN" + valueFrom: + variable: certSANs diff --git a/providers/openstack/rke2/cluster-class/templates/openstack-cluster-template.yaml b/providers/openstack/rke2/cluster-class/templates/openstack-cluster-template.yaml new file mode 100644 index 00000000..2cd2f13d --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/openstack-cluster-template.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackClusterTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-cluster +spec: + template: + spec: + identityRef: + cloudName: overridden-by-patch + name: overridden-by-patch + apiServerLoadBalancer: + enabled: false + bastion: + enabled: false + spec: + flavor: overridden-by-patch + image: + filter: + name: overridden-by-patch + sshKeyName: overridden-by-patch + managedSecurityGroups: + allNodesSecurityGroupRules: + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: RKE2 Node registration + portRangeMin: 9345 + portRangeMax: 9345 + protocol: tcp + description: "Allow RKE2 node registration (server and agent)" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: Calico Typha + portRangeMin: 5473 + portRangeMax: 5473 + protocol: tcp + description: "Allow Calico-node pod connecting to typha pod" + - remoteIPPrefix: 0.0.0.0/0 + direction: ingress + etherType: IPv4 + name: SSH + portRangeMin: 22 + portRangeMax: 22 + protocol: tcp + description: "Allow SSH for node driver provisioning" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: VXLAN (Cilium) + portRangeMin: 8472 + portRangeMax: 8472 + protocol: udp + description: "Allow VXLAN traffic for Cilium" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: HealthCheck (Cilium) + portRangeMin: 4240 + portRangeMax: 4240 + protocol: tcp + description: "Allow HealthCheck traffic for Cilium" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: Hubble (Cilium) + portRangeMin: 4244 + portRangeMax: 4244 + protocol: tcp + description: "Allow Hubble traffic for Cilium" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: Rancher webhook (8443) + portRangeMin: 8443 + portRangeMax: 8443 + protocol: tcp + description: "Allow Rancher webhook traffic" + - remoteManagedGroups: + - controlplane + - worker + direction: ingress + etherType: IPv4 + name: Rancher webhook (9443) + portRangeMin: 9443 + portRangeMax: 9443 + protocol: tcp + description: "Allow Rancher webhook traffic" diff --git a/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-control-plane.yaml b/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-control-plane.yaml new file mode 100644 index 00000000..703c1b1c --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-control-plane.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackMachineTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane +spec: + template: + spec: + flavor: overridden-by-patch + image: + imageRef: + name: overridden-by-patch diff --git a/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-worker.yaml b/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-worker.yaml new file mode 100644 index 00000000..920dbb0a --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/openstack-machine-template-worker.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: OpenStackMachineTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker +spec: + template: + spec: + flavor: overridden-by-patch + image: + imageRef: + name: overridden-by-patch diff --git a/providers/openstack/rke2/cluster-class/templates/rke2-config-template-worker-openstack.yaml b/providers/openstack/rke2/cluster-class/templates/rke2-config-template-worker-openstack.yaml new file mode 100644 index 00000000..173871d9 --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/rke2-config-template-worker-openstack.yaml @@ -0,0 +1,16 @@ +apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 +kind: RKE2ConfigTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-default-worker +spec: + template: + spec: + preRKE2Commands: + - sleep 30 # fix to give OS time to become ready + agentConfig: + kubelet: + extraArgs: + - provider-id=openstack:///{{ `{{ instance_id }}` }} # Data from Openstack metadata-service + - cloud-provider=external + nodeName: '{{ `{{ local_hostname }}` }}' # Data from Openstack metadata-service + gzipUserData: false diff --git a/providers/openstack/rke2/cluster-class/templates/rke2-control-plane-template.yaml b/providers/openstack/rke2/cluster-class/templates/rke2-control-plane-template.yaml new file mode 100644 index 00000000..3933ee5b --- /dev/null +++ b/providers/openstack/rke2/cluster-class/templates/rke2-control-plane-template.yaml @@ -0,0 +1,24 @@ +apiVersion: controlplane.cluster.x-k8s.io/v1beta1 +kind: RKE2ControlPlaneTemplate +metadata: + name: {{ .Release.Name }}-{{ .Chart.Version }}-control-plane +spec: + template: + spec: + agentConfig: + kubelet: + extraArgs: + - provider-id=openstack:///{{ `{{ instance_id }}` }} # Data from Openstack metadata-service + nodeName: '{{ `{{ local_hostname }}` }}' # Data from Openstack metadata-service + gzipUserData: false + version: "" + rolloutStrategy: + type: "RollingUpdate" + rollingUpdate: + maxSurge: 1 + registrationMethod: "internal-first" + serverConfig: + cni: calico + disableComponents: + kubernetesComponents: + - cloudController # We use use openstack-cloud-controller-manager diff --git a/providers/openstack/rke2/cluster-class/values.yaml b/providers/openstack/rke2/cluster-class/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/providers/openstack/rke2/clusteraddon.yaml b/providers/openstack/rke2/clusteraddon.yaml new file mode 100644 index 00000000..4f9f9773 --- /dev/null +++ b/providers/openstack/rke2/clusteraddon.yaml @@ -0,0 +1,13 @@ +apiVersion: clusteraddonconfig.x-k8s.io/v1alpha1 +clusterAddonVersion: clusteraddons.clusterstack.x-k8s.io/v1alpha1 +addonStages: + AfterControlPlaneInitialized: + - name: csi + action: apply + - name: ccm + action: apply + BeforeClusterUpgrade: + - name: csi + action: apply + - name: ccm + action: apply diff --git a/providers/openstack/rke2/csctl.yaml b/providers/openstack/rke2/csctl.yaml new file mode 100644 index 00000000..ef38efcd --- /dev/null +++ b/providers/openstack/rke2/csctl.yaml @@ -0,0 +1,7 @@ +apiVersion: csctl.clusterstack.x-k8s.io/v1alpha1 +config: + clusterStackName: rke2 + kubernetesVersion: v1.33.6+rke2r1 + provider: + apiVersion: openstack.csctl.clusterstack.x-k8s.io/v1alpha1 + type: openstack diff --git a/providers/openstack/rke2/versions.yaml b/providers/openstack/rke2/versions.yaml new file mode 100644 index 00000000..7296c226 --- /dev/null +++ b/providers/openstack/rke2/versions.yaml @@ -0,0 +1,3 @@ +- kubernetes: 1.33.6+rke2r1 + cinder_csi: 2.33.1 + occm: 2.33.1 From 1df78a7b30788afa099e5ab23cf7e84df63596d2 Mon Sep 17 00:00:00 2001 From: Axel Schmidt Date: Fri, 19 Dec 2025 12:32:30 +0100 Subject: [PATCH 2/2] some spelling improvements of README.md Signed-off-by: Axel Schmidt --- providers/openstack/rke2/README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/providers/openstack/rke2/README.md b/providers/openstack/rke2/README.md index c07ceddf..834a6f5c 100644 --- a/providers/openstack/rke2/README.md +++ b/providers/openstack/rke2/README.md @@ -2,13 +2,13 @@ ## Getting started -At first you need a Ready installed Rancher Management Dashboard (without any existing Downstreamclusters installed via custom-cluster. The cso will breake the management). +To begin, ensure you have a functional Rancher Management Dashboard. Note that there must be no existing downstream clusters installed via the "custom-cluster" method, as the Cluster Stacks Operator (CSO) will conflict with the cluster management. -For Rancher Version < 2.13 you must install the Rancher Turtles to open the preinstalled capi. https://ranchermanager.docs.rancher.com/integrations-in-rancher/cluster-api/overview +For Rancher versions prior to 2.13, you must manually install Rancher Turtles to enable the preinstalled Cluster API (CAPI) functionality. Refer to the Rancher CAPI Overview for more details. -For Rancher Version >= 2.13 the Rancher Turtles is preinstalled and enabled by default. Only the Rancher Turtles UI must be installed sepratly. https://turtles.docs.rancher.com/turtles/v0.24/en/tutorials/quickstart.html#_capi_ui_extension_installation +For Rancher versions 2.13 and later, Rancher Turtles is preinstalled and enabled by default. However, the Rancher Turtles UI extension must be installed separately. Installation instructions can be found in the Turtles Quickstart Guide. -Now you must install following providers (via GUI Cluster Management > CAPI > Provider > Create) +Once the environment is prepared, install the required providers via the GUI by navigating to Cluster Management > CAPI > Provider > Create |Key|Value bootstrap|Value controlplane|Value infrastructure| |---|---|---|--| @@ -119,7 +119,7 @@ spec: topology: variables: - name: clusterCNI - value: "cilium" # also calicio is posible, but musst be manual patched after install: kubectl patch ippools.crd.projectcalico.org default-ipv4-ippool --type='json' -p '[{"op": "replace", "path": "/spec/ipipMode", "value":"CrossSubnet"}]' + value: "cilium" # Calicio is also possible, but must be manually patched after installation.: kubectl patch ippools.crd.projectcalico.org default-ipv4-ippool --type='json' -p '[{"op": "replace", "path": "/spec/ipipMode", "value":"CrossSubnet"}]' - name: apiServerLoadBalancer value: "octavia-ovn" - name: imageAddVersion @@ -150,9 +150,7 @@ EOF ```sh clusterctl get kubeconfig -n $CLUSTER_NAMESPACE $CLUSTER_NAME > /tmp/kubeconfig kubectl get nodes --kubeconfig /tmp/kubeconfig -# Enable rke2-ingress-loadbalancer -kubectl --kubeconfig /tmp/kubeconfig -n kube-system patch HelmChart.helm.cattle.io rke2-ingress-nginx --type='json' -p '[{"op": "add", "path": "/spec/set/'controller.service.enabled'", "value":"true"}]' -# Set rke2-ingress-loadbalancer-IP -kubectl --kubeconfig /tmp/kubeconfig -n kube-system patch HelmChart.helm.cattle.io rke2-ingress-nginx --type='json' -p '[{"op": "add", "path": "/spec/set/'controller.service.loadBalancerIP'", "value":"xxx.xxx.xxx.xxx"}]' +# Enable rke2-ingress-loadbalancer and set loadBalancerIP +kubectl --kubeconfig /tmp/kubeconfig -n kube-system patch HelmChart.helm.cattle.io rke2-ingress-nginx --type='json' -p '[{"op": "add", "path": "/spec/set/'controller.service.enabled'", "value":"true"}, {"op": "add", "path": "/spec/set/'controller.service.loadBalancerIP'", "value":"xxx.xxx.xxx.xxx"}]' ```