Skip to content

while1malloc0/cat-picture-operator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Cat Picture Operator

A tutorial for creating a new custom resource type called a CatPicture. This will be acted upon by an operator written with the operator framework.

Requirements

  • A Go development environment
  • A working Kubernetes cluster
  • The operator-sdk installed
  • A place to store container images

Build Steps

Build the cat serving app

# In the app directory
make build
docker build -t cat-operator-app:latest
# Substitute IMAGE_REPO for the image repo of your choice
docker push [IMAGE_REPO]/cat-operator-app:latest

Create the project scaffolding

operator-sdk new operator --api-version=cat.example.com/v1 --kind=CatPicture --skip-git-init

Define the spec for the CatPicture type

// operator/pkg/apis/cat/v1/types.go
type CatPictureSpec struct {
	// The number of containers to have running in the ReplicaSet
	Num int32 `json:"num,omitempty"`
}

Update the business logic for the Handler

Rename the stub package to cats by renaming the folder and replacing the reference in cats/handler.go. Make sure to rename the references in operator/cmd/operator/main.go

Remove the newBusyBox method. We'll want to create two things: a Service and a Deployment. Create the deployment first. We'll need import Deployments from the Kubernetes client-go library.

import (
    // ... a bunch of stuff
    appsv1 "k8s.io/api/apps/v1"
)
// operator/pkg/cats/handler.go

// catContainerImage is the name of the container image
const catContainerImage = "fill-in-your-location"

// newCatDeployment creates a new deployment of the cat picture service
func newCatDeployment(cr *v1.CatPicture) *appsv1.Deployment {
	return &appsv1.Deployment{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "apps/v1",
			Kind:       "Deployment",
		},

		ObjectMeta: metav1.ObjectMeta{
			Name:      "cat-deployment",
			Namespace: cr.Namespace,
		},

		Spec: appsv1.DeploymentSpec{
			Selector: &metav1.LabelSelector{
				MatchLabels: map[string]string{
					"app": "cat-pictures",
				},
			},
			Replicas: &cr.Spec.Num,
			Template: corev1.PodTemplateSpec{
				ObjectMeta: metav1.ObjectMeta{
					Labels: map[string]string{
						"app": "cat-pictures",
					},
				},
				Spec: corev1.PodSpec{
					Containers: []corev1.Container{
						{
							Name:  "cat-pictures",
							Image: catContainerImage,
							Ports: []corev1.ContainerPort{
								{
									HostPort:      8080,
									ContainerPort: 8080,
								},
							},
						},
					},
				},
			},
		},
	}
}

And then the service

// operator/pkg/cats/handler.go

// newCatService creates a new service for the cat application
func newCatService(cr *v1.CatPicture) *corev1.Service {
	return &corev1.Service{
		TypeMeta: metav1.TypeMeta{
			APIVersion: "v1",
			Kind:       "Service",
		},
		ObjectMeta: metav1.ObjectMeta{
			Labels: map[string]string{
				"service": "cats",
			},
			Namespace: cr.Namespace,
			Name:      "cat-pictures",
		},
		Spec: corev1.ServiceSpec{
			Type: "LoadBalancer",
			Selector: map[string]string{
				"app": "cat-pictures",
			},
			Ports: []corev1.ServicePort{
				{
					Name:       "http",
					Port:       80,
					TargetPort: intstr.IntOrString{IntVal: 8080},
					Protocol:   "TCP",
				},
			},
		},
	}
}

Plug the two creation functions into the handler

type Handler struct{}

func (h *Handler) Handle(ctx context.Context, event sdk.Event) error {
	switch o := event.Object.(type) {
	case *v1.CatPicture:
		if err := sdk.Create(newCatDeployment(o)); err != nil && !errors.IsAlreadyExists(err) {
			logrus.Errorf("Failed to create cat deployment : %v", err)
			return err
		}

		if err := sdk.Create(newCatService(o)); err != nil && !errors.IsAlreadyExists(err) {
			logrus.Errorf("Failed to create cat service : %v", err)
			return err
		}
	}

	return nil
}

Build the operator

# Replace IMAGE_REPO with what's being pushed to.
# For google container images, use gcr.io/[YOUR_PROJECT_ID]

# From within the operator folder
operator-sdk build [IMAGE_REPO]/cat-picture-operator

docker push [IMAGE_REPO]/cat-picture-operator:latest

Deploy the operator

kubectl apply -f ./operator/deploy/crd.yaml
# Optional, but recommended
kubectl apply -f ./operator/deploy/rbac.yaml
# This file is generated by the build step above
kubectl apply -f ./operator/deploy/operator.yaml

Deploy the example resource

kubectl apply -f ./operator/deploy/cr.yaml

Get some cat picture

Get the cat-pictures service and copy the ExternalIP

kubectl get svc

Copy the IP into your browser and enjoy the cats

About

A tutorial for the operator-sdk

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published