“Kubernetes official Example: Deploying PHP message board Application using Redis” operatorized.

Source code repository: github.com/jxlwqq/gues…

precondition

  • Install Docker Desktop and start the built-in Kubernetes cluster
  • To sign up for a hub.docker.com account, you need to push locally built images to a public repository
  • Install operator SDK CLI:brew install operator-sdk
  • Install the Go:brew install go

Recommended versions of dependencies for this example:

  • Docker Desktop: > = 4.0.0
  • Kubernetes: > = 1.21.4
  • Operator – SDK: > = 1.11.0
  • Go: > = 1.17

JXLWQQ is the author’s ID, and the personal ID involved in the command line and code should be replaced by the reader’s own, including

  • --domain=
  • --repo=
  • //+kubebuilder:rbac:groups=
  • IMAGE_TAG_BASE ? =

Create a project

Use the Operator SDK CLI to create a project named GuestBook – Operator.

mkdir -p $HOME/projects/guestbook-operator
cd $HOME/projects/guestbook-operator
go env -w GOPROXY=https://goproxy.cn,direct
```shell

operator-sdk init \
--domain=jxlwqq.github.io \
--repo=github.com/jxlwqq/guestbook-operator \
--skip-go-version-check
Copy the code

Create apis and controllers

Use the Operator SDK CLI to create custom resource Definition (CRD) apis and controllers.

Run the following command to create an API with group app, version V1alpha1, and the species Guestbook:

operator-sdk create api \
--resource=true \
--controller=true \
--group=app \
--version=v1alpha1 \
--kind=Guestbook
Copy the code

Define apis for Guestbook Custom Resources (CR).

Modify the GO type definition in API /v1alpha1/ Guestbook_types. go to have the following spec and status

type GuestbookSpec struct {
	FrontendSize int32 `json:"frontendSize"`
	RedisFollowerSize int32 `json:"redisFollowerSize"`
}
Copy the code

Update generated code for resource types:

make generate
Copy the code

Run the following command to generate and update the CRD manifest:

make manifests
Copy the code

Implementation controller

Because the logic is complex and the code is too large to show it all here, see the Controllers directory for the complete operator code.

In this example, replace the generated controller file controllers/ Guestbook_controller.go with the following example implementation:

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */

package controllers

import (
	"context"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"

	"k8s.io/apimachinery/pkg/runtime"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/log"

	appv1alpha1 "github.com/jxlwqq/guestbook-operator/api/v1alpha1"
)

// GuestbookReconciler reconciles a Guestbook object
type GuestbookReconciler struct {
	client.Client
	Scheme *runtime.Scheme
}

//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks,verbs=get; list; watch; create; update; patch; delete
//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks/status,verbs=get; update; patch
//+kubebuilder:rbac:groups=app.jxlwqq.github.io,resources=guestbooks/finalizers,verbs=update
//+kubebuilder:rbac:groups=apps,resources=deployments,verbs=get; list; watch; create; update; patch; delete
//+kubebuilder:rbac:groups=core,resources=service,verbs=get; list; watch; create; update; patch; delete
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get; list; watch

// 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
// the Guestbook object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
/ / https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
	reqLogger := log.FromContext(ctx)
	reqLogger.Info("Reconciling Guestbook")

	guestbook := &appv1alpha1.Guestbook{}
	err := r.Client.Get(context.TODO(), req.NamespacedName, guestbook)
	iferr ! =nil {
		if errors.IsNotFound(err) {
			return ctrl.Result{}, nil
		}
		return ctrl.Result{}, err
	}

	var result = &ctrl.Result{}

	result, err = r.ensureDeployment(r.redisLeaderDeployment(guestbook))
	ifresult ! =nil {
		return *result, err
	}
	result, err = r.ensureService(r.redisLeaderService(guestbook))
	ifresult ! =nil {
		return *result, err
	}

	result, err = r.ensureDeployment(r.redisFollowerDeployment(guestbook))
	ifresult ! =nil {
		return *result, err
	}
	result, err = r.ensureService(r.redisFollowerService(guestbook))
	ifresult ! =nil {
		return *result, err
	}
	result, err = r.handleRedisFollowerChanges(guestbook)
	ifresult ! =nil {
		return *result, err
	}

	result, err = r.ensureDeployment(r.frontendDeployment(guestbook))
	ifresult ! =nil {
		return *result, err
	}
	result, err = r.ensureService(r.frontendService(guestbook))
	ifresult ! =nil {
		return *result, err
	}
	result, err = r.handleFrontendChanges(guestbook)
	ifresult ! =nil {
		return *result, err
	}

	return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {
	return ctrl.NewControllerManagedBy(mgr).
		For(&appv1alpha1.Guestbook{}).
		Owns(&appsv1.Deployment{}).
		Owns(&corev1.Service{}).
		Complete(r)
}
Copy the code

Run the following command to generate and update the CRD manifest:

make manifests
Copy the code

Run the Operator

Bundle operators and deploy them in a cluster using Operator Lifecycle Manager (OLM).

Modify IMAGE_TAG_BASE and IMG in Makefile:

IMAGE_TAG_BASE ? = docker.io/jxlwqq/guestbook-operator IMG ? =$(IMAGE_TAG_BASE):latest
Copy the code

Build an image:

make docker-build
Copy the code

To push an image to the mirror repository:

make docker-push
Copy the code

After a successful visit: hub.docker.com/r/jxlwqq/gu…

Run the make bundle command to create the Operator bundle list and fill in the name, author, and other necessary information:

make bundle
Copy the code

Build the bundle image:

make bundle-build
Copy the code

Push bundle image:

make bundle-push
Copy the code

After a successful visit: hub.docker.com/r/jxlwqq/gu…

Deploy operators using Operator Lifecycle Manager:

#Switch to the local cluster
kubectl config use-context docker-desktop
#Install the olm
operator-sdk olm install
#Run Operator in a cluster using OLM integration in Operator SDKOperator - SDK run bundle docker. IO/JXLWQQ/guestbook - operator - bundle: v0.0.1Copy the code

Create a custom resource

Edit the sample Guestbook CR manifest on config/samples/ app_v1alpha1_GuestBook.yaml to include the following specifications:

apiVersion: app.jxlwqq.github.io/v1alpha1
kind: Guestbook
metadata:
  name: guestbook-sample
spec:
  # Add fields here
  frontendSize: 2
  redisFollowerSize: 2
Copy the code

Create a CR:

kubectl apply -f config/samples/app_v1alpha1_guestbook.yaml
Copy the code

Check the Pod:

NAME                              READY   STATUS    RESTARTS   AGE
frontend-85595f5bf9-jrcp4         1/1     Running   0          9s
frontend-85595f5bf9-q8fkl         1/1     Running   0          9s
redis-follower-76c5cc5b79-fxxlq   1/1     Running   0          9s
redis-follower-76c5cc5b79-g8vnf   1/1     Running   0          9s
redis-leader-6666df964-vjhp2      1/1     Running   0          9s
Copy the code

To view the Service:

NAME TYPE cluster-ip external-ip PORT(S) AGE frontend NodePort 10.106.145.169 < None > 80:30693/TCP 24s kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4m58s Redis-follower ClusterIP 10.108.30.112 < None > 6379/TCP 24s redis-leader ClusterIP 10.106.255.152 < None > 6379/TCP 24sCopy the code

Browser: http://localhost:30693

The Guestbook form page is displayed.

Update the CR:

#Example Modify the number of frontend and redis copies
kubectl patch guestbook guestbook-sample -p '{"spec":{"frontendSize": 3, "redisFollowerSize": 3}}' --type=merge
Copy the code

Check the Pod:

NAME                              READY   STATUS    RESTARTS   AGE
frontend-85595f5bf9-4pmfj         1/1     Running   0          4s
frontend-85595f5bf9-jrcp4         1/1     Running   0          50s
frontend-85595f5bf9-q8fkl         1/1     Running   0          50s
redis-follower-76c5cc5b79-bxbb4   1/1     Running   0          4s
redis-follower-76c5cc5b79-fxxlq   1/1     Running   0          50s
redis-follower-76c5cc5b79-g8vnf   1/1     Running   0          50s
redis-leader-6666df964-vjhp2      1/1     Running   0          50s
Copy the code

Do a good job in cleaning up

operator-sdk cleanup guestbook-operator
operator-sdk olm uninstall
Copy the code

More and more

For more classic examples: github.com/jxlwqq/kube…