Skip to content

Commit fc6a7c1

Browse files
committed
Add migration guide
1 parent c27d99c commit fc6a7c1

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed

docs/kubebuilder_v0_v1_difference.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Kubebuilder v0 v.s. v1
2+
3+
## command difference
4+
- kubebuilder v0 has `init`, `create controller`, `create resouece`, `create config`, `generate` commands and the workflow is
5+
6+
```
7+
kubebuilder init --domain example.com
8+
kubebuilder create resource --group <group> --version <version> --kind <Kind>
9+
GOBIN=${PWD}/bin go install ${PWD#$GOPATH/src/}/cmd/controller-manager
10+
bin/controller-manager --kubeconfig ~/.kube/config
11+
12+
kubectl apply -f hack/sample/<resource>.yaml
13+
docker build -f Dockerfile.controller . -t <image:tag>
14+
docker push <image:tag>
15+
kubebuilder create config --controller-image <image:tag> --name <project-name>
16+
kubectl apply -f hack/install.yaml
17+
```
18+
Everytime the resource or controller is updated, users need to run `kubebuilder generate` to regenerate the project.
19+
- kubebuilder v1 has `init`, `create api` commands and the workflow is
20+
21+
```
22+
kubebuilder init --domain example.com --license apache2 --owner "The Kubernetes authors"
23+
kubebuilder create api --group ship --version v1beta1 --kind Frigate
24+
make install
25+
make run
26+
```
27+
In v1 project, there is no generate command. When the resource or controller is updated, users don't need to regenerate the project.
28+
29+
## scaffolding difference
30+
Init a project with example.com and add a resource/api with group apps, version v1, kind Hello in both v0 and v1. The scaffolded projects are as follows.
31+
- v0 project
32+
```
33+
.
34+
├── cmd
35+
│   └── controller-manager
36+
│   └── main.go
37+
├── Dockerfile.controller
38+
├── Gopkg.lock
39+
├── Gopkg.toml
40+
├── hack
41+
│   ├── boilerplate.go.txt
42+
│   ├── doc.go
43+
│   ├── imports.go
44+
│   └── sample
45+
│   └── hello.yaml
46+
├── pkg
47+
│   ├── apis
48+
│   │   ├── apps
49+
│   │   │   ├── doc.go
50+
│   │   │   └── v1
51+
│   │   └── doc.go
52+
│   ├── client
53+
│   │   ├── clientset
54+
│   │   │   └── versioned
55+
│   │   ├── informers
56+
│   │   │   └── externalversions
57+
│   │   └── listers
58+
│   │   └── apps
59+
│   ├── controller
60+
│   │   ├── doc.go
61+
│   │   └── hello
62+
│   │   ├── controller.go
63+
│   │   ├── controller_test.go
64+
│   │   └── hello_suite_test.go
65+
│   ├── doc.go
66+
│   └── inject
67+
│   ├── args
68+
│   │   └── args.go
69+
│   ├── doc.go
70+
│   ├── inject.go
71+
│   └── zz_generated.kubebuilder.go
72+
└── vendor
73+
74+
```
75+
- v1 project
76+
```
77+
├── cmd
78+
│   └── manager
79+
│   └── main.go
80+
├── config
81+
│   ├── crds
82+
│   │   └── apps_v1_hello.yaml
83+
│   └── manager
84+
│   ├── apps_rolebinding_rbac.yaml
85+
│   ├── apps_role_rbac.yaml
86+
│   └── manager.yaml
87+
├── Dockerfile
88+
├── Gopkg.toml
89+
├── hack
90+
│   └── boilerplate.go.txt
91+
├── Makefile
92+
├── pkg
93+
│   ├── apis
94+
│   │   ├── addtoscheme_apps_v1.go
95+
│   │   ├── apis.go
96+
│   │   └── apps
97+
│   │   ├── group.go
98+
│   │   └── v1
99+
│   │   ├── doc.go
100+
│   │   ├── hello_types.go
101+
│   │   ├── hello_types_test.go
102+
│   │   ├── register.go
103+
│   │   └── v1_suite_test.go
104+
│   └── controller
105+
│   ├── add_hello.go
106+
│   ├── controller.go
107+
│   └── hello
108+
│   ├── hello_controller.go
109+
│   ├── hello_controller_suite_test.go
110+
│   └── hello_controller_test.go
111+
├── PROJECT
112+
└── vendor
113+
```
114+
Compared with v0 project, there is no `client`, `inject` folders.
115+
116+
## library difference
117+
118+
- v0 projects import the libraries from kubebuilder, for example kubebuilder/pkg/controller. It provides a `GenericController` type with a list of functions. Note that for created resources, the corresponding client library is generated under the project folder `pkg/client`
119+
120+
- v1 projects import the libraries from controller-runtime, for example controller-runtime/pkg/controller, controller-runtime/pkg/client, controller-runtime/pkg/reconcile. Note that for created resources or core types, the client library is provided by controller-runtime.
121+
122+
## wiring difference
123+
- v0 projects has a `inject` package and it provides functions for adding the controller to controller-manager as well as registering CRDs.
124+
- v1 projects doesn't have a `inject` package, the controller is added to controller-manager by a `init` function inside add_<type>.go file inside the controller directory. The types is registered by a `init` function inside <type>_types.go file inside the apis directory.

docs/migration_guide.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Migration guide from v0 project to v1 project
2+
3+
4+
This document describes how to migrate a project created by kubebuilder v0 to a project created by kubebuilder v1. Before jumping into the detailed instructions, please take a look at the list of [major differences between kubebuilder v0 and kubebuilder v1](kubebuilder_v0_v1_difference.md).
5+
6+
The recommended way of migrating a v0 project to a v1 project is to create a new v1 project and copy/modify the code from v0 project to it.
7+
8+
## Init a v1 project
9+
Find project's domain name from the old project's pkg/apis/doc.go and use it to initiate a new project with
10+
`kubebuilder init --project-version v1 --domain <domain>`
11+
12+
## Create api
13+
Find the group/version/kind names from the project's pkg/apis. The group and version names are directory names while the kind name can be found from *_types.go. Note that the kind name should be capitalized.
14+
15+
Create api in the new project with
16+
`kubebuilder create api --group <group> --version <version> --kind <kind>`
17+
18+
If there are several resources in the old project, repeat the `kubebuilder create api` command to create all of them.
19+
20+
## Copy types.go
21+
Copy the content of <type>_types.go from the old project into the file <type>_types.go in the new project.
22+
Note that in the v1 project, there is a section containing `<type>List` and `init` function. Please keep this section.
23+
```
24+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
25+
// +genclient:nonNamespaced
26+
27+
// HelloList contains a list of Hello
28+
type HelloList struct {
29+
metav1.TypeMeta `json:",inline"`
30+
metav1.ListMeta `json:"metadata,omitempty"`
31+
Items []Hello `json:"items"`
32+
}
33+
34+
func init() {
35+
SchemeBuilder.Register(&Hello{}, &HelloList{})
36+
}
37+
```
38+
39+
## Copy and modify controller code
40+
41+
### copy and update reconcile function
42+
Note that in v0 and v1 projects, the `Reconcile`
43+
functions have different arguments and return types.
44+
45+
- `Reconcile` function in v0 project: `func (bc *<kind>Controller) Reconcile(k types.ReconcileKey) error`
46+
47+
- `Reconcile` function in v1 project: `func (r *Reconcile<kind>) Reconcile(request reconcile.Request) (reconcile.Result, error)`
48+
49+
Remove the original body of `Reconcile` function inside the v1 project and copy the body of the `Reconcile` function from the v0 project to the v1 project. Then apply following changes:
50+
- add `reconcile.Result{}` as the first value in every `return` statement
51+
- change the call of client functions such as `Get`, `Create`, `Update`. In v0 projects, the call of client functions has the format like `bc.<kind>Lister.<kind>().Get()` or `bc.KubernetesClientSet.<group>.<version>.<Kind>.Get()`. They can be replaced by `r.Client` functions. Here are several examples of updating the client function from v0 project to v1 project.
52+
```
53+
# in v0 project
54+
mc, err := bc.memcachedLister.Memcacheds(k.Namespace).Get(k.Name)
55+
# in v1 project, change to
56+
mc := &myappsv1alpha1.Memcached{}
57+
err := r.Client.Get(context.TODO(), request.NamespacedName, mc)
58+
59+
60+
# in v0 project
61+
dp, err := bc.KubernetesInformers.Apps().V1().Deployments().Lister().Deployments(mc.Namespace).Get(mc.Name)
62+
# in v1 project, change to
63+
dp := &appsv1.Deployment{}
64+
err := r.Client.Get(context.TODO(), request.NamespacedName, dp)
65+
66+
67+
dep := &appsv1.Deployment{...}
68+
# in v0 project
69+
dp, err := bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Create(dep)
70+
# in v1 project, change to
71+
err := r.Client.Create(context.TODO(), dep)
72+
73+
74+
dep := &appsv1.Deployment{...}
75+
# in v0 project
76+
dp, err = bc.KubernetesClientSet.AppsV1().Deployments(mc.Namespace).Update(deploymentForMemcached(mc))
77+
# in v1 project, change to
78+
err := r.Client.Update(context.TODO(), dep)
79+
80+
81+
labelSelector := labels.SelectorFrom{...}
82+
# in v0 project
83+
pods, err := bc.KubernetesInformers.Core().V1().Pods().Lister().Pods(mc.Namespace).List(labelSelector)
84+
# in v1 project, change to
85+
pods := &v1.PodList{}
86+
err = r.Client.List(context.TODO(), &client.ListOptions{LabelSelector: labelSelector}, pods)
87+
```
88+
- add library imports used in the v0 project to v1 project such as log, fmt or k8s libraries. Note that libraries from kubebuilder or from the old project's client package shouldn't be added.
89+
90+
91+
### update add function
92+
In v0 project controller file, there is a `ProvideController` function creating a controller and adding some watches. In v1 project, the corresponding function is `add`. For this part, you don't need to copy any code from v0 project to v1 project. You need to add some watchers in v1 project's `add` function based on what `watch` functions are called in v0 project's `ProvideController` function.
93+
94+
Here are several examples
95+
96+
```
97+
gc := &controller.GenericController{...}
98+
gc.Watch(&myappsv1alpha1.Memcached{})
99+
gc.WatchControllerOf(&v1.Pod{}, eventhandlers.Path{bc.LookupRS, bc.LookupDeployment, bc.LookupMemcached})
100+
```
101+
need to be changed to
102+
```
103+
c, err := controller.New{...}
104+
c.Watch(&source.Kind{Type: &myappsv1alpha1.Memcached{}}, &handler.EnqueueRequestForObject{})
105+
c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
106+
IsController: true,
107+
OwnerType: &myappsv1alpha1.Memcached{},
108+
})
109+
```
110+
111+
### copy other functions
112+
If `reconcile` function depends on some other user defined functions, copy those function as well into the v1 project
113+
114+
## Copy user libraries
115+
If there are some user defined libraries in the old project, make sure to copy them as well into the new project.
116+
117+
## Update dependency
118+
Open the Gopkg.toml file in the old project and find if there is user defined dependency in this block
119+
```
120+
# Users add deps lines here
121+
122+
[prune]
123+
go-tests = true
124+
#unused-packages = true
125+
126+
# Note: Stanzas below are generated by Kubebuilder and may be rewritten when
127+
# upgrading kubebuilder versions.
128+
129+
# DO NOT MODIFY BELOW THIS LINE.
130+
```
131+
Copy those dependencies into the new project's Gopkg.toml file **before** the line
132+
```
133+
# STANZAS BELOW ARE GENERATED AND MAY BE WRITTEN - DO NOT MODIFY BELOW THIS LINE.
134+
```
135+
136+
## Copy other user files
137+
If there are other user created files in the old project, such as any build scripts, REAMDE.md files. Copy those files into the new project.
138+
139+
## Confirmation
140+
Run `make` to make sure the new project can build and pass all the tests.
141+
Run `make install` and `make run` to make sure the api and controller work well on cluster.

0 commit comments

Comments
 (0)