Exercise 6: Custom Resource Definitions (CRDs)

Task 1 - Understanding Custom Resource Definitions

  1. Custom Resource Definitions (CRDs) allow you to extend the Kubernetes API with your own custom resources.

  2. CRDs define:

    • The structure of your custom resource (schema)
    • The validation rules for the resource
    • How the resource is presented in the API
  3. Create a CRD manifest:

    $applicationCrd = @"
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: applications.workshop-example.io
    spec:
      group: workshop-example.io
      versions:
        - name: v1
          served: true
          storage: true
          schema:
            openAPIV3Schema:
              type: object
              properties:
                spec:
                  type: object
                  properties:
                    deploymentName:
                      type: string
                    replicas:
                      type: integer
                      minimum: 1
                      maximum: 10
                    image:
                      type: string
                    containerPort:
                      type: integer
                    resources:
                      type: object
                      properties:
                        memoryRequest:
                          type: string
                        cpuRequest:
                          type: string
                        memoryLimit:
                          type: string
                        cpuLimit:
                          type: string
                  required:
                    - deploymentName
                    - replicas
                    - image
      scope: Namespaced
      names:
        plural: applications
        singular: application
        kind: Application
        shortNames:
        - app
    "@
    
    # Output the CRD to review it
    $applicationCrd
    cat <<EOF > application-crd.yaml
    apiVersion: apiextensions.k8s.io/v1
    kind: CustomResourceDefinition
    metadata:
      name: applications.workshop-example.io
    spec:
      group: workshop-example.io
      versions:
        - name: v1
          served: true
          storage: true
          schema:
            openAPIV3Schema:
              type: object
              properties:
                spec:
                  type: object
                  properties:
                    deploymentName:
                      type: string
                    replicas:
                      type: integer
                      minimum: 1
                      maximum: 10
                    image:
                      type: string
                    containerPort:
                      type: integer
                    resources:
                      type: object
                      properties:
                        memoryRequest:
                          type: string
                        cpuRequest:
                          type: string
                        memoryLimit:
                          type: string
                        cpuLimit:
                          type: string
                  required:
                    - deploymentName
                    - replicas
                    - image
      scope: Namespaced
      names:
        plural: applications
        singular: application
        kind: Application
        shortNames:
        - app
    EOF
    
    # Output the CRD to review it
    cat application-crd.yaml

    This manifest defines an Application resource with properties like deploymentName, replicas, image, etc.

Task 2 - Create a Custom Resource Definition

  1. First, check if any previous version of the CRD exists and delete it if needed:

    kubectl delete crd applications.workshop-example.io --ignore-not-found
    kubectl delete crd applications.workshop-example.io --ignore-not-found
  2. Apply the Application CRD:

    $applicationCrd | kubectl apply -f -
    kubectl apply -f application-crd.yaml
  3. Verify the CRD was created:

    kubectl get crd applications.workshop-example.io
    kubectl get crd applications.workshop-example.io
  4. Examine the CRD details:

    kubectl describe crd applications.workshop-example.io
    kubectl describe crd applications.workshop-example.io

    Notice the schema validation rules and the API versions available.

Task 3 - Create a Custom Resource

  1. Create the Application custom resource:

    $applicationCr = @"
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: example-app
    spec:
      deploymentName: example-app
      replicas: 3
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
      resources:
        memoryRequest: "64Mi"
        cpuRequest: "100m"
        memoryLimit: "128Mi"
        cpuLimit: "200m"
    "@
    
    # Output the custom resource to review it
    $applicationCr
    cat <<EOF > application-cr.yaml
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: example-app
    spec:
      deploymentName: example-app
      replicas: 3
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
      resources:
        memoryRequest: "64Mi"
        cpuRequest: "100m"
        memoryLimit: "128Mi"
        cpuLimit: "200m"
    EOF
    
    # Output the custom resource to review it
    cat application-cr.yaml

    This is an instance of the Application custom resource type we just defined.

  2. Create the Custom Resource:

    $applicationCr | kubectl apply -f -
    kubectl apply -f application-cr.yaml
  3. Verify the Custom Resource was created:

    kubectl get applications
    kubectl get applications
  4. View the details of the Custom Resource:

    kubectl describe application example-app
    kubectl describe application example-app

Task 4 - Test Validation Rules

  1. Try to create an invalid Custom Resource (with too many replicas):

    $invalidApp = @"
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: invalid-app
    spec:
      deploymentName: invalid-app
      replicas: 20
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
    "@
    
    $invalidApp | kubectl apply -f -
    cat <<EOF | kubectl apply -f -
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: invalid-app
    spec:
      deploymentName: invalid-app
      replicas: 20
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
    EOF

    You should get an error because the replicas field has a maximum value of 10 in our CRD.

  2. Fix the invalid resource and apply again:

    $validApp = @"
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: valid-app
    spec:
      deploymentName: valid-app
      replicas: 5
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
      resources:
        memoryRequest: "64Mi"
        cpuRequest: "100m"
        memoryLimit: "128Mi"
        cpuLimit: "200m"
    "@
    
    $validApp | kubectl apply -f -
    cat <<EOF | kubectl apply -f -
    apiVersion: workshop-example.io/v1
    kind: Application
    metadata:
      name: valid-app
    spec:
      deploymentName: valid-app
      replicas: 5
      image: k8sonazureworkshoppublic.azurecr.io/nginx:latest
      containerPort: 80
      resources:
        memoryRequest: "64Mi"
        cpuRequest: "100m"
        memoryLimit: "128Mi"
        cpuLimit: "200m"
    EOF
  3. Verify the resource was created:

    kubectl get applications
    kubectl get applications

Task 5 - Using Kubectl for Custom Resources

  1. Try kubectl commands with your custom resource:

    # List all applications
    kubectl get applications
    
    # Get output in YAML format
    kubectl get application example-app -o yaml
    
    # Get specific fields using jsonpath
    kubectl get application example-app -o jsonpath='{.spec.replicas}'
    # List all applications
    kubectl get applications
    
    # Get output in YAML format
    kubectl get application example-app -o yaml
    
    # Get specific fields using jsonpath
    kubectl get application example-app -o jsonpath='{.spec.replicas}'
  2. Edit a Custom Resource:

    kubectl edit application example-app
    kubectl edit application example-app

    Change the number of replicas to 4 and save the file.

  3. Verify the change:

    kubectl get application example-app -o jsonpath='{.spec.replicas}'
    kubectl get application example-app -o jsonpath='{.spec.replicas}'

Task 6 - Clean up

  1. Remove the Custom Resources:

    kubectl delete application example-app valid-app
    kubectl delete application example-app valid-app
  2. Remove the Custom Resource Definition:

    kubectl delete crd applications.workshop-example.io
    kubectl delete crd applications.workshop-example.io