{"id":15175,"date":"2024-09-24T17:33:05","date_gmt":"2024-09-24T12:03:05","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=15175"},"modified":"2024-09-24T17:34:20","modified_gmt":"2024-09-24T12:04:20","slug":"extending-k8s-api","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2024\/09\/24\/extending-k8s-api\/","title":{"rendered":"Extending K8S API"},"content":{"rendered":"\r\n<p>Ever found yourself thinking, &#8220;Kubernetes is awesome, but I wish it could do this specific thing just for my setup&#8221;? Well, guess what? It probably can. Kubernetes isn&#8217;t just about managing those swanky Pods and Services; it&#8217;s like a LEGO set, and with the right pieces, you can build pretty much anything.<\/p>\r\n\r\n\r\n\r\n<p>Enter the world of Custom Resource Definitions, or CRDs for the cool kids. Imagine being able to teach your Kubernetes new tricks without waiting for the next big release. That&#8217;s exactly what CRDs let you do!<\/p>\r\n\r\n\r\n\r\n<p>In this blog post, we will explore how to extend the Kubernetes API with Custom Resource Definitions (CRDs).<\/p>\r\n<p><!--more--><\/p>\r\n\r\n\r\n\r\n<p>Topics To be covered :<\/p>\r\n\r\n\r\n\r\n<ol>\r\n<li>Registering a Custom API in Golang<\/li>\r\n\r\n\r\n\r\n<li>Creating a Custom Resource Definition ( CRD ) to Register our Custom Resource<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">A Look at the General API of Kubernetes Resources<\/h2>\r\n\r\n\r\n\r\n<p><strong>1. The Basics: API Groups and Versions<\/strong><\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li><strong>API Groups<\/strong>: To make its API more extensible and modular, Kubernetes has different API groups like <code>core<\/code>, <code>apps<\/code>, <code>batch<\/code>, <code>extensions<\/code>, and more. These groups represent various functionalities and components.<\/li>\r\n\r\n\r\n\r\n<li><strong>Versions<\/strong>: Each group can have multiple versions, typically marked as <code>v1<\/code>, <code>v1beta1<\/code>, etc. This is because the Kubernetes API evolves over time, and different versions can coexist.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p><strong>2. Resources and Kinds<\/strong><\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li><strong>Resources<\/strong>: These are a persistent entity in the Kubernetes system. <code>Pods<\/code>, <code>Services<\/code>, and <code>Nodes<\/code> are all examples of resources.<\/li>\r\n\r\n\r\n\r\n<li><strong>Kinds<\/strong>: This denotes the type of the resource. When you create or read a resource, you work with its <code>kind<\/code>. For instance, the kind for a Pod is <code>Pod<\/code>, and for a Service, it&#8217;s <code>Service<\/code>.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p><strong>3. Object Metadata<\/strong> Every Kubernetes resource comes with metadata. This section usually includes details like:<\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li><code>name<\/code>: Unique within a namespace, used to identify the resource.<\/li>\r\n\r\n\r\n\r\n<li><code>namespace<\/code>: Helps with the resource&#8217;s scope. Some resources are cluster-scoped (like <code>Node<\/code>), while others are namespace-scoped (like <code>Pod<\/code>).<\/li>\r\n\r\n\r\n\r\n<li><code>labels<\/code> and <code>annotations<\/code>: Key-value pairs that you can attach to resources for various purposes, from organizational patterns to notes.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p><strong>4. Spec and Status<\/strong> Almost every Kubernetes resource has these two main fields:<\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li><strong>Spec (Specification)<\/strong>: This is what you provide. It\u2019s your desired state for the resource.<\/li>\r\n\r\n\r\n\r\n<li><strong>Status<\/strong>: This is what Kubernetes provides back. It tells you the current state of the resource and how it compares to the spec.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p><strong>5. API Endpoints<\/strong> For every resource, there are specific API endpoints. These are the URLs you&#8217;d hit if you were to interact directly with the Kubernetes API server. For instance, <code>\/api\/v1\/namespaces\/{namespace}\/pods\/{pod}<\/code> would be an endpoint for a specific pod.<\/p>\r\n\r\n\r\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Registering a Custom API in Golang<\/h2>\r\n\r\n\r\n\r\n<p>Before you can use a custom resource in Kubernetes, you need to define it, usually in Golang. Here is how you can do it.<\/p>\r\n\r\n\r\n\r\n<ol>\r\n<li>Define your types in Go. Use tags to define how the fields are serialized in JSON or YAML.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">package v1\r\n\r\ntype MyCustomResourceSpec struct {\r\n    Field1 string `json:\"field1,omitempty\"`\r\n    Field2 int    `json:\"field2,omitempty\"`\r\n}\r\n\r\ntype MyCustomResource struct {\r\n    metav1.TypeMeta   `json:\",inline\"`\r\n    metav1.ObjectMeta `json:\"metadata,omitempty\"`\r\n\r\n    Spec   MyCustomResourceSpec   `json:\"spec,omitempty\"`\r\n    Status MyCustomResourceStatus `json:\"status,omitempty\"`\r\n}\r\n\r\ntype MyCustomResourceList struct {\r\n    metav1.TypeMeta `json:\",inline\"`\r\n    metav1.ListMeta `json:\"metadata,omitempty\"`\r\n    Items           []MyCustomResource `json:\"items\"`\r\n}<\/pre>\r\n\r\n\r\n\r\n<ol start=\"2\">\r\n<li>Next, we must create a deep copy to make our API object compatible with the k8s object. Since the Object Interface requires DeepCopyObject()<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">type Object interface {\r\n    GetObjectKind() schema.ObjectKind\r\n    DeepCopyObject() Object\r\n}<\/pre>\r\n\r\n\r\n\r\n<p>To generate a deepcopy we would use <a href=\"https:\/\/github.com\/kubernetes-sigs\/controller-tools\/blob\/v0.12.1\/cmd\/controller-gen\/main.go\" target=\"_blank\" rel=\"noopener\">controller-gen<\/a> run the below command to install at <code>$GOPATH\/bin\/<\/code><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">go install sigs.k8s.io\/controller-tools\/cmd\/controller-gen@latest<\/pre>\r\n\r\n\r\n\r\n<ol start=\"3\">\r\n<li>We need to put kubebuilder tags to tell the controller-gen which object we need to create deecopy. The tag we use is <code>\/\/ +kubebuilder:object:root=true<\/code> as suggested <a href=\"https:\/\/github.com\/kubernetes-sigs\/controller-tools\/blob\/master\/pkg\/deepcopy\/gen.go#L43\" target=\"_blank\" rel=\"noopener\">here<\/a>. We need to put this tag on <code>MyCustomResource<\/code> and <code>MyCustomResourceList<\/code> to generate deepcopy for that as given below. This would generate a file zz_deepcopy.go in the same directory.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<pre class=\"wp-block-syntaxhighlighter-code\">\/\/ +kubebuilder:object:root=true\r\ntype MyCustomResource struct {\r\n    metav1.TypeMeta   `json:\",inline\"`\r\n    metav1.ObjectMeta `json:\"metadata,omitempty\"`\r\n\r\n    Spec   MyCustomResourceSpec   `json:\"spec,omitempty\"`\r\n    Status MyCustomResourceStatus `json:\"status,omitempty\"`\r\n}\r\n\r\n\/\/ +kubebuilder:object:root=true\r\ntype MyCustomResourceList struct {\r\n    metav1.TypeMeta `json:\",inline\"`\r\n    metav1.ListMeta `json:\"metadata,omitempty\"`\r\n    Items           []MyCustomResource `json:\"items\"`\r\n}<\/pre>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Creating a Custom Resource definition (CRD) to Register the Custom Resource<\/h2>\r\n\r\n\r\n\r\n<p>Since now we have created a Go scheme for our custom resource we need to register this resource in the k8s. We have to create a definition for that i.e. custom resource definition<\/p>\r\n\r\n\r\n\r\n<p>We would use controller-gen to create a CRD manifest. Go to the root of the repo and run :<br \/><code>controller-gen crd:crdVersions=v1 paths=\".\/...\" output:dir=\".\/crd\"<\/code><\/p>\r\n\r\n\r\n\r\n<p>This command will:<\/p>\r\n\r\n\r\n\r\n<ul>\r\n<li>Scan for types in the current module (the paths=&#8221;.\/\u2026&#8221; part).<\/li>\r\n\r\n\r\n\r\n<li>Generate CRDs in the v1 format (crd:crdVersions=v1).<\/li>\r\n\r\n\r\n\r\n<li>Place the generated CRD YAML files in the .\/crd directory.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<p>If you have a Kubernetes cluster ready and you want to apply the CRDs, you can use kubectl: <code>kubectl apply -f .\/crd<\/code><\/p>\r\n<p><strong>Blog Pundits: <a href=\"https:\/\/opstree.com\/blog\/\/author\/sandeep7c51ad81ba\/\" target=\"_blank\" rel=\"noreferrer noopener\">Sandeep Rawat<\/a><\/strong><\/p>\r\n<p>\r\n\r\n<\/p>\r\n<p><strong><a href=\"https:\/\/opstree.com\/contact-us\/?utm_source=WordPress&amp;utm_medium=Blog&amp;utm_campaign=On-Premise_Setup_of_Kubernetes_Cluster_using_KubeSpray_%28Offline+Mode%29-PART+_1\" target=\"_blank\" rel=\"noreferrer noopener\">OpsTree<\/a><\/strong> is an End-to-End DevOps Solution Provider.<\/p>\r\n<p>\r\n\r\n<\/p>\r\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\r\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/opstree.com\/contact-us\/?utm_source=WordPress&amp;utm_medium=Blog&amp;utm_campaign=On-Premise_Setup_of_Kubernetes_Cluster_using_KubeSpray_%28Offline+Mode%29-PART+_1\" target=\"_blank\" rel=\"noreferrer noopener\">Contact Us<\/a><\/div>\r\n<\/div>\r\n<p>\r\n\r\n<\/p>\r\n<p class=\"has-text-align-center\"><strong>Connect with Us<\/strong><\/p>","protected":false},"excerpt":{"rendered":"<p>Ever found yourself thinking, &#8220;Kubernetes is awesome, but I wish it could do this specific thing just for my setup&#8221;? Well, guess what? It probably can. Kubernetes isn&#8217;t just about managing those swanky Pods and Services; it&#8217;s like a LEGO set, and with the right pieces, you can build pretty much anything. Enter the world &hellip; <a href=\"https:\/\/opstree.com\/blog\/2024\/09\/24\/extending-k8s-api\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Extending K8S API&#8221;<\/span><\/a><\/p>\n","protected":false},"author":230200049,"featured_media":19171,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[768739351],"tags":[768739380],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2023\/09\/Extending-K8S-API.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-3WL","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/15175"}],"collection":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/users\/230200049"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=15175"}],"version-history":[{"count":9,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/15175\/revisions"}],"predecessor-version":[{"id":19175,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/15175\/revisions\/19175"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/19171"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=15175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=15175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=15175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}