Skip to content

Commit 5096b1c

Browse files
authored
📖 Update new provider docs to be more current (#12085)
* docs: make the mkdir and cd use the same directory Signed-off-by: cprivitere <[email protected]> * docs: document staging the generated files to the git commit Signed-off-by: cprivitere <[email protected]> * docs: remove status subresource section - created by default since kubebuilder 3.0 in 2020 Signed-off-by: cprivitere <[email protected]> * docs: add comments back and remove reference to deleted comments - referencing deleted comments is very confusing to understand Signed-off-by: cprivitere <[email protected]> * docs: update scaffold examples to current kubebuilder output Signed-off-by: cprivitere <[email protected]> * docs: point readers to where the files in question likely are Signed-off-by: cprivitere <[email protected]> * docs: replace Captain with Mailgun for consistency in example Signed-off-by: cprivitere <[email protected]> * docs: grammar and typo fix Signed-off-by: cprivitere <[email protected]> * docs: update examples to what you get from current kubebuilder version Signed-off-by: cprivitere <[email protected]> * docs: Improvements to consistency and functionality of example code - Consistently refer to cluster as mailgunCluster - Add that you need to import the cluster-api package to your project before you can use the util function - Use mailgunCluster.ObjectMeta instead of a pointer in GetOwnerCluster call - Add explanation that we need to wait for the Cluster API controller to set the ownerref before we can use the cluster object, update code to do that - Show entire Reconcile function again after adding many lines to it Signed-off-by: cprivitere <[email protected]> * docs: update reconciler initiation to be like current kubebuilder provided scaffold Signed-off-by: cprivitere <[email protected]> * docs: correct typo of credentials manifest filename Signed-off-by: cprivitere <[email protected]> * docs: update and simplify image name section - Provide directions that work with current kubebuilder output - Provide simpler example overriding of image name - Drop old no longer working example of image name patching - Providing a more current example of how providers actually do this would involve teaching about CI/CD setups which seems out of scope for this document Signed-off-by: cprivitere <[email protected]> * docs: update cluster-api deployment section - Old section didn't work anymore - replace it with a link to the quick start guide - Suggest/note that we assume the user will use kind and clusterctl init, which will install cert-manager automatically. - Update Condition status example to match what a kubectl describe currently shows Signed-off-by: cprivitere <[email protected]> * docs: update example of runing provider in a local kind cluster - Show how to load the image into kind - Use a tag that isn't latest so kubernetes won't try to pull it from docker hub - Update Conditions fields to current kubernetes output Signed-off-by: cprivitere <[email protected]> * docs: update tilt example - Tilt example wasn't functional as it was - Added go_main to point to where kubebuilder puts main.go - Use make tilt-up instead of trying to build your own kind cluster to proerly set up tilt to use the local registry config showin in the example tilt files Signed-off-by: cprivitere <[email protected]> * docs: remove unneeded ctx from example Signed-off-by: cprivitere <[email protected]> * docs: simplify getowner introduction Signed-off-by: cprivitere <[email protected]> --------- Signed-off-by: cprivitere <[email protected]>
1 parent 29fabbd commit 5096b1c

File tree

5 files changed

+127
-108
lines changed

5 files changed

+127
-108
lines changed

docs/book/src/developer/providers/getting-started/building-running-and-testing.md

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,20 @@
22

33
## Docker Image Name
44

5-
The patch in `config/manager/manager_image_patch.yaml` will be applied to the manager pod.
6-
Right now there is a placeholder `IMAGE_URL`, which you will need to change to your actual image.
7-
8-
### Development Images
9-
It's likely that you will want one location and tag for release development, and another during development.
10-
11-
The approach most Cluster API projects is using [a `Makefile` that uses `sed` to replace the image URL][sed] on demand during development.
12-
13-
[sed]: https://github.com/kubernetes-sigs/cluster-api/blob/e0fb83a839b2755b14fbefbe6f93db9a58c76952/Makefile#L201-L204
14-
15-
## Deployment
16-
17-
### cert-manager
18-
19-
Cluster API uses [cert-manager] to manage the certificates it needs for its webhooks.
20-
Before you apply Cluster API's yaml, you should [install `cert-manager`][cm-install]
21-
22-
[cert-manager]: https://github.com/cert-manager/cert-manager
23-
[cm-install]: https://cert-manager.io/docs/installation/
5+
The IMG variable is used to build the Docker image and push it to a registry. The default value is `controller:latest`, which is a local image. You can change it to a remote image if you want to push it to a registry.
246

257
```bash
26-
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/<version>/cert-manager.yaml
8+
make docker-push IMG=ghcr.io/your-org/your-repo:dev
279
```
2810

11+
## Deployment
12+
2913
### Cluster API
3014

3115
Before you can deploy the infrastructure controller, you'll need to deploy Cluster API itself to the management cluster.
3216

33-
You can use a precompiled manifest from the [release page][releases], run `clusterctl init`, or clone [`cluster-api`][capi] and apply its manifests using `kustomize`:
17+
Follow the [quick start guide](https://cluster-api.sigs.k8s.io/user/quick-start) up to and including the step of [creating the management cluster](https://cluster-api.sigs.k8s.io/user/quick-start#initialize-the-management-cluster). We will proceed presuming you created a cluster with kind and initalized cluster-api with `clusterctl init`.
3418

35-
```bash
36-
cd cluster-api
37-
make envsubst
38-
kustomize build config/default | ./hack/tools/bin/envsubst | kubectl apply -f -
39-
```
4019

4120
Check the status of the manager to make sure it's running properly:
4221

@@ -45,11 +24,11 @@ kubectl describe -n capi-system pod | grep -A 5 Conditions
4524
```
4625
```bash
4726
Conditions:
48-
Type Status
49-
Initialized True
50-
Ready True
51-
ContainersReady True
52-
PodScheduled True
27+
Type Status
28+
PodReadyToStartContainers True
29+
Initialized True
30+
Ready True
31+
ContainersReady True
5332
```
5433

5534
[capi]: https://github.com/kubernetes-sigs/cluster-api
@@ -66,24 +45,36 @@ labels:
6645
cluster.x-k8s.io/provider: infrastructure-mailgun
6746
```
6847
48+
If you're using kind for your management cluster, you can use the following command to build and push your image to the kind cluster's local registry. We need to use the IMG variable to override the default `controller:latest` image name with a specific version like `controller:0.1` to avoid having kubernetes try to pull the latest version of `controller` from docker hub.
49+
50+
```bash
51+
cd cluster-api-provider-mailgun
52+
53+
# Build the Docker image
54+
make docker-build IMG=controller:dev
55+
56+
# Load the Docker image into the kind cluster
57+
kind load docker-image controller:dev
58+
```
59+
6960
Now you can apply your provider as well:
7061

7162
```bash
7263
cd cluster-api-provider-mailgun
7364
7465
# Install CRD and controller to current kubectl context
75-
make install deploy
66+
make install deploy IMG=controller:dev
7667
7768
kubectl describe -n cluster-api-provider-mailgun-system pod | grep -A 5 Conditions
7869
```
7970

8071
```text
8172
Conditions:
82-
Type Status
83-
Initialized True
84-
Ready True
85-
ContainersReady True
86-
PodScheduled True
73+
Type Status
74+
PodReadyToStartContainers True
75+
Initialized True
76+
Ready True
77+
ContainersReady True
8778
```
8879

8980
[label_prefix]: https://github.com/kubernetes-sigs/cluster-api/search?q=%22infrastructure-%22
@@ -102,6 +93,7 @@ config:
10293
image: controller:latest # change to remote image name if desired
10394
label: CAPM
10495
live_reload_deps: ["main.go", "go.mod", "go.sum", "api", "controllers", "pkg"]
96+
go_main: cmd/main.go # kubebuilder puts main.go under the cmd directory
10597
```
10698

10799
- Create file `tilt-settings.yaml` in the cluster-api directory:
@@ -116,15 +108,11 @@ enable_providers:
116108
- mailgun
117109
```
118110
119-
- Create a kind cluster. By default, Tiltfile assumes the kind cluster is named `capi-test`.
111+
- Bring tilt up by using the `make tilt-up` command in the cluster-api directory. This will ensure tilt is set up correctly to use a local registry for your image. You may need to `make tilt-clean` before this if you've been using tilt with other providers.
120112

121113
```bash
122-
kind create cluster --name capi-test
123-
124-
# If you want a more sophisticated setup of kind cluster + image registry, try:
125-
# ---
126-
# cd cluster-api
127-
# hack/kind-install-for-capd.sh
114+
cd cluster-api
115+
make tilt-up
128116
```
129117

130118
- Run `tilt up` in the cluster-api folder

docs/book/src/developer/providers/getting-started/configure-the-deployment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ As you might have noticed, we are reading variable values from a `ConfigMap` and
5353
You now have to add those to the manifest, but how to inject configuration in production?
5454
The convention many Cluster-API projects use is environment variables.
5555

56-
`config/manager/configuration.yaml`
56+
`config/manager/credentials.yaml`
5757

5858
```yaml
5959
---

docs/book/src/developer/providers/getting-started/controllers-and-reconciliation.md

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Controllers and Reconciliation
22

3-
Right now, you can create objects with our API types, but those objects doesn't make any impact on your mailgun infrastrucrure.
3+
Right now, you can create objects with your API types, but those objects don't make any impact on your mailgun infrastructure.
44
Let's fix that by implementing controllers and reconciliation for your API objects.
55

66
From the [kubebuilder book][controller]:
@@ -25,17 +25,16 @@ Kubebuilder has created our first controller in `controllers/mailguncluster_cont
2525
// MailgunClusterReconciler reconciles a MailgunCluster object
2626
type MailgunClusterReconciler struct {
2727
client.Client
28-
Log logr.Logger
28+
Scheme *runtime.Scheme
2929
}
3030

3131
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=mailgunclusters,verbs=get;list;watch;create;update;patch;delete
3232
// +kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=mailgunclusters/status,verbs=get;update;patch
3333

3434
func (r *MailgunClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
35-
_ = context.Background()
36-
_ = r.Log.WithValues("mailguncluster", req.NamespacedName)
35+
_ = logf.FromContext(ctx)
3736

38-
// your logic here
37+
// TODO(user): your logic here
3938

4039
return ctrl.Result{}, nil
4140
}
@@ -88,7 +87,7 @@ We're going to be sending mail, so let's add a few extra fields:
8887
// MailgunClusterReconciler reconciles a MailgunCluster object
8988
type MailgunClusterReconciler struct {
9089
client.Client
91-
Log logr.Logger
90+
Scheme *runtime.Scheme
9291
Mailgun mailgun.Mailgun
9392
Recipient string
9493
}
@@ -102,7 +101,7 @@ Here's a naive example:
102101
```go
103102
func (r *MailgunClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
104103
ctx := context.Background()
105-
_ = r.Log.WithValues("mailguncluster", req.NamespacedName)
104+
_ = ctrl.LoggerFrom(ctx)
106105

107106
var cluster infrav1.MailgunCluster
108107
if err := r.Get(ctx, req.NamespacedName, &cluster); err != nil {
@@ -117,8 +116,8 @@ By returning an error, you request that our controller will get `Reconcile()` ca
117116
That may not always be what you want - what if the object's been deleted? So let's check that:
118117

119118
```go
120-
var cluster infrav1.MailgunCluster
121-
if err := r.Get(ctx, req.NamespacedName, &cluster); err != nil {
119+
var mailgunCluster infrav1.MailgunCluster
120+
if err := r.Get(ctx, req.NamespacedName, &mailgunCluster); err != nil {
122121
// import apierrors "k8s.io/apimachinery/pkg/api/errors"
123122
if apierrors.IsNotFound(err) {
124123
return ctrl.Result{}, nil
@@ -127,19 +126,57 @@ That may not always be what you want - what if the object's been deleted? So let
127126
}
128127
```
129128

130-
Now, if this were any old `kubebuilder` project you'd be done, but in our case you have one more object to retrieve.
131-
Cluster API splits a cluster into two objects: the [`Cluster` defined by Cluster API itself][cluster].
132-
We'll want to retrieve that as well.
129+
Now that we have our own cluster object (`MailGunCluster`) that represents all the
130+
infrastructure provider specific details for our cluster, we also need to retrieve
131+
the upstream [`Cluster` object that is defined by Cluster API itself][cluster].
133132
Luckily, cluster API [provides a helper for us][getowner].
134133

134+
First, you'll need to import the cluster-api package into our project if you haven't done so yet:
135+
136+
```bash
137+
# In your Mailgun repository's root directory
138+
go get sigs.k8s.io/cluster-api
139+
go mod tidy
140+
```
141+
142+
Now we can add in a call to the `GetOwnerCluster` function to retrieve the cluster object:
143+
135144
```go
136-
cluster, err := util.GetOwnerCluster(ctx, r.Client, &mg)
145+
// import sigs.k8s.io/cluster-api/util
146+
cluster, err := util.GetOwnerCluster(ctx, r.Client, mailgunCluster.ObjectMeta)
137147
if err != nil {
138148
return ctrl.Result{}, err
139-
140149
}
141150
```
142151

152+
If our cluster was just created, the Cluster API controller may not have set the ownership reference on our object yet, so we'll have to return here and wait to do more with our cluster object until then. We can leave a log message noting that we're waiting for the main Cluster API controller to set the ownership reference. Here's what our `Reconcile()` function looks like now:
153+
154+
```go
155+
func (r *MailgunClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
156+
// We change the _ to `log` since we're going to log something now
157+
log = ctrl.LoggerFrom(ctx)
158+
159+
var mailgunCluster infrav1.MailgunCluster
160+
if err := r.Get(ctx, req.NamespacedName, &mailgunCluster); err != nil {
161+
// import apierrors "k8s.io/apimachinery/pkg/api/errors"
162+
if apierrors.IsNotFound(err) {
163+
return ctrl.Result{}, nil
164+
}
165+
return ctrl.Result{}, err
166+
}
167+
168+
// import sigs.k8s.io/cluster-api/util
169+
cluster, err := util.GetOwnerCluster(ctx, r.Client, mailgunCluster.ObjectMeta)
170+
if err != nil {
171+
return ctrl.Result{}, err
172+
}
173+
174+
if cluster == nil {
175+
log.Info("Waiting for Cluster Controller to set OwnerRef on MailGunCluster")
176+
return ctrl.Result{}, nil
177+
}
178+
```
179+
143180
### The fun part
144181
145182
_More Documentation: [The Kubebuilder Book][book] has some excellent documentation on many things, including [how to write good controllers!][implement]_
@@ -152,10 +189,10 @@ This is where your provider really comes into its own.
152189
In our case, let's try sending some mail:
153190
154191
```go
155-
subject := fmt.Sprintf("[%s] New Cluster %s requested", mgCluster.Spec.Priority, cluster.Name)
156-
body := fmt.Sprint("Hello! One cluster please.\n\n%s\n", mgCluster.Spec.Request)
192+
subject := fmt.Sprintf("[%s] New Cluster %s requested", mailgunCluster.Spec.Priority, cluster.Name)
193+
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mailgunCluster.Spec.Request)
157194

158-
msg := mailgun.NewMessage(mgCluster.Spec.Requester, subject, body, r.Recipient)
195+
msg := r.mailgun.NewMessage(mailgunCluster.Spec.Requester, subject, body, r.Recipient)
159196
_, _, err = r.Mailgun.Send(msg)
160197
if err != nil {
161198
return ctrl.Result{}, err
@@ -172,28 +209,28 @@ This is an important thing about controllers: they need to be idempotent. This m
172209
So in our case, we'll store the result of sending a message, and then check to see if we've sent one before.
173210
174211
```go
175-
if mgCluster.Status.MessageID != nil {
212+
if mailgunCluster.Status.MessageID != nil {
176213
// We already sent a message, so skip reconciliation
177214
return ctrl.Result{}, nil
178215
}
179216

180-
subject := fmt.Sprintf("[%s] New Cluster %s requested", mgCluster.Spec.Priority, cluster.Name)
181-
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mgCluster.Spec.Request)
217+
subject := fmt.Sprintf("[%s] New Cluster %s requested", mailgunCluster.Spec.Priority, cluster.Name)
218+
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mailgunCluster.Spec.Request)
182219

183-
msg := mailgun.NewMessage(mgCluster.Spec.Requester, subject, body, r.Recipient)
220+
msg := r.Mailgun.NewMessage(mailgunCluster.Spec.Requester, subject, body, r.Recipient)
184221
_, msgID, err := r.Mailgun.Send(msg)
185222
if err != nil {
186223
return ctrl.Result{}, err
187224
}
188225

189226
// patch from sigs.k8s.io/cluster-api/util/patch
190-
helper, err := patch.NewHelper(&mgCluster, r.Client)
227+
helper, err := patch.NewHelper(&mailgunCluster, r.Client)
191228
if err != nil {
192229
return ctrl.Result{}, err
193230
}
194-
mgCluster.Status.MessageID = &msgID
195-
if err := helper.Patch(ctx, &mgCluster); err != nil {
196-
return ctrl.Result{}, errors.Wrapf(err, "couldn't patch cluster %q", mgCluster.Name)
231+
mailgunCluster.Status.MessageID = &msgID
232+
if err := helper.Patch(ctx, &mailgunCluster); err != nil {
233+
return ctrl.Result{}, errors.Wrapf(err, "couldn't patch cluster %q", mailgunCluster.Name)
197234
}
198235

199236
return ctrl.Result{}, nil
@@ -223,7 +260,7 @@ Right now, it probably looks like this:
223260
```go
224261
if err = (&controllers.MailgunClusterReconciler{
225262
Client: mgr.GetClient(),
226-
Log: ctrl.Log.WithName("controllers").WithName("MailgunCluster"),
263+
Scheme: mgr.GetScheme(),
227264
}).SetupWithManager(mgr); err != nil {
228265
setupLog.Error(err, "Unable to create controller", "controller", "MailgunCluster")
229266
os.Exit(1)
@@ -256,7 +293,7 @@ We're going to use environment variables for this:
256293

257294
if err = (&controllers.MailgunClusterReconciler{
258295
Client: mgr.GetClient(),
259-
Log: ctrl.Log.WithName("controllers").WithName("MailgunCluster"),
296+
Scheme: mgr.GetScheme(),
260297
Mailgun: mg,
261298
Recipient: recipient,
262299
}).SetupWithManager(mgr); err != nil {

0 commit comments

Comments
 (0)