How to Access Kubernetes Custom Resource Definitions (CRDs) Using Client-go?
Kubernetes is a powerful container orchestration platform that enables seamless scaling and management of containerized applications. While Kubernetes provides built-in resources such as Pods and Deployments, it also supports Custom Resource Definitions (CRDs), allowing users to define custom resources tailored to their specific needs.
Benefits of Kubernetes CRDs:
– CRDs allow you to extend Kubernetes’ capabilities by defining resources with customized formats.
– You can manage custom resources using `kubectl`, just like built-in resources.
– Kubernetes automatically handles the scaling of custom resources as needed.
– CRDs integrate seamlessly with Kubernetes API and client tools for programmatic interaction.
One such client tool is client-go, a Go-based library that facilitates interaction with Kubernetes resources programmatically. In this guide, we’ll explore how to access and manage Kubernetes CRDs using client-go.
Demonstration Scenario
Imagine your development team relies on Kubernetes for application deployment. When building a new application, you need to verify whether a required database is already available within the cluster. To streamline database management, you create a custom resource that maintains information about databases, such as:
– The list of supported databases.
– The total number of instances.
– Available instances for each database type.
By defining a CRD for databases, you can programmatically retrieve and manage this information using client-go.
Prerequisites
Before proceeding, ensure you have the following:
– A newly deployed Ubuntu 20.04 server on Vultr.
– A Vultr Kubernetes Engine (VKE) cluster (this guide uses version 1.24.4).
– A Go development environment (Go version 1.19 is used in this demo).
– The kubectl command-line tool installed to interact with Kubernetes.
Accessing the VKE Cluster Using kubectl
Once your VKE cluster is deployed, follow these steps to configure access:
1. Log in to your Vultr customer portal.
2. Navigate to the VKE section and select your cluster.
3. Click Download Configuration to get the Kubernetes config file.
The downloaded file will have a name similar to `vke-example-6b5a-4e5e-a92e-example.yaml`. Rename it to `vke.yaml` and move it to your home directory:
```sh $ cd ~/Downloads $ mv vke-example-6b5a-4e5e-a92e-example.yaml ~/vke.yaml ```
Next, export the config file as an environment variable so `kubectl` can access the cluster:
```sh $ cd ~ $ echo $HOME Get the home directory path $ export KUBECONFIG='${HOME}/vke.yaml' ```
Verify the connection by running:
```sh $ kubectl get node ```
If successful, the output should resemble:
``` NAME STATUS ROLES AGE VERSION k8s-crd-ba11fd0aaa9b Ready <none> 6d20h v1.24.4 k8s-crd-e29c4afea916 Ready <none> 6d20h v1.24.4 ```
Now that you have access to the Kubernetes cluster using `kubectl`, let’s proceed with creating a CRD.
Creating a Custom Resource Definition (CRD) Using kubectl
Kubernetes uses YAML configuration files to define resources and instruct the server on how to handle them. A CRD file provides essential information, including:
– `apiVersion`: The Kubernetes API version.
– `metadata`: Identifies the resource.
– `spec`: Defines the structure and scope of the custom resource.
– `scope`: Specifies whether the resource is namespaced or cluster-wide.
Refer to the official Kubernetes documentation on creating CRDs for a detailed guide on structuring these YAML files.
By defining a CRD for database management, you gain improved visibility and control over your Kubernetes cluster resources. In the next steps, we’ll explore how to interact with CRDs programmatically using client-go.
Creating a Database Custom Resource Definition (CRD)
To define a new database custom resource in Kubernetes, follow these steps:
Step 1: Create a CRD Definition File
Run the following commands to create a directory and a new CRD YAML file:
```sh $ mkdir k8s-crd-demo $ cd k8s-crd-demo $ nano dbs_crd.k8s.yaml ```
Step 2: Define the CRD in YAML
Copy and paste the following YAML code into the `dbs_crd.k8s.yaml` file and save it:
```yaml apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: databases.resource.example.com spec: group: resource.example.com versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: dbName: type: string nullable: false description: type: string nullable: false total: type: integer default: 10 minimum: 1 maximum: 100 available: type: integer default: 10 minimum: 1 maximum: 100 dbType: type: string enum: - sql - noSQL - timeSeries - messageQueue - caching nullable: false tags: type: string nullable: true required: ["dbName", "total", "available", "dbType"] required: ["spec"] scope: Cluster names: plural: databases singular: database kind: Database shortNames: - db ```
Step 3: Understanding the CRD Definition
– The `apiVersion` is set to `apiextensions.k8s.io/v1`, the stable version for defining CRDs in Kubernetes.
– The `metadata.name` is `databases.resource.example.com`, which uniquely identifies the CRD.
– The `group` is `resource.example.com`, which is required when using the Kubernetes Go client to interact with custom resources.
– The `scope` is set to `Cluster`, meaning the resource can be accessed from anywhere in the cluster. To limit access to a specific namespace, change `scope` to `Namespace`.
– The database custom resource includes fields like `dbName`, `description`, `total`, `available`, `dbType`, and `tags`.
– `total` and `available` are integers constrained to values between 1 and 100.
– `dbType` is a string and must be one of `sql`, `noSQL`, `timeSeries`, `messageQueue`, or `caching`.
Step 4: Apply the CRD to the Cluster
Run the following command to create the database CRD in your Kubernetes cluster:
```sh $ kubectl apply -f dbs_crd.k8s.yaml ```
This command uses the `apply` option to create or update the custom resource, while the `-f` option specifies the YAML file to apply. If successful, you should see output similar to:
```sh customresourcedefinition.apiextensions.k8s.io/databases.resource.example.com created
Now you successfully created the custom resource definition. Let’s move on to add a new database to database custom resource definition.
Add a new database resource item into the database custom resource definition. To do it, create mysql_resource_object.yaml with your editor:
$ nano mysql_resource_object.yaml
Copy the following content into mysql_resource_object.yaml:
apiVersion: "resource.example.com/v1" kind: Database metadata: name: mysql spec: dbName: mysql
description: Used for storing relation structured data.
total: 50 available: 50 dbType: sql
tags: Web Development, Data Engineering, Embedded software
You set the apiVersion for the resource definition with the value resource.example.com/v1.
The apiVersion must be in the format of resourceGroup.version.
The kind of resource is Database and must match the kind of the custom resource definition you already created earlier.
The name of the database item is “mysql” with dbType as “sql” and available instances are 50.
Run the following command to add the mysql database item to the database resource definition.
$ kubectl apply -f mysql_resource_object.yaml
Similar to creating the resource definition, use kubectl with the apply option to add a new resource. You should be able to see similar output like:
database.resource.example.com/mysql created
You now successfully added the “mysql” resource to the database custom resource definition. To check the available databases in the Kubernetes cluster, run the following:
$ kubectl get db
You should be able to see the output like:
NAME AGE mysql 2m58s
Or you can get detailed information for the database custom resource definition using the following command:
$ kubectl get db -o yaml
The output should look like this:
apiVersion: v1 items: - apiVersion: resource.example.com/v1 kind: Database metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"resource.example.com/v1","kind":"Database","metadata":{"annotations":{},"name":"mysql"},"spec": {"available":50,"dbName":"mysql","dbType":"sql","description":"Used for storing relation structured data.","tags":"Web Development, Data Engineering, Embedded software","total":50}} creationTimestamp: "2022-11-17T17:58:30Z" generation: 1 name: mysql resourceVersion: "1419745" uid: 40ed6d7e-a372-4f64-8400-20376fd8fdba spec: available: 50 dbName: mysql dbType: sql description: Used for storing relation structured data. tags: Web Development, Data Engineering, Embedded software total: 50 kind: List metadata: resourceVersion: ""
At this step, you successfully create the database custom resource definition and added the mysql database.
Let’s move on to see how you can programmatically access the database custom resource definition using Go with the help of Kubernetes go-client tool.
Interact with Kubernetes custom resources using go-client
You must initiate a go module environment and install the needed dependencies to build an app that interacts with the Kubernetes custom resources.
I. Install needed dependencies
Open the terminal and type the following go mod command to initialize the go module environment.
$ go mod init k8s-resource.com/m
The go module will automatically create a go.mod file. Add the following dependencies into your app’s go.mod file to connect with the Kubernetes cluster.
require k8s.io/client-go v0.24.4 require ( github.com/google/go-cmp v0.5.9 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/rogpeppe/go-internal v1.8.0 // indirect github.com/stretchr/testify v1.7.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.2.0 // indirect ) require ( k8s.io/api v0.24.4 // indirect k8s.io/apimachinery v0.24.4 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/imdario/mergo v0.3.13 // indirect; indirectap github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/net v0.2.0 // indirect golang.org/x/oauth2 v0.2.0 // indirect golang.org/x/sys v0.2.0 // indirect golang.org/x/term v0.2.0 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.80.1 // indirect k8s.io/utils v0.0.0-20221108210102-8e77b1f39fe2 // indirect )
NOTE: The version of the go-client library should match the Kubernetes cluster version to prevent incompatible issues. Check out this guide for compatibility matrix details.
Then run go mod tidy to install these dependencies:
$ go mod tidy
Now that you’ve installed the dependencies, let’s write code to interact with the Kubernetes database custom resources.
II. Write the code to interact with the Kubernetes custom resources
Let’s write the code that allows the app to:
Create a new custom resource
Remove an existing one
Get all the current custom resources
Get the custom resource by the resource name
To do it, you use several built-in methods from Kubernetes go-client:
type Interface interface { GetRateLimiter() flowcontrol.RateLimiter Verb(verb string) *Request Post() *Request Put() *Request Patch(pt types.PatchType) *Request Get() *Request Delete() *Request APIVersion() schema.GroupVersion }
You use the Post method to create a new resource, Get to retrieve all the resources or a specific resource by its name, and Delete to remove an existing resource.
1. Implemented Database structs and methods to interact with Kubernetes runtime
Create Database structs
You must create structs for DatabaseSpec, Database, and DatabaseList to interact with the existing database custom resource definition. Run the following commands to create a new database.go file.
$ mkdir api $ cd api $ nano database.go
Copy the following codes into the database.go file:
package api
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" type DatabaseSpec struct { DbName string `json:"dbName"` Description string `json:"description,omitempty"` Total int `json:"total"` Available int `json:"available"` DbType string `json:"dbType"` Tags string `json:"tags,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type Database struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec DatabaseSpec `json:"spec"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type DatabaseList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []Database `json:"items"` }
The DatabaseSpec have fields that match with the current spec database resource definition are dbName, description, total, available,dbType, and tags. Similarly, the Database and DatabaseList structs consist of fields that match with database resource definition metadata information.
Creating DeepCopy Methods
To enable deep copying of custom resources, create a `deepcopy.go` file and define methods so your application can interact with the Kubernetes runtime.
Create the deepcopy.go File
```sh $ nano deepcopy.go ```
Copy and paste the following code into `deepcopy.go`:
```go package api import "k8s.io/apimachinery/pkg/runtime" // DeepCopyInto copies the receiver into the provided object. func (in *Database) DeepCopyInto(out *Database) { out.TypeMeta = in.TypeMeta out.ObjectMeta = in.ObjectMeta out.Spec = DatabaseSpec{ DbName: in.Spec.DbName, Description: in.Spec.Description, Total: in.Spec.Total, Available: in.Spec.Available, DbType: in.Spec.DbType, Tags: in.Spec.Tags, } } // DeepCopyObject creates a new instance of Database and copies the data. func (in *Database) DeepCopyObject() runtime.Object { out := Database{} in.DeepCopyInto(&out) return &out } // DeepCopyObject creates a new instance of DatabaseList and copies the data. func (in *DatabaseList) DeepCopyObject() runtime.Object { out := DatabaseList{} out.TypeMeta = in.TypeMeta out.ListMeta = in.ListMeta if in.Items != nil { out.Items = make([]Database, len(in.Items)) for i := range in.Items { in.Items[i].DeepCopyInto(&out.Items[i]) } } return &out } ```
This code defines the `DeepCopyInto` method for the `Database` struct and `DeepCopyObject` methods for both `Database` and `DatabaseList` structs, ensuring proper interaction with the Kubernetes runtime.
Adding Schema Types for Kubernetes Runtime
To register custom resources with the Kubernetes API, create a `register.go` file.
Create the register.go File
```sh $ nano register.go ```
Copy and paste the following code into `register.go`:
```go package api import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) const ( GroupName = "resource.example.com" GroupVersion = "v1" ) var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion} var ( SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) AddToScheme = SchemeBuilder.AddToScheme ) // addKnownTypes registers custom resource types with the Kubernetes runtime. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &Database{}, &DatabaseList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } ```
This code:
– Defines `GroupName` and `GroupVersion` to match the custom resource definition (CRD).
– Implements `addKnownTypes` to register `Database` and `DatabaseList` with the Kubernetes runtime.
At this stage, you have successfully implemented the Go structs, functions, and methods required to interact with the Kubernetes runtime. The next section will focus on defining the Kubernetes client and methods to manage the custom resources.
In this section, we will implement a Kubernetes client and define methods for managing custom resources. Specifically, we will:
Create a new resource
Retrieve existing resources
Delete an existing resource
2. Implementing Kubernetes Client and Methods
To interact with Kubernetes custom resources, we need to define the configuration for the Kubernetes REST client. Follow the steps below to set up the client.
Step 1: Define the Kubernetes REST Client Configuration
First, create a new file named api.go to configure the REST client. Run the following commands:
$ cd .. $ mkdir clientset $ cd clientset $ nano api.go
Step 2: Copy the Following Code into api.gogo
package clientset import ( "context" "k8s-resource.com/m/api" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) // ExampleInterface defines the contract for interacting with Database custom resources type ExampleInterface interface { Databases(ctx context.Context) DatabaseInterface } // ExampleClient represents a Kubernetes client for handling custom resources type ExampleClient struct { restClient rest.Interface } // NewForConfig initializes a new Kubernetes client with the given configuration func NewForConfig(c *rest.Config) (*ExampleClient, error) { config := *c config.ContentConfig.GroupVersion = &schema.GroupVersion{ Group: api.GroupName, Version: api.GroupVersion, } config.APIPath = "/apis" config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() config.UserAgent = rest.DefaultKubernetesUserAgent() client, err := rest.RESTClientFor(&config) if err != nil { return nil, err } return &ExampleClient{restClient: client}, nil } // Databases returns a client instance for interacting with Database resources func (c *ExampleClient) Databases(ctx context.Context) DatabaseInterface { return &databaseClient{ restClient: c.restClient, ctx: ctx, } }
Explanation of the Code
The ExampleInterface defines the available database operations.
The ExampleClient struct wraps the Kubernetes REST client.
The NewForConfig function initializes the client by setting API paths, group versions, and serialization options.
The Databases function provides an instance for interacting with Database resources.
Step 3: Add Methods for Managing Custom Resources
Next, you need to define methods for creating, retrieving, and deleting custom resources. For this, create a new file named databases.go.
$ nano databases.go
Now, proceed with implementing the required functions inside databases.go.
$ nano databases.go
Copy the following code into the databases.go file.
package clientset import ( "context" "k8s-resource.com/m/api" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) type DatabaseInterface interface { List(opts metav1.ListOptions) (*api.DatabaseList, error) Get(name string, options metav1.GetOptions) (*api.Database, error) Create(*api.Database) (*api.Database, error) Delete(name string, options metav1.DeleteOptions) (*api.Database, error) } type databaseClient struct { restClient rest.Interface ctx context.Context } func (c *databaseClient) List(opts metav1.ListOptions) (*api.DatabaseList, error) { result := api.DatabaseList{} err := c.restClient. Get(). AbsPath("/apis/resource.example.com/v1/databases"). Do(c.ctx). Into(&result) return &result, err } func (c *databaseClient) Get(name string, opts metav1.GetOptions) (*api.Database, error) { result := api.Database{} err := c.restClient. Get(). AbsPath("/apis/resource.example.com/v1/databases"). Name(name). VersionedParams(&opts, scheme.ParameterCodec). Do(c.ctx). Into(&result) return &result, err } func (c *databaseClient) Create(database *api.Database) (*api.Database, error) { result := api.Database{} err := c.restClient. Post(). AbsPath("/apis/resource.example.com/v1/databases"). Body(database). Do(c.ctx). Into(&result) return &result, err } func (c *databaseClient) Delete(name string, opts metav1.DeleteOptions) (*api.Database, error) { result := api.Database{} err := c.restClient. Delete(). AbsPath("/apis/resource.example.com/v1/databases"). Name(name). VersionedParams(&opts, scheme.ParameterCodec). Do(c.ctx).Into(&result) return &result, err }
Next, we define essential methods for interacting with Kubernetes custom resources. These methods include:
Create → Adds a new resource.
Get → Retrieves a resource by name.
List → Fetches all available resources.
Delete → Removes an existing resource that is no longer needed.
With these methods in place, the Kubernetes client is now fully equipped to interact with custom resources.
3. Creating main.go to Interact with Kubernetes Resources
In your next software project, suppose you need to use MongoDB as a database for storing application data. To add a mongodb database into the Database Custom Resource Definition (CRD), follow these steps:
Copy the vke.yaml configuration file into the current directory.
Proceed with setting up main.go to interact with the Kubernetes cluster and manage resources efficiently.
$ cd .. $ cp ~/vke.yaml .
Create a main.go file.
$ cd .. $ nano main.go
Add the following code to the main.go file:
package main import ( "context" "flag" "fmt" "log" "os" "k8s-resource.com/m/api" client "k8s-resource.com/m/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) var kubeconfig string func init() { path, err := os.Getwd() if err != nil { log.Println(err) } flag.StringVar(&kubeconfig, "kubeconfig", path+"/vke.yaml", "path to Kubernetes config file") flag.Parse() } func main() { var config *rest.Config var err error if kubeconfig == "" { log.Printf("using in-cluster configuration") config, err = rest.InClusterConfig() } else { log.Printf("using configuration from '%s'", kubeconfig) config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) } if err != nil { panic(err) } api.AddToScheme(scheme.Scheme) clientSet, err := client.NewForConfig(config) if err != nil { panic(err) } context := context.TODO() newDatabase := new(api.Database) // pa == &Student{"", 0} newDatabase.Name = "mongodb" newDatabase.Kind = "Database" // pa == &Student{"Alice", 0} newDatabase.APIVersion = "resource.example.com/v1" newDatabase.Spec.DbName = "mongodb" newDatabase.Spec.Description = "Used storing unstructured data" newDatabase.Spec.Total = 100 newDatabase.Spec.Available = 50 newDatabase.Spec.DbType = "noSQL" newDatabase.Spec.Tags = "Web Development, nosql data" newDatabase.Spec.Available = 70 projectCreated, err := clientSet.Databases(context).Create(newDatabase) if err != nil { panic(err) } fmt.Println(projectCreated) }
Here you call the Create method to add mongodb database to the database custom resource definition.
Execute the action. Run the main.go file.
$ go run main.go
After running this command, you should see a similar output below:
2022/11/18 02:14:55 using configuration from '/home/example/Projects/Personal/vultr/k8s-crd/k8s-crd-full- demo/vke.yaml' &{{ } {mongodb f8ba273e-fd1f-4b40-b036-cf13b8c72366 1430720 1 2022-11-18 02:14:55 +0700 +07 <nil> <nil> map[] map[] [] [] [{main Update resource.example.com/v1 2022-11-18 02:14:55 +0700 +07 FieldsV1 {"f:spec":{".":{},"f:available":{},"f:dbName":{},"f:dbType":{},"f:description":{},"f:tags":{},"f:total":{}}} }]} {mongodb Used storing unstructured data 100 70 noSQL Web Development, nosql data}}
You just added the “mongodb” database. Let’s try to get detailed information about the “mongodb” database using the Get method.
Get detailed information for “mongodb” database. To do this, replace the main.go code with the below code.
package main import ( "context" "flag" "fmt" "log" "os" "k8s-resource.com/m/api" client "k8s-resource.com/m/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) var kubeconfig string func init() { path, err := os.Getwd() if err != nil { log.Println(err) } flag.StringVar(&kubeconfig, "kubeconfig", path+"/vke.yaml", "path to Kubernetes config file") flag.Parse() } func main() { var config *rest.Config var err error if kubeconfig == "" { log.Printf("using in-cluster configuration") config, err = rest.InClusterConfig() } else { log.Printf("using configuration from '%s'", kubeconfig) config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) } if err != nil { panic(err) } api.AddToScheme(scheme.Scheme) clientSet, err := client.NewForConfig(config) if err != nil { panic(err) } context := context.TODO() projectGet, err := clientSet.Databases(context).Get("mongodb", metav1.GetOptions{}) if err != nil { panic(err) } fmt.Println(projectGet) }
Then run the command:
$ go run main.go
You should see a similar output as below:
2022/11/18 02:18:20 using configuration from '/home/example/Projects/Personal/vultr/k8s-crd/k8s-crd-full-demo/vke.yaml' &{{ } {mongodb f8ba273e-fd1f-4b40-b036-cf13b8c72366 1430720 1 2022-11-18 02:14:55 +0700 +07 <nil> <nil> map[] map[] [] [] [{main Update resource.example.com/v1 2022-11-18 02:14:55 +0700 +07 FieldsV1 {"f:spec":{".":{},"f:available":{},"f:dbName":{},"f:dbType":{},"f:description":{},"f:tags":{},"f:total":{}}} }]} {mongodb Used storing unstructured data 100 70 noSQL Web Development, nosql data}}
If the MySQL database is no longer needed in the Kubernetes cluster, you can remove it by updating the main.go file with the appropriate deletion logic.
Steps to Remove MySQL Resource:
Open the main.go file in your project directory. Replace its content with the following code, which ensures the MySQL database resource is deleted from the cluster. Run the updated code to execute the deletion process. By following these steps, you will successfully remove the MySQL database resource from the Kubernetes cluster.
package main import ( "context" "flag" "log" "os" "k8s-resource.com/m/api" client "k8s-resource.com/m/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) var kubeconfig string func init() { path, err := os.Getwd() if err != nil { log.Println(err) } flag.StringVar(&kubeconfig, "kubeconfig", path+"/vke.yaml", "path to Kubernetes config file") flag.Parse() } func main() { var config *rest.Config var err error if kubeconfig == "" { log.Printf("using in-cluster configuration") config, err = rest.InClusterConfig() } else { log.Printf("using configuration from '%s'", kubeconfig) config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) } if err != nil { panic(err) } api.AddToScheme(scheme.Scheme) clientSet, err := client.NewForConfig(config) if err != nil { panic(err) } context := context.TODO() _, err = clientSet.Databases(context).Delete("mysql", metav1.DeleteOptions{}) if err != nil { panic(err) } }
Then run:
$ go run main.go
Check if the “mysql” database is actually removed. Now, let’s try to get all the current custom resources to see whether you successfully removed the “mysql” database. Replace the existing code in the main.go file with the following content:
package main import ( "context" "flag" "fmt" "log" "os" "k8s-resource.com/m/api" client "k8s-resource.com/m/clientset" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" ) var kubeconfig string func init() { path, err := os.Getwd() if err != nil { log.Println(err) } flag.StringVar(&kubeconfig, "kubeconfig", path+"/vke.yaml", "path to Kubernetes config file") flag.Parse() } func main() { var config *rest.Config var err error if kubeconfig == "" { log.Printf("using in-cluster configuration") config, err = rest.InClusterConfig() } else { log.Printf("using configuration from '%s'", kubeconfig) config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) } if err != nil { panic(err) } api.AddToScheme(scheme.Scheme) clientSet, err := client.NewForConfig(config) if err != nil { panic(err) } context := context.TODO() projects, err := clientSet.Databases(context).List(metav1.ListOptions{}) if err != nil { panic(err) } for _, k := range projects.Items { fmt.Println(k.Name) } }
Let’s run the main.go file:
$ go run main.go
You should only see the mongodb database displayed in the output.
2022/11/18 02:24:08 using configuration from '/home/example/Projects/Personal/vultr/k8s-crd/k8s-crd-full- demo/vke.yaml'
mongodb
And that’s how you can interact with Kubernetes custom resources using Kubernetes go-client tool.
Conclusion
This article covered the concept of Kubernetes CRD, its benefits for your projects, and how to use the Kubernetes Go client to interact with CRDs programmatically. Working with Kubernetes can be both exciting and challenging, so be ready to tackle new obstacles along the way.