Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added code #1

Merged
merged 2 commits into from
Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 68 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ https://github.com/alexcpn/go_operator_2022/compare/master...generated-code

In this simple Operator we are going to read the CRD `testoperator/config/samples/grpcapp_v1_testoperartor.yaml` and create a deployment via code.

## Step 4.1
## Step 4.1: Adding custom fields to CRD yaml
For this the minimum is the Pod Image needed to create a deployment. We will add that to the above file

testoperator/config/samples/grpcapp_v1_testoperartor.yaml
Expand All @@ -79,7 +79,7 @@ spec:
podImage: alexcpn/run_server:1.2
```

## Step 4.2
## Step 4.2: Adding custom types for added fields to the Go code

Before we Apply this to the cluster we need to add the PodImage field to the controller types file `/testoperator/api/v1/testoperartor_types.go`
```
Expand All @@ -91,21 +91,64 @@ type TestoperartorSpec struct {
// Foo is an example field of Testoperartor. Edit testoperartor_types.go to remove/update
Foo string `json:"foo,omitempty"`

// Le's create a service with this operator
// Let's create a service with this operator
PodImage string `json:"podImage,omitempty"` //2 ADDED
}
```
Every time a new field is added, re-run the make file (Not in this folder, but in the child PROJECT folder, generated by Kubebuilder)
Every time a new field is added, re-run the make file

## Step 4.3
```
cd testoperator
make
```
(The Make file for Kubebuilder is in child PROJECT folder, generated by Kubebuilder)

## Step 4.3: Apply CRD to Cluster

With the above step we will be able to successfully deploy the Yaml to the cluster with first Make install - which will install all the needed CRD's and then applying our modified file

```
cd testoperator
make install
kubectl apply -f ./config/samples/grpcapp_v1_testoperartor.yaml
```
Ouput
```
kubectl get testoperartor
NAME AGE
testoperartor-sample 46s
kubectl get crds
NAME CREATED AT
testoperartors.grpcapp.mytest.io 2022-08-22T11:55:11Z
```
Note - There is a typo in operator name above; To keep the commits easy to follow I am not correcting it now.

## Step 4.4: Adding reconcile logic - here create a deployment with data in CRD

With the above step we will be able to successfully deploy the Yaml to the cluster with `make install`. But it will not be able to do anything
Add the controller logic in `testoperartor_controller.go`

## Step 4.4
We first Get the PodImage name from the deployed Kind (Step 4.2 & 4.3) and add the code to create a Deployment based on the retrieved Image name in the controller Reconcile loop

Add the controller logic
Since we are creating a deployment we need to add the following Imports

```
appsv1 "k8s.io/api/apps/v1" //ADDED
corev1 "k8s.io/api/core/v1" //ADDED
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" //ADDED
```

To instruct the Kubebuilder to add RBAC for this operation we add the following too in the Reconcile function comments

```
//ADDED extra for creating deployment
// generate rbac to get,list, and watch pods // 3 ADDED
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch
// generate rbac to get, list, watch, create, update, patch, and delete deployments
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
```

We first Get the Pod Image name from the deployed Kind (Step 4.3) and add the code to create a Deployment based on the retrieved Image name
Now add the logic; Basically first GET the STATE you want; that is in our case a deployment with a particular Pod Image name; and then in reconcile controller method add the logic to REACH that STATE. Basically in our case, create a deployment
Note - That particular Deployment code boilerplate was generated by GitHub AI Co-pilot

```
func (r *TestoperartorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
Expand Down Expand Up @@ -170,31 +213,18 @@ func (r *TestoperartorReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, nil
}
```
## Step 4.5 - Running the operartor in Place

To instruct the Kubebuilder to add RBAC for this operation we add the following too in the Reconcile function comments

```
// generate rbac to get,list, and watch pods // 3 ADDED
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch
// generate rbac to get, list, watch, create, update, patch, and delete deployments
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
```

Also we do the following Imports
Test if there are any code errors by 'make` by deploying to cluster via `make run`; which will run the controller in the terminal


```
appsv1 "k8s.io/api/apps/v1" //ADDED
corev1 "k8s.io/api/core/v1" //ADDED
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" //ADDED
```

## Step 4.5

Test it by deploying to cluster via `make run`

cd testoperator
make
make run
```

## Output

```
alex@pop-os:~/coding/app_fw/go_operator/testoperator$ make run
Expand Down Expand Up @@ -254,3 +284,13 @@ metadata:
selfLink: ""
```

## Step 4.5 -Create a Docker Image for the operator and installing it

As per the guideline here
https://book.kubebuilder.io/cronjob-tutorial/running.html

```
cd testoperator
make docker-build docker-push IMG=alexcpn/testoperator:1
make deploy alexcpn/testoperator:1
```
3 changes: 3 additions & 0 deletions testoperator/api/v1/testoperartor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type TestoperartorSpec struct {

// Foo is an example field of Testoperartor. Edit testoperartor_types.go to remove/update
Foo string `json:"foo,omitempty"`

// Let's create a service with this operator
PodImage string `json:"podImage,omitempty"` //2 ADDED
}

// TestoperartorStatus defines the observed state of Testoperartor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ spec:
description: Foo is an example field of Testoperartor. Edit testoperartor_types.go
to remove/update
type: string
podImage:
description: Let's create a service with this operator
type: string
type: object
status:
description: TestoperartorStatus defines the observed state of Testoperartor
Expand Down
62 changes: 62 additions & 0 deletions testoperator/controllers/testoperartor_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"

appsv1 "k8s.io/api/apps/v1" //ADDED
corev1 "k8s.io/api/core/v1" //ADDED
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" //ADDED
grpcappv1 "mytest.io/testoperator/api/v1"
)

Expand All @@ -37,6 +40,12 @@ type TestoperartorReconciler struct {
//+kubebuilder:rbac:groups=grpcapp.mytest.io,resources=testoperartors/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=grpcapp.mytest.io,resources=testoperartors/finalizers,verbs=update

//ADDED extra for creating deployment
// generate rbac to get,list, and watch pods
// +kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch
// generate rbac to get, list, watch, create, update, patch, and delete deployments
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
Expand All @@ -50,6 +59,59 @@ func (r *TestoperartorReconciler) Reconcile(ctx context.Context, req ctrl.Reques
_ = log.FromContext(ctx)

// TODO(user): your logic here
var testOperator grpcappv1.Testoperartor
if err := r.Get(ctx, req.NamespacedName, &testOperator); err != nil {
log.Log.Error(err, "unable to fetch Test Operator")
// we'll ignore not-found errors, since they can't be fixed by an immediate
// requeue (we'll need to wait for a new notification), and we can get them
// on deleted requests.
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// ADDED - Block below
log.Log.Info("Reconciling Test Operator", "Test Operator", testOperator)
log.FromContext(ctx).Info("Pod Image is ", "PodImageName", testOperator.Spec.PodImage)
// check if the PodImage is set
if testOperator.Spec.PodImage == "" {
log.Log.Info("Pod Image is not set")
} else {
log.Log.Info("Pod Image is set", "PodImageName", testOperator.Spec.PodImage)
}
//Lets create a deployment
one := int32(1)
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: testOperator.Name + "-deployment",
Namespace: testOperator.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &one,
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": testOperator.Name,
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": testOperator.Name,
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: testOperator.Name,
Image: testOperator.Spec.PodImage,
},
},
},
},
},
}
if err := r.Create(ctx, deployment); err != nil {
log.Log.Error(err, "unable to create Deployment", "Deployment.Namespace", deployment.Namespace, "Deployment.Name", deployment.Name)
return ctrl.Result{}, err
}
log.Log.Info("Created Deployment", "Deployment.Namespace", deployment.Namespace, "Deployment.Name", deployment.Name)

return ctrl.Result{}, nil
}
Expand Down