{"id":11932,"date":"2022-10-25T11:22:16","date_gmt":"2022-10-25T05:52:16","guid":{"rendered":"https:\/\/opstree.com\/blog\/\/?p=11932"},"modified":"2024-09-24T17:22:36","modified_gmt":"2024-09-24T11:52:36","slug":"on-premise-setup-of-kubernetes-cluster-using-kubespray-offline-mode-part-1","status":"publish","type":"post","link":"https:\/\/opstree.com\/blog\/2022\/10\/25\/on-premise-setup-of-kubernetes-cluster-using-kubespray-offline-mode-part-1\/","title":{"rendered":"On-Premise Setup of Kubernetes Cluster using KubeSpray (Offline Mode) &#8211; PART 1"},"content":{"rendered":"\r\n<p>Today, most organizations are moving to<strong> Managed Services<\/strong> like <strong>EKS<\/strong> (Elastic Kubernetes Services), and <strong>AKS<\/strong> (Azure Kubernetes Services), for easier handling of the Kubernetes Cluster. With Managed Kubernetes we do not have to take care of our Master Nodes, cloud providers will be responsible for all Master Nodes and Worker Nodes, freeing up our time. We just need to deploy our Microservices over the Worker nodes. You can pay extra to achieve an uptime of 99.95%. Node repair ensures that a cluster remains healthy and reduces the chances of possible downtime. This is good in many cases but it makes it an expensive ordeal as AKS costs $0.10 per cluster per hour. You have to install upgrades for the VPC CNI yourself and also, install Calico CNI. There is no IDE extension for developing EKS code. it also creates a dependency on the particular Cloud Provider.<\/p>\r\n\r\n\r\n\r\n<p>To skip the dependency on any Cloud Provider we have to create a <strong>Vanilla<\/strong> <strong>Kubernetes Cluster<\/strong>. This means we have to take care of all the components &#8211; all the Master and Worker Nodes of the Cluster by ourselves.<\/p>\r\n\r\n\r\n\r\n<p>Here we got a scenario in which one of our client&#8217;s requirements was to set up a Kubernetes cluster over On-premises Servers, under the condition of no Internet connectivity. So I choose to perform the setup of the Kubernetes Cluster via <strong>Kubespray<\/strong>.<\/p>\r\n\r\n\r\n\r\n<h4 class=\"wp-block-heading\">Why Kubespray?<\/h4>\r\n\r\n\r\n\r\n<p style=\"font-size: 18px;\"><strong>Kubespray<\/strong> is a composition of Ansible playbooks, inventory,<br \/>provisioning tools, and domain knowledge for generic<br \/>OS\/Kubernetes clusters configuration management tasks.<br \/>Kubespray provides a <strong><em>highly available cluster<\/em><\/strong>, <strong><em>composable<br \/>(choice of the network plugin for instance), supports most popular Linux distributions, and continuous integration tests<\/em><\/strong>.<\/p>\r\n\r\n\r\n\r\n<p><!--more--><\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\"><strong><em>Creating a cluster<\/em><\/strong><\/h3>\r\n\r\n\r\n\r\n<p><br \/>\u25cf Minimum required version of Kubernetes is v1.22<br \/>\u25cf Ansible v2.11+, Jinja 2.11+ and python-netaddr is installed on the machine that will run Ansible commands<br \/>\u25cf The target servers must have access to the Internet in order to pull docker images. Otherwise, additional configuration is required. Checkout offline_environment.md file.<br \/>\u25cf The target servers are configured to allow IPv4 forwarding.<br \/>\u25cf If using IPv6 for pods and services, the target servers are configured to allow IPv6 forwarding.<br \/>\u25cf The firewalls are not managed, you have to implement your own rules the way you are used to. In order to avoid any issues during the deployments you should disable your firewall.<br \/>\u25cf If Kubespray is run from a non-root user account, the correct privilege escalation method should be configured in the target servers. Then the ansible_become flag or command parameters &#8211;become or -b should be specified.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Setup K8s Cluster using Kubespray(Offline Mode):<\/h2>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">Prerequisite:<\/h3>\r\n\r\n\r\n\r\n<p style=\"font-size: 16px;\">\u25cf All required binaries should be downloaded Offline.<br \/>\u25cf All binaries are pushed to whitelisted Storage to K8s Servers as a defined directory structure.<br \/>\u25cf Ansible over jump host.<br \/>\u25cf Passwordless connectivity b\/w jump host and all K8s nodes.<br \/>\u25cf Python over all K8s nodes.<br \/>\u25cf ACR connectivity b\/w all K8s nodes and decided ACR.<br \/>\u25cf YUM Proxy setup from K8s nodes to nexus.<br \/>\u25cf Get the Kubespray Ansible Role over Jump host.<\/p>\r\n\r\n\r\n\r\n<h3 class=\"wp-block-heading\">After completing all the prerequisites We can continue further<\/h3>\r\n\r\n\r\n\r\n<p><strong>1) <\/strong>First of all we need to pull the required code from the official GitHub repository.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">git clone https:\/\/github.com\/kubernetes-sigs\/kubespray.git<\/pre>\r\n\r\n\r\n\r\n<p><strong>As we are setting up an Offline Kubernetes cluster, we have to do<br \/>some required changes in the below file and we have to update<br \/>all the offline binaries over the location.<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">vi kubespray\/roles\/download\/defaults\/main.yml<\/pre>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" class=\"wp-image-12043\" style=\"width: 800px;\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2022\/09\/capture.png?w=942\" alt=\"\" width=\"800\" \/>\r\n<figcaption class=\"wp-element-caption\"><strong>Previous Download file<\/strong><\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-12210\" style=\"width: 796px; height: 279px;\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2022\/10\/ss2.png?w=1024\" alt=\"\" width=\"796\" height=\"279\" \/>\r\n<figcaption class=\"wp-element-caption\"><strong>Updated Download File<\/strong><\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" class=\"wp-image-12045\" style=\"width: 800px;\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2022\/09\/capture2.png?w=1024\" alt=\"\" width=\"800\" \/>\r\n<figcaption class=\"wp-element-caption\"><strong>Nexus View<\/strong><\/figcaption>\r\n<\/figure>\r\n\r\n\r\n\r\n<p><strong>We have to modify all the required URLs as per the directory structure given over Nexus.<\/strong><\/p>\r\n\r\n\r\n\r\n<p style=\"font-size: 16px;\"><strong>2)<\/strong> After Modifying all the Binary URLS we will provide <strong>Root Privileges<\/strong> to all the tasks mentioned in <strong>cluster.yml<\/strong> file.<br \/>cluster.yml<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">cd kubespray\/<\/pre>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">vi cluster.yml<\/pre>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image size-large is-resized\"><img decoding=\"async\" class=\"wp-image-12047\" style=\"width: 800px;\" src=\"https:\/\/opstree.com\/blog\/\/wp-content\/uploads\/2022\/09\/capture3.png?w=902\" alt=\"\" width=\"800\" \/><\/figure>\r\n\r\n\r\n\r\n<p>3) After editing cluster.yml we have to set SELINUX Disabled over each Kubernetes node. We have to run the below command over each server.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">sudo vi \/etc\/selinux\/config<\/pre>\r\n\r\n\r\n\r\n<p><strong>We have to uncomment the line and set<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">SELINUX=disabled<\/pre>\r\n\r\n\r\n\r\n<p>4) After the previous step, we have to turn off the SWAP Memory. For that, we need to edit the \u2018fstab\u2019 file over each K8s node. We have to run the below command over each server.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">sudo vi \/etc\/fstab<\/pre>\r\n\r\n\r\n\r\n<p>Here we have to comment on the line which is having below content:<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">#\/dev\/mapper\/rootVG-swapLV swap swap default     0        0<\/pre>\r\n\r\n\r\n\r\n<p>5) After setting up all the K8s nodes We have to restart the server.<br \/>We have to run this command over all the servers.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">sudo init 6<\/pre>\r\n\r\n\r\n\r\n<p>6) Now we will come back to our jump host and run the below<br \/>commands one by one.<\/p>\r\n\r\n\r\n\r\n<p class=\"has-text-align-left\"><strong>a) Copy &#8216;inventory\/sample&#8217; as &#8216;inventory\/mycluster&#8217;:<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">cp -rfp inventory\/sample inventory\/mycluster<\/pre>\r\n\r\n\r\n\r\n<p><strong>b) Update Ansible inventory file with inventory builder:<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\"><strong>declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)<\/strong><\/pre>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">CONFIG_FILE=inventory\/mycluster\/hosts.yaml python3 contrib\/inventory_builder\/inventory.py ${IPS[@]}<\/pre>\r\n\r\n\r\n\r\n<p><strong>c) Review and change parameters:<\/strong><\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\"><strong>cat inventory\/mycluster\/group_vars\/all\/all.yml<\/strong><\/pre>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">cat inventory\/mycluster\/group_vars\/k8s_cluster\/k8s-cluster.yml<\/pre>\r\n\r\n\r\n\r\n<p>7) Deploy Kubespray with Ansible Playbook<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">ansible-playbook -i inventory\/mycluster\/hosts.yaml --become\r\n--become-user=root cluster.yml<\/pre>\r\n\r\n\r\n\r\n<p class=\"has-bright-red-color has-text-color has-medium-font-size\"><strong>Note: It will take 25-30 mins to run the complete playbook.<\/strong><\/p>\r\n\r\n\r\n\r\n<p>8) After the completion of the playbook we can run the below command over K8s Master Node to check whether all nodes are connected up and running.<\/p>\r\n\r\n\r\n\r\n<pre class=\"wp-block-verse has-white-color has-dark-gray-background-color has-text-color has-background\">sudo \/usr\/local\/bin\/kubectl get nodes -o wide<\/pre>\r\n\r\n\r\n\r\n<p class=\"has-bright-blue-color has-text-color\">It will give you the detail of your Cluster Nodes.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\r\n\r\n\r\n\r\n<p>This is how we can set up <strong>Kubernetes Cluster<\/strong> via <strong>Kubespray<\/strong>. With all that set, we need to add monitoring, tracing, logging, and all the associated operations for troubleshooting. Now as we have reached the end of the blog &#8211; what do you think I could have done something differently? Do comment. Also If you face any sort of issue in setting up the Kubernetes cluster drop a comment. I&#8217;ll be back with Part &#8211; 2 of the blog series where I&#8217;ll discuss setting up the Metrics Server, and Redis Setup.<\/p>\r\n\r\n\r\n\r\n<p><strong>Blog Pundits: <a href=\"https:\/\/www.linkedin.com\/in\/mehul-sharma-devops\/\" target=\"_blank\" rel=\"noreferrer noopener\">Mehul Sharma<\/a> and <a href=\"https:\/\/opstree.com\/blog\/\/author\/sandeep7c51ad81ba\/\" target=\"_blank\" rel=\"noreferrer noopener\">Sandeep Rawat<\/a><\/strong><\/p>\r\n\r\n\r\n\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\r\n\r\n\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\r\n\r\n\r\n<p class=\"has-text-align-center\"><strong>Connect with Us<\/strong><\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-social-links aligncenter is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-1 wp-block-social-links-is-layout-flex\"><li class=\"wp-social-link wp-social-link-linkedin  wp-block-social-link\"><a href=\"https:\/\/www.linkedin.com\/company\/opstree-solutions\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">LinkedIn<\/span><\/a><\/li>\r\n\r\n<li class=\"wp-social-link wp-social-link-youtube  wp-block-social-link\"><a href=\"https:\/\/www.youtube.com\/channel\/UCeLma6SpNYH7jjYKSBNSexw\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">YouTube<\/span><\/a><\/li>\r\n\r\n<li class=\"wp-social-link wp-social-link-github  wp-block-social-link\"><a href=\"https:\/\/github.com\/OpsTree\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">GitHub<\/span><\/a><\/li>\r\n\r\n<li class=\"wp-social-link wp-social-link-facebook  wp-block-social-link\"><a href=\"https:\/\/www.facebook.com\/opstree\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">Facebook<\/span><\/a><\/li>\r\n\r\n<li class=\"wp-social-link wp-social-link-medium  wp-block-social-link\"><a href=\"https:\/\/medium.com\/buildpiper\" class=\"wp-block-social-link-anchor\" target=\"_blank\" rel=\"noopener\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M20.962,7.257l-5.457,8.867l-3.923-6.375l3.126-5.08c0.112-0.182,0.319-0.286,0.527-0.286c0.05,0,0.1,0.008,0.149,0.02 c0.039,0.01,0.078,0.023,0.114,0.041l5.43,2.715l0.006,0.003c0.004,0.002,0.007,0.006,0.011,0.008 C20.971,7.191,20.98,7.227,20.962,7.257z M9.86,8.592v5.783l5.14,2.57L9.86,8.592z M15.772,17.331l4.231,2.115 C20.554,19.721,21,19.529,21,19.016V8.835L15.772,17.331z M8.968,7.178L3.665,4.527C3.569,4.479,3.478,4.456,3.395,4.456 C3.163,4.456,3,4.636,3,4.938v11.45c0,0.306,0.224,0.669,0.498,0.806l4.671,2.335c0.12,0.06,0.234,0.088,0.337,0.088 c0.29,0,0.494-0.225,0.494-0.602V7.231C9,7.208,8.988,7.188,8.968,7.178z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">Medium<\/span><\/a><\/li><\/ul>\r\n","protected":false},"excerpt":{"rendered":"<p>Today, most organizations are moving to Managed Services like EKS (Elastic Kubernetes Services), and AKS (Azure Kubernetes Services), for easier handling of the Kubernetes Cluster. With Managed Kubernetes we do not have to take care of our Master Nodes, cloud providers will be responsible for all Master Nodes and Worker Nodes, freeing up our time. &hellip; <a href=\"https:\/\/opstree.com\/blog\/2022\/10\/25\/on-premise-setup-of-kubernetes-cluster-using-kubespray-offline-mode-part-1\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;On-Premise Setup of Kubernetes Cluster using KubeSpray (Offline Mode) &#8211; PART 1&#8221;<\/span><\/a><\/p>\n","protected":false},"author":215838922,"featured_media":29900,"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":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2}},"categories":[28070474],"tags":[44070,768739308,676319247,768739309,502915258,719458036,586614237,4996032],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/opstree.com\/blog\/wp-content\/uploads\/2025\/11\/DevSecOps-1.jpg","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pfDBOm-36s","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/11932"}],"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\/215838922"}],"replies":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/comments?post=11932"}],"version-history":[{"count":26,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/11932\/revisions"}],"predecessor-version":[{"id":19174,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/posts\/11932\/revisions\/19174"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media\/29900"}],"wp:attachment":[{"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/media?parent=11932"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/categories?post=11932"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/opstree.com\/blog\/wp-json\/wp\/v2\/tags?post=11932"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}