How to Access Kubernetes Custom Resource Definitions (CRDs) Using Client-go?
Introduction
Kubernetes is a powerful container orchestration platform that enables seamless scaling and management of containerized applications. It provides built-in resources such as Pods and Deployments, and also supports custom resource definitions Kubernetes users rely on to define 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. Learn more on What is Kubernetes.
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 Cantech.
– A Cantech Kubernetes Engine (CKE) 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 CKE Cluster Using kubectl
Once your CKE cluster is deployed, follow these steps to configure access:
1. Log in to your Cantech customer portal.
2. Navigate to the CKE section and select your cluster.
3. Click Download Configuration to get the Kubernetes config file.
The downloaded file will have a name similar to `cke-example-6b5a-4e5e-a92e-example.yaml`. Rename it to `cke.yaml` and move it to your home directory:
$ cd ~/Downloads $ mv cke-example-6b5a-4e5e-a92e-example.yaml ~/cke.yaml
Next, export the config file as an environment variable so `kubectl` can access the cluster:
$ cd ~
$ echo $HOME Get the home directory path
$ export KUBECONFIG='${HOME}/cke.yaml'
Verify the connection by running:
$ 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: Specifies whether the resource is namespaced or cluster-wide.
– scope: Defines the structure and scope of the custom resource.
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:
$ 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:
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
apiVersionis set toapiextensions.k8s.io/v1, the stable version for defining CRDs in Kubernetes. - The
metadata.nameisdatabases.resource.example.com, which uniquely identifies the CRD. - The
groupisresource.example.com, which is required when using the Kubernetes Go client to interact with custom resources. - The
scopeis set toCluster, meaning the resource can be accessed from anywhere in the cluster. To limit access to a specific namespace, changescopetoNamespace. - The database custom resource includes fields like
dbName,description,total,available,dbType, andtags. totalandavailableare integers constrained to values between 1 and 100.dbTypeis a string and must be one ofsql,noSQL,timeSeries,messageQueue, orcaching.
Step 4: Apply the CRD to the Cluster
Run the following command to create the database CRD in your Kubernetes cluster:
$ 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:
customresourcedefinition.apiextensions.k8s.io/databases.resource.example.com created
The custom resource definition is ready. Now, add a new database to it.
Create a file named mysql_resource_object.yaml with your editor to add a new database resource to the custom resource definition.
$ 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
apiVersionfor the resource definition with the valueresource.example.com/v1. - The
apiVersionmust be in the format ofresourceGroup.version. - The resource type should be
databaseand must match the custom resource definition you created earlier. - The name of the
databaseitem is “mysql” withdbTypeas “sql” andavailableinstances 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 point, you’ve set up the database custom resource definition and included 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.
1. 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.
2. 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.
2.1 Implemented Database structs and methods to interact with Kubernetes runtime
- Create
Databasestructs
You must create structs forDatabaseSpec,Database, andDatabaseListto interact with the existingdatabasecustom resource definition. Run the following commands to create a newdatabase.gofile.
$ 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
$ nano deepcopy.go
Copy and paste the following code into deepcopy.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
$ nano register.go
Copy and paste the following code into register.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.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.go:
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
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.
2.3 Creating main.gofile 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
cke.yamlconfiguration file into the current directory.
Proceed with setting up main.go to interact with the Kubernetes cluster and manage resources efficiently.
$ cd .. $ cp ~/cke.yaml .
- Create a
main.gofile.
$ cd .. $ nano main.go
- Add the following code to the
main.gofile:
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+"/cke.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.gofile.
$ 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/cantech/k8s-crd/k8s-crd-full- demo/cke.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.gocode 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/cantech/k8s-crd/k8s-crd-full-demo/cke.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.gofile 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/cantech/k8s-crd/k8s-crd-full- demo/cke.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.