Performing Crud operation on Nginx Deployment with Go-Gin framework
The client-go library is a Go client library provided by Kubernetes, which allows you to interact with Kubernetes clusters programmatically.
Why use code when directly with ‘kubectl’ commands any Kubernetes manifest can be applied here are the following advantages of the client-go library over ‘kubectl’ commands :-
- Automation: Enables programmatically automating Kubernetes operations.
- Customization: Provides flexibility and extensibility for tailored interactions with the Kubernetes API.
- Integration: Seamlessly integrates Kubernetes operations with Go applications.
- Performance: Offers faster and more efficient execution compared to external
kubectl
commands. - Error Handling: Provides structured error types and better error handling capabilities.
Here I used the following steps to create nginx deployment through client-go library
Steps
- Pull the Gin and client-go library.
go get -u github.com/gin-gonic/gin
go get -u k8s.io/client-go@v0.24.0
2. import libraries into the project
import (
"github.com/gin-gonic/gin"
v1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
3. Set up the route
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, world!")
})
r.Run(":8080")
}
4. Now create a client that talks to K8s APIs
func GetKubernetesClient() (*kubernetes.Clientset, error) {
var kubeconfig = "your kube config file path"
/***
BuildConfigFromFlags used as helper function that
builds configs from a master url or a kubeconfig filepath
***/
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}
/**
setup the client with configuration config
**/
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
return clientset, nil
}
5. Create a Route to trigger the deployment
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, world!")
})
r.POST("/create", allRoutes)
r.Run(":8080")
}
//payload
type DeploymentRequest struct {
Replicas int32 `json:"replicas"`
DeploymentName string `json:"deploymentName"`
}
func int32Ptr(i int32) *int32 {
return &i
}
func allRoutes(c *gin.Context) {
//Get the client
clientset, err := GetKubernetesClient()
//handle the error
if err != nil {
fmt.Print(err)
c.String(http.StatusInternalServerError, "Failed to connect to the Kubernetes cluster")
return
}
switch c.Request.Method {
case "POST":
/**
DeploymentRequest is a payload
**/
var req DeploymentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.String(http.StatusBadRequest, "Invalid request payload")
return
}
if err := createNginxDeployment(clientset, req); err != nil {
c.String(http.StatusInternalServerError, "Failed to create Nginx deployment")
return
}
c.String(http.StatusOK, "Nginx deployment created successfully")
default:
c.String(http.StatusMethodNotAllowed, "Method not allowed")
}
}
create the createNginxDeployment function
/**
just like the kubernetes manifest for the nginx deployment here
also we will create a template
**/
func createNginxDeployment(clientset *kubernetes.Clientset, req DeploymentRequest) error {
deployment := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: req.DeploymentName,
},
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "nginx",
},
},
Replicas: int32Ptr(req.Replicas),
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "nginx",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "nginx",
Image: "nginx:latest",
},
},
},
},
},
}
//using inbuild function to create the deployment in kubernetes config
_, err := clientset.AppsV1().Deployments("default").Create(context.TODO(), deployment, metav1.CreateOptions{})
if err != nil {
return err
}
return nil
}
6. To list down all the pods that are running
update the main funtion with GET route
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, world!")
})
r.GET("/getPods", allRoutes)
r.POST("/create", allRoutes)
r.Run(":8080")
}
update the allRoute function to handle the GET request
case "GET":
// List pods
podList, err := clientset.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
if err != nil {
c.String(http.StatusInternalServerError, "Failed to list pods")
return
}
var podNames []string
for _, pod := range podList.Items {
podNames = append(podNames, pod.Name)
}
for i, val := range podNames {
fmt.Println(i, " ", val)
}
c.String(http.StatusOK, "Pods listed successfully")
7. To update the Nginx deployment
update the main function with PUT route
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, world!")
})
r.GET("/getPods", allRoutes)
r.POST("/create", allRoutes)
r.PUT("/update/:name", allRoutes)
r.Run(":8080")
}
Handle put request in the allroutes function
case "PUT":
deploymentName := c.Param("name")
var req DeploymentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.String(http.StatusBadRequest, "Invalid request payload")
return
}
if err := updateNginxDeployment(clientset, deploymentName, req.Replicas); err != nil {
c.String(http.StatusInternalServerError, "Failed to update Nginx deployment")
return
}
c.String(http.StatusOK, "Nginx deployment updated successfully")
create the updateNginxDeployment function
func updateNginxDeployment(clientset *kubernetes.Clientset, deploymentName string, replicas int32) error {
deploymentClient := clientset.AppsV1().Deployments("default")
deployment, err := deploymentClient.Get(context.TODO(), deploymentName, metav1.GetOptions{})
if err != nil {
return err
}
deployment.Spec.Replicas = int32Ptr(replicas)
_, err = deploymentClient.Update(context.TODO(), deployment, metav1.UpdateOptions{})
if err != nil {
return err
}
return nil
}
8. To delete the Nginx deployment
update the main function with DELETE route
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello, world!")
})
r.GET("/getPods", allRoutes)
r.POST("/create", allRoutes)
r.PUT("/update/:name", allRoutes)
r.DELETE("/delete/:name", allRoutes)
r.Run(":8080")
}
Handle delete request in the allroutes function
case "DELETE":
deploymentName := c.Param("name")
if err := deleteNginxDeployment(clientset, deploymentName); err != nil {
c.String(http.StatusInternalServerError, "Failed to delete Nginx deployment")
return
}
c.String(http.StatusOK, "Nginx deployment deleted successfully")
create the deleteNginxDeployment function
func deleteNginxDeployment(clientset *kubernetes.Clientset, deploymentName string) error {
deploymentClient := clientset.AppsV1().Deployments("default")
deletePolicy := metav1.DeletePropagationForeground
if err := deploymentClient.Delete(context.TODO(), deploymentName, metav1.DeleteOptions{
PropagationPolicy: &deletePolicy,
}); err != nil {
return err
}
return nil
}
With client-go, you can create deployments with different configurations, such as defining the number of replicas, specifying container images, setting environment variables, configuring volume mounts, defining resource limits, and more.
The client-go library provides a comprehensive set of APIs and resources for interacting with the Kubernetes API server. You can use it to create deployments, services, pods, config maps, secrets, and other Kubernetes resources programmatically.
In conclusion, by utilizing the client-go library, you have the flexibility to define and customize deployments according to your specific requirements, enabling you to create and manage various types of deployments in Kubernetes.
In my upcoming blog posts, I’ll be writing about how to create custom resources using the client-go library.