|
| 1 | +# Migration from v1 to v2 |
| 2 | + |
| 3 | +Make sure you understand the [differences between Kubebuilder v1 and v2](./v1vsv2.md) |
| 4 | +before continuing |
| 5 | + |
| 6 | +Please ensure you have followed the [installation guide](/quick-start.md#installation) |
| 7 | +to install the required components. |
| 8 | + |
| 9 | +The recommended way to migrate a v1 project is to create a new v2 project and |
| 10 | +copy over the API and the reconciliation code. The conversion will end up with a |
| 11 | +project that looks like a native v2 project. However, in some cases, it's |
| 12 | +possible to do an in-place upgrade (i.e. reuse the v1 project layout, upgrading |
| 13 | +controller-runtime and controller-tools. |
| 14 | + |
| 15 | +Let's take the [example v1 project][v1-project] and migrate it to Kubebuilder |
| 16 | +v2. At the end, we should have something that looks like the |
| 17 | +[example v2 project][v2-project]. |
| 18 | + |
| 19 | +## Preparation |
| 20 | + |
| 21 | +We'll need to figure out what the group, version, kind and domain are. |
| 22 | + |
| 23 | +Let's take a look at our current v1 project structure: |
| 24 | + |
| 25 | +``` |
| 26 | +pkg/ |
| 27 | +├── apis |
| 28 | +│ ├── addtoscheme_batch_v1.go |
| 29 | +│ ├── apis.go |
| 30 | +│ └── batch |
| 31 | +│ ├── group.go |
| 32 | +│ └── v1 |
| 33 | +│ ├── cronjob_types.go |
| 34 | +│ ├── cronjob_types_test.go |
| 35 | +│ ├── doc.go |
| 36 | +│ ├── register.go |
| 37 | +│ ├── v1_suite_test.go |
| 38 | +│ └── zz_generated.deepcopy.go |
| 39 | +├── controller |
| 40 | +└── webhook |
| 41 | +``` |
| 42 | + |
| 43 | +All of our API information is stored in `pkg/apis/batch`, so we can look |
| 44 | +there to find what we need to know. |
| 45 | + |
| 46 | +In `cronjob_types.go`, we can find |
| 47 | + |
| 48 | +```go |
| 49 | +type CronJob struct {...} |
| 50 | +``` |
| 51 | + |
| 52 | +In `register.go`, we can find |
| 53 | + |
| 54 | +```go |
| 55 | +SchemeGroupVersion = schema.GroupVersion{Group: "batch.tutorial.kubebuilder.io", Version: "v1"} |
| 56 | +``` |
| 57 | + |
| 58 | +Putting that together, we get `CronJob` as the kind, and `batch.tutorial.kubebuilder.io/v1` as the group-version |
| 59 | + |
| 60 | +## Initialize a v2 Project |
| 61 | + |
| 62 | +Now, we need to initialize a v2 project. Before we do that, though, we'll need |
| 63 | +to initialize a new go module if we're not on the `gopath`: |
| 64 | + |
| 65 | +```bash |
| 66 | +go mod init tutorial.kubebuilder.io/project |
| 67 | +``` |
| 68 | + |
| 69 | +Then, we can finish initializing the project with kubebuilder: |
| 70 | + |
| 71 | +```bash |
| 72 | +kubebuilder init --domain tutorial.kubebuilder.io |
| 73 | +``` |
| 74 | + |
| 75 | +## Migrate APIs and Controllers |
| 76 | + |
| 77 | +Next, we'll re-scaffold out the API types and controllers. Since we want both, |
| 78 | +we'll say yes to both the API and controller prompts when asked what parts we |
| 79 | +want to scaffold: |
| 80 | + |
| 81 | +```bash |
| 82 | +kubebuilder create api --group batch --version v1 --kind CronJob |
| 83 | +``` |
| 84 | + |
| 85 | +If you're using multiple groups, some manual work is required to migrate. |
| 86 | +Please follow [this](/TODO.md) for more details. |
| 87 | + |
| 88 | +### Migrate the APIs |
| 89 | + |
| 90 | +Now, let's copy the API definition from `pkg/apis/batch/v1/cronjob_types.go` to |
| 91 | +`api/v1/cronjob_types.go`. We only need to copy the implementation of the `Spec` |
| 92 | +and `Status` fields. |
| 93 | + |
| 94 | +We can replace the `+k8s:deepcopy-gen:interfaces=...` marker (which is |
| 95 | +[deprecated in kubebuilder](/reference/markers/object.md)) with |
| 96 | +`+kubebuilder:object:root=true`. |
| 97 | + |
| 98 | +We don't need the following markers any more (they're not used anymore, and are |
| 99 | +relics from much older versions of KubeBuilder): |
| 100 | + |
| 101 | +```go |
| 102 | +// +genclient |
| 103 | +// +k8s:openapi-gen=true |
| 104 | +``` |
| 105 | + |
| 106 | +Our API types should look like the following: |
| 107 | + |
| 108 | +```go |
| 109 | +// +kubebuilder:object:root=true |
| 110 | + |
| 111 | +// CronJob is the Schema for the cronjobs API |
| 112 | +type CronJob struct {...} |
| 113 | + |
| 114 | +// +kubebuilder:object:root=true |
| 115 | + |
| 116 | +// CronJobList contains a list of CronJob |
| 117 | +type CronJobList struct {...} |
| 118 | +``` |
| 119 | + |
| 120 | +### Migrate the Controllers |
| 121 | + |
| 122 | +Now, let's migrate the controller reconciler code from |
| 123 | +`pkg/controller/cronjob/cronjob_controller.go` to |
| 124 | +`controllers/cronjob_controller.go`. |
| 125 | + |
| 126 | +We'll need to copy |
| 127 | +- the fields from the `ReconcileCronJob` struct to `CronJobReconciler` |
| 128 | +- the contents of the `Reconcile` function |
| 129 | +- the [rbac related markers](/reference/markers/rbac.md) to the new file. |
| 130 | +- the code under `func add(mgr manager.Manager, r reconcile.Reconciler) error` |
| 131 | +to `func SetupWithManager` |
| 132 | + |
| 133 | +## Migrate the Webhooks |
| 134 | + |
| 135 | +If you don't have a webhook, you can skip this section. |
| 136 | + |
| 137 | +### Webhooks for Core Types and External CRDs |
| 138 | + |
| 139 | +If you are using webhooks for Kubernetes core types (e.g. Pods), or for an |
| 140 | +external CRD that is not owned by you, you can refer the |
| 141 | +[controller-runtime example for builtin types][builtin-type-example] |
| 142 | +and do something similar. Kubebuilder doesn't scaffold much for these cases, but |
| 143 | +you can use the library in controller-runtime. |
| 144 | + |
| 145 | +### Scaffold Webhooks for our CRDs |
| 146 | + |
| 147 | +Now let's scaffold the webhooks for our CRD (CronJob). We'll need to run the |
| 148 | +following command with the `--defaulting` and `--programmatic-validation` flags |
| 149 | +(since our test project uses defaulting and validating webhooks): |
| 150 | + |
| 151 | +```bash |
| 152 | +kubebuilder create webhook --group batch --version v1 --kind CronJob --defaulting --programmatic-validation |
| 153 | +``` |
| 154 | + |
| 155 | +Depending on how many CRDs need webhooks, we may need to run the above command |
| 156 | +multiple times with different Group-Version-Kinds. |
| 157 | + |
| 158 | +Now, we'll need to copy the logic for each webhook. For validating webhooks, we |
| 159 | +can copy the contents from |
| 160 | +`func validatingCronJobFn` in `pkg/default_server/cronjob/validating/cronjob_create_handler.go` |
| 161 | +to `func ValidateCreate` in `api/v1/cronjob_webhook.go` and then the same for `update`. |
| 162 | + |
| 163 | +Similarly, we'll copy from `func mutatingCronJobFn` to `func Default`. |
| 164 | + |
| 165 | +### Webhook Markers |
| 166 | + |
| 167 | +When scaffolding webhooks, Kubebuilder v2 adds the following markers: |
| 168 | + |
| 169 | +``` |
| 170 | +// These are v2 markers |
| 171 | +
|
| 172 | +// This is for the mutating webhook |
| 173 | +// +kubebuilder:webhook:path=/mutate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=true,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=mcronjob.kb.io |
| 174 | +
|
| 175 | +... |
| 176 | +
|
| 177 | +// This is for the validating webhook |
| 178 | +// +kubebuilder:webhook:path=/validate-batch-tutorial-kubebuilder-io-v1-cronjob,mutating=false,failurePolicy=fail,groups=batch.tutorial.kubebuilder.io,resources=cronjobs,verbs=create;update,versions=v1,name=vcronjob.kb.io |
| 179 | +``` |
| 180 | + |
| 181 | +The default verbs are `verbs=create;update`. We need to ensure `verbs` matches |
| 182 | +what we need. For example, if we only want to validate creation, then we would |
| 183 | +change it to `verbs=create`. |
| 184 | + |
| 185 | +We also need to ensure `failure-policy` is still the same. |
| 186 | + |
| 187 | +Markers like the following are no longer needed (since they deal with |
| 188 | +self-deploying certificate configuration, which was removed in v2): |
| 189 | + |
| 190 | +```go |
| 191 | +// v1 markers |
| 192 | +// +kubebuilder:webhook:port=9876,cert-dir=/tmp/cert |
| 193 | +// +kubebuilder:webhook:service=test-system:webhook-service,selector=app:webhook-server |
| 194 | +// +kubebuilder:webhook:secret=test-system:webhook-server-secret |
| 195 | +// +kubebuilder:webhook:mutating-webhook-config-name=test-mutating-webhook-cfg |
| 196 | +// +kubebuilder:webhook:validating-webhook-config-name=test-validating-webhook-cfg |
| 197 | +``` |
| 198 | + |
| 199 | +In v1, a single webhook marker may be split into multiple ones in the same |
| 200 | +paragraph. In v2, each webhook must be represented by a single marker. |
| 201 | + |
| 202 | +## Others |
| 203 | + |
| 204 | +If there are any manual updates in `main.go` in v1, we need to port the changes |
| 205 | +to the new `main.go`. We'll also need to ensure all of the needed schemes have |
| 206 | +been registered. |
| 207 | + |
| 208 | +If there are additional manifests added under `config` directory, port them as |
| 209 | +well. |
| 210 | + |
| 211 | +Change the image name in the Makefile if needed. |
| 212 | + |
| 213 | +## Verification |
| 214 | + |
| 215 | +Finally, we can run `make` and `make docker-build` to ensure things are working |
| 216 | +fine. |
| 217 | + |
| 218 | +[v1-project]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/migration/testdata/gopath/project |
| 219 | +[v2-project]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/docs/book/src/cronjob-tutorial/testdata/project |
| 220 | +[builtin-type-example]: https://sigs.k8s.io/controller-runtime/examples/builtins |
0 commit comments