Custom resources definition

Creating a Custom Resources Definition (CRD) object includes two steps: CRD registration and object creation. 

Let's create a CRD configuration first:

# cat chapter5/5-4_crd/5-4-1_crd.yaml
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: books.devops.kubernetes.com
spec:
group: devops.kubernetes.com
version: v1alpha1
scope: Namespaced
names:
plural: books
singular: book
kind: Book
shortNames:
- bk
validation:
openAPIV3Schema:
required: ["spec"]
properties:
spec:
required: ["name", "edition"]
properties:
name:
type: string
minimum: 50
edition:
type: string
minimum: 10
chapter:
type: integer
minimum: 1
maximum: 2

With CustomResourceDefinition, we can define our own spec for the custom object. First, we'll have to decide on the name of the CRD. The naming convention for a CRD must be spec.names.plural+"."+spec.group. Next, we'll define the group, version, scope, and names. The scope is either Namespaced or Cluster (non-namespaced). After Kubernetes 1.13, we can add a validation section to validate the custom objects via the OpenAPI v3 schema (https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject). We can define the required fields, as well as the spec and validation condition for each field. In the preceding example, we created a custom object named books.devops.kubernetes.com that has three properties: name, edition, and chapter. name and edition are required during object creation. Let's create the CRD via the kubectl command. We can also list all the CRDs via the kubectl get crd command:

# kubectl create -f chapter5/5-4_crd/5-4-1_crd.yaml
customresourcedefinition.apiextensions.k8s.io/books.devops.kubernetes.com created

# kubectl get crd
NAME CREATED AT
backendconfigs.cloud.google.com 2018-12-22T20:48:00Z
books.devops.kubernetes.com 2018-12-28T16:14:34Z
scalingpolicies.scalingpolicy.kope.io 2018-12-22T20:48:30Z

Next, we'll create an object accordingly. In spec, name, and edition are required. The apiVersion will be the <group>/<version> we defined in the preceding CRD configuration:

# cat chapter5/5-4_crd/5-4-2_objectcreation.yaml
apiVersion: devops.kubernetes.com/v1alpha1
kind: Book
metadata:
name: book-object
spec:
name: DevOps-with-Kubernetes
edition: second

# kubectl create -f chapter5/5-4_crd/5-4-2_objectcreation.yaml
book.devops.kubernetes.com/book-object created

If we set the edition to second, an error will be thrown, as follows:

spec.edition in body must be of type string: "integer"
spec.edition in body should be greater than or equal to 10

Now, we should be able to get and describe it, just like a normal API object:

# kubectl get books
NAME AGE
book-object 3s

# kubectl describe books book-object
Name: book-object
Namespace: default
Labels: <none>
Annotations: <none>
API Version: devops.kubernetes.com/v1alpha1
Kind: Book
Metadata:
/apis/devops.kubernetes.com/v1alpha1/namespaces/default/books/book-object
UID: c6912ab5-0abd-11e9-be06-42010a8a0078
Spec:
Edition: second
Name: DevOps-with-Kubernetes
Events: <none>

After registering a CRD, a custom controller might be needed to handle custom object operations. The custom controller requires additional programming effort. There are also multiple tools available in the community that can help us create a skeleton controller, such as the following:

With the sample controller (provided by Kubernetes), a set of ResourceEventHandlerFuncs will be added into EventHandler for handling object life cycle events, such as AddFunc for UpdateFunc and DeleteFunc

Both Kubebuilder and Operator can simplify the preceding steps. Kubebuilder provides support for building APIs via CRDs, controllers, and admission webhooks. Operator, which was introduced by CoreOS, is an application-specific controller that's implemented with CRD. There are existing operators being implemented by the community, and they can be found at https://github.com/operator-framework/awesome-operators. We'll introduce how to leverage the operator SDK in the Operator framework to build a simple controller with the same book CRD.

First, we'll have to install the operator SDK (https://github.com/operator-framework/operator-sdk). We are using v.0.3.0 in the following example:

// Check the prerequisites at https://github.com/operator-framework/operator-sdk#prerequisites
# mkdir -p $GOPATH/src/github.com/operator-framework # cd $GOPATH/src/github.com/operator-framework # git clone https://github.com/operator-framework/operator-sdk # cd operator-sdk # git checkout master # make dep # make install

// check version
# operator-sdk --version
# operator-sdk version v0.3.0+git

Let's create a new operator named devops-operator via the following command:

// operator-sdk new <operator_name>
# operator-sdk new devops-operator
INFO[0076] Run git init done
INFO[0076] Project creation complete.

After the operator is initialized, we can start adding components to it. Let's add api to create an API object and controller to handle object operations:

// operator-sdk add api --api-version <group>/<version> --kind <kind>
# operator-sdk add api --api-version devops.kubernetes.com/v1alpha1 --kind Book
INFO[0000] Generating api version devops.kubernetes.com/v1alpha1 for kind Book.
INFO[0000] Create pkg/apis/devops/v1alpha1/book_types.go
INFO[0000] Create pkg/apis/addtoscheme_devops_v1alpha1.go
INFO[0000] Create pkg/apis/devops/v1alpha1/register.go
INFO[0000] Create pkg/apis/devops/v1alpha1/doc.go
INFO[0000] Create deploy/crds/devops_v1alpha1_book_cr.yaml
INFO[0000] Create deploy/crds/devops_v1alpha1_book_crd.yaml
INFO[0008] Running code-generation for Custom Resource group versions: [devops:[v1alpha1], ]
INFO[0009] Code-generation complete.
INFO[0009] Api generation complete.

# operator-sdk add controller --api-version devops.kubernetes.com/v1alpha1 --kind Book
INFO[0000] Generating controller version devops.kubernetes.com/v1alpha1 for kind Book.
INFO[0000] Create pkg/controller/book/book_controller.go
INFO[0000] Create pkg/controller/add_book.go
INFO[0000] Controller generation complete.

There are multiple files we need to modify. The first one is API spec. In the previous CRD example, we added three custom properties in the book resource: name, edition, and chapter. We'll need to add that into spec here, too. This can be found under pkg/apis/devops/v1alpha1/book_types.go:

// in pkg/apis/devops/v1alpha1/book_types.go

type BookSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "operator-sdk generate k8s" to regenerate code after modifying this file
Name string `json:"name"`
Edition string `json:"edition"`
Chapter int32 `json:"chapter"`
}

Run operator-sdk generate k8s after modifying the file, as shown in the preceding code. Next, we will add some custom logic to the controller logic. This is located in the Reconcile function in pkg/controller/book/book_controller.go.

In the existing example that was created by the framework, the controller will receive a podSpec. This is exactly what we need, and we'll just get the name and edition from the Spec and print it out in busybox stdout:

// in pkg/controller/book/book_controller.go
func newPodForCR(cr *devopsv1alpha1.Book) *corev1.Pod {
labels := map[string]string{
"app": cr.Name,
}
name := cr.Spec.Name
edition := cr.Spec.Edition
return &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: cr.Name + "-pod",
Namespace: cr.Namespace,
Labels: labels,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "busybox",
Image: "busybox",
Command: []string{"echo", "Please support", name, edition, "Edition :-) "},
Stdin: true,
},
},
},
}
}

Then, we can run operator-sdk build devopswithkubernetes/sample-operator to build the docker image and push it to a registry. Here, we'll just push it to our public docker hub, docker push devopswithkubernetes/sample-operator.

The operator is done! After that, we can start looking into how to deploy it. The deployment scripts are automatically created in the deploy folder. The file we need to change is operator.yaml, which specifies the operator container image. Find the image: REPLACE_IMAGE line in podSpec and update that so that it points into your registry (here, we'll point it to devopswithkubernetes/sample-operator). Now, it's good to deploy:

# kubectl create -f deploy/service_account.yaml
# kubectl create -f deploy/role.yaml
# kubectl create -f deploy/role_binding.yaml
# kubectl create -f deploy/crds/app_v1alpha1_appservice_crd.yaml
# kubectl create -f deploy/operator.yaml

Now, you should be able to see an operator pod when listing the pods:

# kubectl get po
NAME READY STATUS RESTARTS AGE
devops-operator-58476dbcdd-s5m5v 1/1 Running 0 41m

Now, let's create a Book resource. You could modify deploy/crds/devops_v1alpha1_book_cr.yaml in the current folder or reuse 5-4_crd/5-4-2_objectcreation.yaml from our repo:

# kubectl create -f deploy/crds/devops_v1alpha1_book_cr.yaml
book.devops.kubernetes.com/book-object created

Then, we should be able to see that another pod was created by the CRD, and we can also check its logs:

# kubectl get po
NAME READY STATUS RESTARTS AGE
book-object-pod 0/1 Completed 0 2s
devops-operator-58476dbcdd-s5m5v 1/1 Running 0 45m

# kubectl logs book-object-pod
Please support DevOps-with-Kubernetes second Edition :-)

Hurray! Everything looks fine. Here, we have demonstrated a very simple example. Of course, we could leverage this concept and evolve more sophisticated logic and handlers.

Application CRD:
A containerized application might contain multiple Kubernetes resources, such as deployments, services, ConfigMaps, secrets, as well as custom CRDs. An application CRD has been implemented at https://github.com/kubernetes-sigs/application, providing a bridge to make application metadata describable. It also has application level health checks so that users don't need to list all the resources after deployment and check whether the application has been deployed properly. Instead, they list the application CRD and check its status. 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset