|
| 1 | +# Migration Guide: v1alpha2 to v1alpha3 |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The v1alpha3 API version introduces significant simplifications by removing the `ManagerSpec` type and consolidating all provider configuration directly into `ContainerSpec.Args`. This change makes the API more flexible and easier to understand. |
| 6 | + |
| 7 | +## Key Changes |
| 8 | + |
| 9 | +### 1. Removed Types |
| 10 | +- `ManagerSpec` - All fields moved to container args |
| 11 | +- `ControllerManagerConfiguration` - Configuration now in args |
| 12 | +- `ControllerConfigurationSpec` - Controller settings now in args |
| 13 | +- `ControllerMetrics` - Metrics configuration now in args |
| 14 | +- `ControllerHealth` - Health probe configuration now in args |
| 15 | +- `ControllerWebhook` - Webhook configuration now in args |
| 16 | +- `AdditionalDeployments` struct - Replaced with direct `DeploymentSpec` |
| 17 | + |
| 18 | +### 2. ProviderSpec Changes |
| 19 | + |
| 20 | +During conversion from v1alpha2 to v1alpha3, the `ManagerSpec` is converted to a container with an **empty name** (`""`). The code then determines the correct container name to apply these changes to at runtime using the following logic: |
| 21 | +1. First, it checks if a default container is specified in the deployment's annotations (`kubectl.kubernetes.io/default-container`) |
| 22 | +2. Then, it looks for a container named "manager" |
| 23 | +3. As a last resort, it uses the first container in the deployment |
| 24 | + |
| 25 | +**Important**: Even if the container with empty name is specified first in the container list, its changes will be applied **after** all other containers. This ensures that explicit container configurations take precedence over the converted ManagerSpec settings. |
| 26 | + |
| 27 | +#### v1alpha2 (Old) |
| 28 | +```yaml |
| 29 | +spec: |
| 30 | + manager: |
| 31 | + maxConcurrentReconciles: 10 |
| 32 | + verbosity: 2 |
| 33 | + featureGates: |
| 34 | + FeatureA: true |
| 35 | + deployment: |
| 36 | + containers: |
| 37 | + - name: manager |
| 38 | +``` |
| 39 | +
|
| 40 | +#### v1alpha3 (New) |
| 41 | +```yaml |
| 42 | +spec: |
| 43 | + deployment: |
| 44 | + containers: |
| 45 | + - name: "" # Empty name - the code will determine the correct container |
| 46 | + args: |
| 47 | + "--max-concurrent-reconciles": "10" |
| 48 | + "--v": "2" |
| 49 | + "--feature-gates": "FeatureA=true" |
| 50 | +``` |
| 51 | +
|
| 52 | +### 3. AdditionalDeployments Changes |
| 53 | +
|
| 54 | +The `AdditionalDeployments` type has been simplified: |
| 55 | +- **v1alpha2**: `map[string]AdditionalDeployments` where `AdditionalDeployments` is a struct with `Manager` and `Deployment` fields |
| 56 | +- **v1alpha3**: `map[string]DeploymentSpec` - directly maps to deployment specifications without the wrapper struct |
| 57 | + |
| 58 | +**Important Note**: During conversion from v1alpha2 to v1alpha3, the `ManagerSpec` fields in `additionalDeployments` are **NOT** converted to container args. This is because additional deployments are not Cluster API providers, and therefore the `ManagerSpec` configuration is not applicable to them. The `Manager` field is simply dropped during conversion, and only the `Deployment` field is preserved. |
| 59 | + |
| 60 | +#### v1alpha2 (Old) |
| 61 | +```yaml |
| 62 | +additionalDeployments: |
| 63 | + webhook: |
| 64 | + manager: # These settings are dropped during conversion |
| 65 | + verbosity: 2 |
| 66 | + metrics: |
| 67 | + bindAddress: ":9090" |
| 68 | + deployment: # Only this is preserved |
| 69 | + replicas: 2 |
| 70 | + containers: |
| 71 | + - name: webhook |
| 72 | +``` |
| 73 | + |
| 74 | +#### v1alpha3 (New) |
| 75 | +```yaml |
| 76 | +additionalDeployments: |
| 77 | + webhook: # Directly a DeploymentSpec, no wrapper struct |
| 78 | + replicas: 2 |
| 79 | + containers: |
| 80 | + - name: webhook |
| 81 | + # Note: manager settings are not converted to args |
| 82 | + # Users must manually add args if needed |
| 83 | +``` |
| 84 | + |
| 85 | +## Argument Mappings |
| 86 | + |
| 87 | +| v1alpha2 ManagerSpec Field | v1alpha3 Container Arg | |
| 88 | +|---|---| |
| 89 | +| `maxConcurrentReconciles` | `--max-concurrent-reconciles` | |
| 90 | +| `cacheNamespace` | `--namespace` | |
| 91 | +| `health.healthProbeBindAddress` | `--health-addr` | |
| 92 | +| `leaderElection.leaderElect` | `--leader-elect` | |
| 93 | +| `leaderElection.resourceNamespace/resourceName` | `--leader-election-id=<namespace>/<name>` | |
| 94 | +| `leaderElection.leaseDuration` | `--leader-elect-lease-duration` | |
| 95 | +| `leaderElection.renewDeadline` | `--leader-elect-renew-deadline` | |
| 96 | +| `leaderElection.retryPeriod` | `--leader-elect-retry-period` | |
| 97 | +| `metrics.bindAddress` | `--metrics-bind-addr` | |
| 98 | +| `metrics.diagnosticsAddress` | `--diagnostics-address` | |
| 99 | +| `metrics.insecureDiagnostics` | `--insecure-diagnostics` | |
| 100 | +| `webhook.host` | `--webhook-host` | |
| 101 | +| `webhook.port` | `--webhook-port` | |
| 102 | +| `webhook.certDir` | `--webhook-cert-dir` | |
| 103 | +| `syncPeriod` | `--sync-period` | |
| 104 | +| `profilerAddress` | `--profiler-address` | |
| 105 | +| `verbosity` | `--v` | |
| 106 | +| `featureGates` | `--feature-gates` | |
| 107 | +| `controller.groupKindConcurrency.<resource>` | `--<resource>-concurrency` | |
| 108 | +| `additionalArgs` | Merged directly into args | |
| 109 | + |
| 110 | +### Special Cases |
| 111 | + |
| 112 | +1. **LivenessEndpointName** and **ReadinessEndpointName**: These are not converted to args but should be configured by modifying the container's probe paths directly. |
| 113 | + |
| 114 | +2. **GroupKindConcurrency**: Each entry becomes a separate arg. For example: |
| 115 | + - `controller.groupKindConcurrency.Cluster: 10` → `--cluster-concurrency=10` |
| 116 | + - `controller.groupKindConcurrency.Machine: 5` → `--machine-concurrency=5` |
| 117 | + |
| 118 | +3. **Feature Gates**: Multiple feature gates are combined into a single comma-separated arg: |
| 119 | + - `featureGates: {FeatureA: true, FeatureB: false}` → `--feature-gates=FeatureA=true,FeatureB=false` |
| 120 | + |
| 121 | +## Conversion Behavior |
| 122 | + |
| 123 | +The operator includes automatic conversion between v1alpha2 and v1alpha3: |
| 124 | + |
| 125 | +1. **v1alpha2 → v1alpha3**: |
| 126 | + - The `ManagerSpec` fields are automatically converted to container args in a container with **empty name** (`""`) |
| 127 | + - The runtime code determines which container to apply these settings to (see logic in section 2) |
| 128 | + - Container with empty name is processed **after** all other containers, ensuring explicit configurations take precedence |
| 129 | + - For `additionalDeployments`, the `ManagerSpec` is **not** converted - only the `Deployment` field is preserved |
| 130 | + |
| 131 | +2. **v1alpha3 → v1alpha2**: |
| 132 | + - Container args are parsed and reconstructed into a `ManagerSpec` structure |
| 133 | + - The container with empty name (if present) is interpreted as the manager configuration |
| 134 | + |
| 135 | +3. **Round-trip guarantee**: Converting from v1alpha2 to v1alpha3 and back preserves all settings for the main provider deployment (though `additionalDeployments` manager settings are lost) |
| 136 | + |
| 137 | +## Hub Version |
| 138 | + |
| 139 | +v1alpha3 is marked as the hub version and storage version. This means: |
| 140 | +- All versions are converted to v1alpha3 internally |
| 141 | +- v1alpha3 is stored in etcd |
| 142 | +- Conversions happen automatically when accessing different API versions |
| 143 | + |
| 144 | +## Benefits |
| 145 | + |
| 146 | +1. **Simplicity**: Single place for all provider configuration, no wrapper structs |
| 147 | +2. **Flexibility**: Easy to add custom provider-specific flags |
| 148 | +3. **Transparency**: Direct mapping to container arguments |
| 149 | +4. **Compatibility**: Automatic conversion maintains backward compatibility |
| 150 | + |
| 151 | +## Example Migration |
| 152 | + |
| 153 | +Here are complete examples of both v1alpha2 and v1alpha3 formats. |
| 154 | + |
| 155 | +```yaml |
| 156 | +# Example of v1alpha3 CoreProvider without ManagerSpec |
| 157 | +# All manager configuration is now in containerSpec.args |
| 158 | +apiVersion: operator.cluster.x-k8s.io/v1alpha3 |
| 159 | +kind: CoreProvider |
| 160 | +metadata: |
| 161 | + name: cluster-api |
| 162 | + namespace: capi-system |
| 163 | +spec: |
| 164 | + version: v1.5.0 |
| 165 | + deployment: |
| 166 | + replicas: 1 |
| 167 | + containers: |
| 168 | + # When converted from v1alpha2, the ManagerSpec becomes a container with empty name |
| 169 | + - name: "" # Empty name - runtime will determine the target container |
| 170 | + args: |
| 171 | + # These args replace the old ManagerSpec fields |
| 172 | + "--max-concurrent-reconciles": "10" |
| 173 | + "--namespace": "capi-system" |
| 174 | + "--health-addr": ":8081" |
| 175 | + "--metrics-bind-addr": ":8080" |
| 176 | + "--leader-elect": "true" |
| 177 | + "--leader-election-id": "capi-system/cluster-api-controller-leader" |
| 178 | + "--sync-period": "30s" |
| 179 | + "--v": "2" |
| 180 | + "--feature-gates": "ClusterTopology=true,MachinePool=false" |
| 181 | + "--webhook-host": "0.0.0.0" |
| 182 | + "--webhook-port": "9443" |
| 183 | + "--profiler-address": "localhost:6060" |
| 184 | + # Concurrency settings for different resources |
| 185 | + "--cluster-concurrency": "10" |
| 186 | + "--machine-concurrency": "5" |
| 187 | + # Custom args |
| 188 | + "--custom-flag": "custom-value" |
| 189 | + # Example of additionalDeployments - now directly maps to DeploymentSpec |
| 190 | + # No longer wrapped in an extra struct, just direct DeploymentSpec values |
| 191 | + # NOTE: ManagerSpec from v1alpha2 is NOT converted for additional deployments |
| 192 | + additionalDeployments: |
| 193 | + webhook: |
| 194 | + replicas: 2 |
| 195 | + containers: |
| 196 | + - name: webhook |
| 197 | + # Users must manually specify args - not converted from v1alpha2 ManagerSpec |
| 198 | +--- |
| 199 | +# Example of v1alpha2 CoreProvider with ManagerSpec (old style) |
| 200 | +# This will be automatically converted to v1alpha3 format |
| 201 | +apiVersion: operator.cluster.x-k8s.io/v1alpha2 |
| 202 | +kind: CoreProvider |
| 203 | +metadata: |
| 204 | + name: cluster-api-v2 |
| 205 | + namespace: capi-system |
| 206 | +spec: |
| 207 | + version: v1.5.0 |
| 208 | + manager: |
| 209 | + maxConcurrentReconciles: 10 |
| 210 | + cacheNamespace: capi-system |
| 211 | + health: |
| 212 | + healthProbeBindAddress: ":8081" |
| 213 | + metrics: |
| 214 | + bindAddress: ":8080" |
| 215 | + leaderElection: |
| 216 | + leaderElect: true |
| 217 | + resourceNamespace: capi-system |
| 218 | + resourceName: cluster-api-controller-leader |
| 219 | + syncPeriod: 30s |
| 220 | + verbosity: 2 |
| 221 | + featureGates: |
| 222 | + ClusterTopology: true |
| 223 | + MachinePool: false |
| 224 | + webhook: |
| 225 | + host: "0.0.0.0" |
| 226 | + port: 9443 |
| 227 | + profilerAddress: "localhost:6060" |
| 228 | + controller: |
| 229 | + groupKindConcurrency: |
| 230 | + cluster: 10 |
| 231 | + machine: 5 |
| 232 | + additionalArgs: |
| 233 | + "--custom-flag": "custom-value" |
| 234 | + deployment: |
| 235 | + replicas: 1 |
| 236 | + containers: |
| 237 | + - name: manager |
| 238 | + # Example of additionalDeployments in v1alpha2 - includes both Manager and Deployment |
| 239 | + # IMPORTANT: The manager field here will be IGNORED during conversion to v1alpha3 |
| 240 | + additionalDeployments: |
| 241 | + webhook: |
| 242 | + manager: # This entire section is dropped during conversion |
| 243 | + verbosity: 2 |
| 244 | + metrics: |
| 245 | + bindAddress: ":9090" |
| 246 | + webhook: |
| 247 | + port: 8443 |
| 248 | + deployment: # Only this section is preserved in v1alpha3 |
| 249 | + replicas: 2 |
| 250 | + containers: |
| 251 | + - name: webhook |
| 252 | +``` |
0 commit comments