Skip to content

Commit b7b009d

Browse files
📖 Improve and Simplify the Getting Started Guide (#4094)
Improve and Simplify the Getting Started Guide - Refined the sample code implementation to keep it minimal, helping users better understand the core concepts. - Streamlined the guide by focusing on the main information and removing extraneous details. - Ensured that the code and samples in the guide are consistent with the generated project. - Simplified navigation by hiding the full code, making it easier for users to follow along. - Replaced the use of the deploy image plugin with direct commands to provide more comprehensive and straightforward information.
1 parent 1dd866a commit b7b009d

File tree

10 files changed

+679
-633
lines changed

10 files changed

+679
-633
lines changed

docs/book/src/getting-started.md

Lines changed: 220 additions & 339 deletions
Large diffs are not rendered by default.

docs/book/src/getting-started/testdata/project/PROJECT

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,6 @@
55
domain: example.com
66
layout:
77
- go.kubebuilder.io/v4
8-
plugins:
9-
deploy-image.go.kubebuilder.io/v1-alpha:
10-
resources:
11-
- domain: example.com
12-
group: cache
13-
kind: Memcached
14-
options:
15-
containerCommand: memcached,-m=64,-o,modern,-v
16-
containerPort: "11211"
17-
image: memcached:1.4.36-alpine
18-
runAsUser: "1001"
19-
version: v1alpha1
208
projectName: project
219
repo: example.com/memcached
2210
resources:

docs/book/src/getting-started/testdata/project/api/v1alpha1/memcached_types.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16+
// +kubebuilder:docs-gen:collapse=Apache License
1617

1718
package v1alpha1
1819

@@ -23,6 +24,8 @@ import (
2324
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
2425
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
2526

27+
// +kubebuilder:docs-gen:collapse=Imports
28+
2629
// MemcachedSpec defines the desired state of Memcached
2730
type MemcachedSpec struct {
2831
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
@@ -35,9 +38,6 @@ type MemcachedSpec struct {
3538
// +kubebuilder:validation:Maximum=3
3639
// +kubebuilder:validation:ExclusiveMaximum=false
3740
Size int32 `json:"size,omitempty"`
38-
39-
// Port defines the port that will be used to init the container with the image
40-
ContainerPort int32 `json:"containerPort,omitempty"`
4141
}
4242

4343
// MemcachedStatus defines the observed state of Memcached

docs/book/src/getting-started/testdata/project/cmd/main.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,8 @@ func main() {
145145
}
146146

147147
if err = (&controller.MemcachedReconciler{
148-
Client: mgr.GetClient(),
149-
Scheme: mgr.GetScheme(),
150-
Recorder: mgr.GetEventRecorderFor("memcached-controller"),
148+
Client: mgr.GetClient(),
149+
Scheme: mgr.GetScheme(),
151150
}).SetupWithManager(mgr); err != nil {
152151
setupLog.Error(err, "unable to create controller", "controller", "Memcached")
153152
os.Exit(1)

docs/book/src/getting-started/testdata/project/config/crd/bases/cache.example.com_memcacheds.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ spec:
3939
spec:
4040
description: MemcachedSpec defines the desired state of Memcached
4141
properties:
42-
containerPort:
43-
description: Port defines the port that will be used to init the container
44-
with the image
45-
format: int32
46-
type: integer
4742
size:
4843
description: |-
4944
Size defines the number of Memcached instances

docs/book/src/getting-started/testdata/project/config/manager/manager.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ spec:
6565
- --health-probe-bind-address=:8081
6666
image: controller:latest
6767
name: manager
68-
env:
69-
- name: MEMCACHED_IMAGE
70-
value: memcached:1.4.36-alpine
7168
securityContext:
7269
allowPrivilegeEscalation: false
7370
capabilities:

docs/book/src/getting-started/testdata/project/config/samples/cache_v1alpha1_memcached.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,3 @@ spec:
99
# TODO(user): edit the following value to ensure the number
1010
# of Pods/Instances your Operand must have on cluster
1111
size: 1
12-
13-
# TODO(user): edit the following value to ensure the container has the right port to be initialized
14-
containerPort: 11211

docs/book/src/getting-started/testdata/project/internal/controller/memcached_controller.go

Lines changed: 16 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,22 @@ package controller
1919
import (
2020
"context"
2121
"fmt"
22-
"os"
23-
"strings"
24-
"time"
25-
2622
appsv1 "k8s.io/api/apps/v1"
2723
corev1 "k8s.io/api/core/v1"
2824
apierrors "k8s.io/apimachinery/pkg/api/errors"
2925
"k8s.io/apimachinery/pkg/api/meta"
3026
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31-
"k8s.io/apimachinery/pkg/runtime"
3227
"k8s.io/apimachinery/pkg/types"
33-
"k8s.io/client-go/tools/record"
28+
"time"
29+
30+
"k8s.io/apimachinery/pkg/runtime"
3431
ctrl "sigs.k8s.io/controller-runtime"
3532
"sigs.k8s.io/controller-runtime/pkg/client"
36-
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3733
"sigs.k8s.io/controller-runtime/pkg/log"
3834

3935
cachev1alpha1 "example.com/memcached/api/v1alpha1"
4036
)
4137

42-
const memcachedFinalizer = "cache.example.com/finalizer"
43-
4438
// Definitions to manage status conditions
4539
const (
4640
// typeAvailableMemcached represents the status of the Deployment reconciliation
@@ -52,14 +46,9 @@ const (
5246
// MemcachedReconciler reconciles a Memcached object
5347
type MemcachedReconciler struct {
5448
client.Client
55-
Scheme *runtime.Scheme
56-
Recorder record.EventRecorder
49+
Scheme *runtime.Scheme
5750
}
5851

59-
// The following markers are used to generate the rules permissions (RBAC) on config/rbac using controller-gen
60-
// when the command <make manifests> is executed.
61-
// To know more about markers see: https://book.kubebuilder.io/reference/markers.html
62-
6352
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds,verbs=get;list;watch;create;update;patch;delete
6453
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/status,verbs=get;update;patch
6554
// +kubebuilder:rbac:groups=cache.example.com,resources=memcacheds/finalizers,verbs=update
@@ -77,6 +66,8 @@ type MemcachedReconciler struct {
7766
// For further info:
7867
// - About Operator Pattern: https://kubernetes.io/docs/concepts/extend-kubernetes/operator/
7968
// - About Controllers: https://kubernetes.io/docs/concepts/architecture/controller/
69+
//
70+
// For more details, check Reconcile and its Result here:
8071
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile
8172
func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
8273
log := log.FromContext(ctx)
@@ -117,79 +108,6 @@ func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
117108
}
118109
}
119110

120-
// Let's add a finalizer. Then, we can define some operations which should
121-
// occur before the custom resource is deleted.
122-
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/finalizers
123-
if !controllerutil.ContainsFinalizer(memcached, memcachedFinalizer) {
124-
log.Info("Adding Finalizer for Memcached")
125-
if ok := controllerutil.AddFinalizer(memcached, memcachedFinalizer); !ok {
126-
log.Error(err, "Failed to add finalizer into the custom resource")
127-
return ctrl.Result{Requeue: true}, nil
128-
}
129-
130-
if err = r.Update(ctx, memcached); err != nil {
131-
log.Error(err, "Failed to update custom resource to add finalizer")
132-
return ctrl.Result{}, err
133-
}
134-
}
135-
136-
// Check if the Memcached instance is marked to be deleted, which is
137-
// indicated by the deletion timestamp being set.
138-
isMemcachedMarkedToBeDeleted := memcached.GetDeletionTimestamp() != nil
139-
if isMemcachedMarkedToBeDeleted {
140-
if controllerutil.ContainsFinalizer(memcached, memcachedFinalizer) {
141-
log.Info("Performing Finalizer Operations for Memcached before delete CR")
142-
143-
// Let's add here a status "Downgrade" to reflect that this resource began its process to be terminated.
144-
meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeDegradedMemcached,
145-
Status: metav1.ConditionUnknown, Reason: "Finalizing",
146-
Message: fmt.Sprintf("Performing finalizer operations for the custom resource: %s ", memcached.Name)})
147-
148-
if err := r.Status().Update(ctx, memcached); err != nil {
149-
log.Error(err, "Failed to update Memcached status")
150-
return ctrl.Result{}, err
151-
}
152-
153-
// Perform all operations required before removing the finalizer and allow
154-
// the Kubernetes API to remove the custom resource.
155-
r.doFinalizerOperationsForMemcached(memcached)
156-
157-
// TODO(user): If you add operations to the doFinalizerOperationsForMemcached method
158-
// then you need to ensure that all worked fine before deleting and updating the Downgrade status
159-
// otherwise, you should requeue here.
160-
161-
// Re-fetch the memcached Custom Resource before updating the status
162-
// so that we have the latest state of the resource on the cluster and we will avoid
163-
// raising the error "the object has been modified, please apply
164-
// your changes to the latest version and try again" which would re-trigger the reconciliation
165-
if err := r.Get(ctx, req.NamespacedName, memcached); err != nil {
166-
log.Error(err, "Failed to re-fetch memcached")
167-
return ctrl.Result{}, err
168-
}
169-
170-
meta.SetStatusCondition(&memcached.Status.Conditions, metav1.Condition{Type: typeDegradedMemcached,
171-
Status: metav1.ConditionTrue, Reason: "Finalizing",
172-
Message: fmt.Sprintf("Finalizer operations for custom resource %s name were successfully accomplished", memcached.Name)})
173-
174-
if err := r.Status().Update(ctx, memcached); err != nil {
175-
log.Error(err, "Failed to update Memcached status")
176-
return ctrl.Result{}, err
177-
}
178-
179-
log.Info("Removing Finalizer for Memcached after successfully perform the operations")
180-
if ok := controllerutil.RemoveFinalizer(memcached, memcachedFinalizer); !ok {
181-
log.Error(err, "Failed to remove finalizer for Memcached")
182-
return ctrl.Result{Requeue: true}, nil
183-
}
184-
185-
if err := r.Update(ctx, memcached); err != nil {
186-
log.Error(err, "Failed to remove finalizer for Memcached")
187-
return ctrl.Result{}, err
188-
}
189-
}
190-
return ctrl.Result{}, nil
191-
}
192-
193111
// Check if the deployment already exists, if not create a new one
194112
found := &appsv1.Deployment{}
195113
err = r.Get(ctx, types.NamespacedName{Name: memcached.Name, Namespace: memcached.Namespace}, found)
@@ -282,37 +200,19 @@ func (r *MemcachedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
282200
return ctrl.Result{}, nil
283201
}
284202

285-
// finalizeMemcached will perform the required operations before delete the CR.
286-
func (r *MemcachedReconciler) doFinalizerOperationsForMemcached(cr *cachev1alpha1.Memcached) {
287-
// TODO(user): Add the cleanup steps that the operator
288-
// needs to do before the CR can be deleted. Examples
289-
// of finalizers include performing backups and deleting
290-
// resources that are not owned by this CR, like a PVC.
291-
292-
// Note: It is not recommended to use finalizers with the purpose of deleting resources which are
293-
// created and managed in the reconciliation. These ones, such as the Deployment created on this reconcile,
294-
// are defined as dependent of the custom resource. See that we use the method ctrl.SetControllerReference.
295-
// to set the ownerRef which means that the Deployment will be deleted by the Kubernetes API.
296-
// More info: https://kubernetes.io/docs/tasks/administer-cluster/use-cascading-deletion/
297-
298-
// The following implementation will raise an event
299-
r.Recorder.Event(cr, "Warning", "Deleting",
300-
fmt.Sprintf("Custom Resource %s is being deleted from the namespace %s",
301-
cr.Name,
302-
cr.Namespace))
203+
// SetupWithManager sets up the controller with the Manager.
204+
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
205+
return ctrl.NewControllerManagedBy(mgr).
206+
For(&cachev1alpha1.Memcached{}).
207+
Owns(&appsv1.Deployment{}).
208+
Complete(r)
303209
}
304210

305211
// deploymentForMemcached returns a Memcached Deployment object
306212
func (r *MemcachedReconciler) deploymentForMemcached(
307213
memcached *cachev1alpha1.Memcached) (*appsv1.Deployment, error) {
308-
ls := labelsForMemcached()
309214
replicas := memcached.Spec.Size
310-
311-
// Get the Operand image
312-
image, err := imageForMemcached()
313-
if err != nil {
314-
return nil, err
315-
}
215+
image := "memcached:1.6.26-alpine3.19"
316216

317217
dep := &appsv1.Deployment{
318218
ObjectMeta: metav1.ObjectMeta{
@@ -322,46 +222,15 @@ func (r *MemcachedReconciler) deploymentForMemcached(
322222
Spec: appsv1.DeploymentSpec{
323223
Replicas: &replicas,
324224
Selector: &metav1.LabelSelector{
325-
MatchLabels: ls,
225+
MatchLabels: map[string]string{"app.kubernetes.io/name": "project"},
326226
},
327227
Template: corev1.PodTemplateSpec{
328228
ObjectMeta: metav1.ObjectMeta{
329-
Labels: ls,
229+
Labels: map[string]string{"app.kubernetes.io/name": "project"},
330230
},
331231
Spec: corev1.PodSpec{
332-
// TODO(user): Uncomment the following code to configure the nodeAffinity expression
333-
// according to the platforms which are supported by your solution. It is considered
334-
// best practice to support multiple architectures. build your manager image using the
335-
// makefile target docker-buildx. Also, you can use docker manifest inspect <image>
336-
// to check what are the platforms supported.
337-
// More info: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
338-
// Affinity: &corev1.Affinity{
339-
// NodeAffinity: &corev1.NodeAffinity{
340-
// RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
341-
// NodeSelectorTerms: []corev1.NodeSelectorTerm{
342-
// {
343-
// MatchExpressions: []corev1.NodeSelectorRequirement{
344-
// {
345-
// Key: "kubernetes.io/arch",
346-
// Operator: "In",
347-
// Values: []string{"amd64", "arm64", "ppc64le", "s390x"},
348-
// },
349-
// {
350-
// Key: "kubernetes.io/os",
351-
// Operator: "In",
352-
// Values: []string{"linux"},
353-
// },
354-
// },
355-
// },
356-
// },
357-
// },
358-
// },
359-
// },
360232
SecurityContext: &corev1.PodSecurityContext{
361233
RunAsNonRoot: &[]bool{true}[0],
362-
// IMPORTANT: seccomProfile was introduced with Kubernetes 1.19
363-
// If you are looking for to produce solutions to be supported
364-
// on lower versions you must remove this option.
365234
SeccompProfile: &corev1.SeccompProfile{
366235
Type: corev1.SeccompProfileTypeRuntimeDefault,
367236
},
@@ -383,7 +252,7 @@ func (r *MemcachedReconciler) deploymentForMemcached(
383252
},
384253
},
385254
Ports: []corev1.ContainerPort{{
386-
ContainerPort: memcached.Spec.ContainerPort,
255+
ContainerPort: 11211,
387256
Name: "memcached",
388257
}},
389258
Command: []string{"memcached", "-m=64", "-o", "modern", "-v"},
@@ -400,49 +269,3 @@ func (r *MemcachedReconciler) deploymentForMemcached(
400269
}
401270
return dep, nil
402271
}
403-
404-
// labelsForMemcached returns the labels for selecting the resources
405-
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/
406-
func labelsForMemcached() map[string]string {
407-
var imageTag string
408-
image, err := imageForMemcached()
409-
if err == nil {
410-
imageTag = strings.Split(image, ":")[1]
411-
}
412-
return map[string]string{"app.kubernetes.io/name": "project",
413-
"app.kubernetes.io/version": imageTag,
414-
"app.kubernetes.io/managed-by": "MemcachedController",
415-
}
416-
}
417-
418-
// imageForMemcached gets the Operand image which is managed by this controller
419-
// from the MEMCACHED_IMAGE environment variable defined in the config/manager/manager.yaml
420-
func imageForMemcached() (string, error) {
421-
var imageEnvVar = "MEMCACHED_IMAGE"
422-
image, found := os.LookupEnv(imageEnvVar)
423-
if !found {
424-
return "", fmt.Errorf("Unable to find %s environment variable with the image", imageEnvVar)
425-
}
426-
return image, nil
427-
}
428-
429-
// SetupWithManager sets up the controller with the Manager.
430-
// The whole idea is to be watching the resources that matter for the controller.
431-
// When a resource that the controller is interested in changes, the Watch triggers
432-
// the controller’s reconciliation loop, ensuring that the actual state of the resource
433-
// matches the desired state as defined in the controller’s logic.
434-
//
435-
// Notice how we configured the Manager to monitor events such as the creation, update,
436-
// or deletion of a Custom Resource (CR) of the Memcached kind, as well as any changes
437-
// to the Deployment that the controller manages and owns.
438-
func (r *MemcachedReconciler) SetupWithManager(mgr ctrl.Manager) error {
439-
return ctrl.NewControllerManagedBy(mgr).
440-
// Watch the Memcached CR(s) and trigger reconciliation whenever it
441-
// is created, updated, or deleted
442-
For(&cachev1alpha1.Memcached{}).
443-
// Watch the Deployment managed by the MemcachedReconciler. If any changes occur to the Deployment
444-
// owned and managed by this controller, it will trigger reconciliation, ensuring that the cluster
445-
// state aligns with the desired state. See that the ownerRef was set when the Deployment was created.
446-
Owns(&appsv1.Deployment{}).
447-
Complete(r)
448-
}

0 commit comments

Comments
 (0)