<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:hashnode="https://hashnode.com/rss"><channel><title><![CDATA[thirumurthi]]></title><description><![CDATA[An active learner... tech enthusiast.. Software developer lead..
]]></description><link>https://thirumurthi.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 03 Dec 2024 04:28:38 GMT</lastBuildDate><atom:link href="https://thirumurthi.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><atom:link rel="next" href="https://thirumurthi.hashnode.dev/rss.xml?page=2"/><atom:link rel="previous" href="https://thirumurthi.hashnode.dev/rss.xml"/><item><title><![CDATA[Istio - Kubernetes Gateway API in Kind Cluster]]></title><description><![CDATA[Istio deployed in kind cluster and configured with Kubernetes gateway api with HTTPRoute to access a backend app.]]></description><link>https://thirumurthi.hashnode.dev/istio-kubernetes-gateway-api-in-kind-cluster</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/istio-kubernetes-gateway-api-in-kind-cluster</guid><category><![CDATA[#istio]]></category><category><![CDATA[kind]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[Gateway API]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 01 Sep 2024 20:29:28 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-istio-with-kubernetes-gateway-api&quot;&gt;Istio with Kubernetes Gateway API&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;In this blog have detailed deploying Istio in Kind cluster and configure Kubernetes Gateway API.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker desktop installed and running&lt;/li&gt;&lt;li&gt;Kind CLI&lt;/li&gt;&lt;li&gt;Helm CLI (v3.15.3+)&lt;/li&gt;&lt;li&gt;Understanding of Service Mesh (Istio basics and Gateway API)&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-istio-with-kubernetes-gateway-api-1&quot;&gt;Istio with Kubernetes Gateway API&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/&quot;&gt;Istio documentation&lt;/a&gt; recommends to use Kubernetes Gateway API since the release of version v1.1. &lt;/li&gt;&lt;li&gt;&lt;p&gt;In the Istio Ingress Gateway &lt;code&gt;VirtualService&lt;/code&gt; is created for routing, with Kubernetes Gateway API to route the &lt;code&gt;HTTPRoute&lt;/code&gt; is created that  configures the service of the app.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;To configure Kubernetes Gateway API in Kind cluster the Gateway API CRD should be deployed first. In this example the standard install is used. Referred from &lt;code&gt;https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-summary-of-components-deployed&quot;&gt;Summary of components deployed&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kind cluster creation with configuration. Few ports are exposed to access the apps.&lt;/li&gt;&lt;li&gt;Istio is deployed using helm charts. Istio - &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;istiod&lt;/code&gt; charts are deployed with basic configuration. (Not production ready configuration).&lt;/li&gt;&lt;li&gt;Kiali Server (Istio Dashboard) is deployed using helm charts, configured to use the external services of Prometheus and Grafana deployed on monitor namespace.&lt;/li&gt;&lt;li&gt;Kubernetes Gateway API CRD deployed to cluster.&lt;/li&gt;&lt;li&gt;Gateway API custom resource deployed to cluster.&lt;/li&gt;&lt;li&gt;&lt;code&gt;HTTPRoute&lt;/code&gt; configured and deployed to access the Kiali from browser.&lt;/li&gt;&lt;li&gt;Prometheus community chart deployed which installs Prometheus, Grafana and AlertManager. All the components are deployed in monitor namespace. (Not production ready configuration). Refer &lt;a target=&quot;_blank&quot; href=&quot;https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack&quot;&gt;Chart documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Simple backend-app (NGINX) deployed to serve simple JSON response.&lt;/li&gt;&lt;li&gt;&lt;code&gt;HTTPRoute&lt;/code&gt; configured and deployed to access the backend-app.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Note&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The Istio helm charts are downloaded to local machine and then deployed.&lt;/li&gt;&lt;li&gt;It can also be deployed directly once the repo is added to helm CLI. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://istio.io/latest/docs/setup/install/helm/&quot;&gt;Istio documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-representation-of-the-app-deployed-in-the-kind-cluster&quot;&gt;Representation of the app deployed in the Kind cluster&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/30b72d2e-e316-4dda-b518-8261a284eeb2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-kind-cluster-creation&quot;&gt;Kind Cluster creation&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create Kind cluster named istio-dev with below configuration&lt;/li&gt;&lt;li&gt;Few ports exposed in the configuration&lt;ul&gt;&lt;li&gt;Port 9001 and 9002 used to access the Prometheus and Grafana&lt;/li&gt;&lt;li&gt;8180 exposed to access the gateway from the host machine. Note, once the Gateway service is created it has to be edited to configure the port.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kind-configuration&quot;&gt;Kind configuration&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;worker&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31000&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31043&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31100&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9001&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31110&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9002&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-command-to-create-kind-cluster&quot;&gt;Command to create kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;If the above kind cluster configuration is stored in a file cluster_config.yaml, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kind create cluster --config cluster_config.yaml --name istio-dev&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-istio&quot;&gt;Install Istio&lt;/h3&gt;&lt;h4 id=&quot;heading-download-the-charts-locally&quot;&gt;Download the charts locally&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To add the repo to the helm for the Istio charts&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;helm repo add istio https:&lt;span class=&quot;hljs-comment&quot;&gt;//istio-release.storage.googleapis.com/charts&lt;/span&gt;helm repo update&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The Istio charts are download to &lt;code&gt;charts/&lt;/code&gt; folder. The Istio base and istiod charts to local with below commands&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create and navigate charts foldermkdir charts&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/-- download install helm basehelm pull istio/base --untar-- download install helm istiodhelm pull istio/istiod --untar&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-namespace-to-deploy-the-istio-charts&quot;&gt;Create namespace to deploy the Istio charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create &lt;code&gt;istio-system&lt;/code&gt; namespace with below command, in which the Istio base and istiod charts will be deployed&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl create ns istio-system&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-istio-base-charts&quot;&gt;Deploy the Istio base charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Deploy Istio base charts to kind cluster.&lt;/li&gt;&lt;li&gt;The default revision is deployed in this case by passing &lt;code&gt;default&lt;/code&gt; in value defaultRevision. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- navigate to charts/base&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/basehelm upgrade -i istio-base . -n istio-system --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; defaultRevision=default&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-istio-istiod-charts&quot;&gt;Deploy the Istio istiod charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Deploy Istio istiod, before deploying Istio CRD make sure the Istio base is deployed&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- deploy the Istio/istiod-- navigate to charts/istiod&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/istiodhelm upgrade -i istiod . -n istio-system --&lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-chart-status-check&quot;&gt;Chart status check&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Once Charts are installed the status can be checked using below helm command. Chart status should be deployed. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n istio-systemNAME         NAMESPACE       REVISION   UPDATED                       STATUS          CHART                   APP VERSIONistio-base   istio-system    1          2024-09-01 08:10:11 -0700 PDT deployed        base-1.23.0             1.23.0istiod       istio-system    1          2024-09-01 08:10:28 -0700 PDT deployed        istiod-1.23.0           1.23.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-kuberented-gateway-api&quot;&gt;Deploy Kuberented Gateway API&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To deploy the Gateway API CRD, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-create-and-deploy-gateway-api-custom-resource&quot;&gt;Create and deploy Gateway API custom resource&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The Kubenetes Gateway API custom resource YAML content looks like below (refer &lt;code&gt;kuberenetes-gateway-api.yaml&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;Note, in case of Istio Ingress Gateway the apiVersion would be &lt;code&gt;networking.istio.io/v1alpha3&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# fileName: kuberenetes-gateway-api.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Gateway&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;gatewayClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;#hostname: &quot;127.0.0.1&quot;  # commented here but we can use &quot;*.example.com&quot; refer docs&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTP&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;allowedRoutes:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespaces:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;from:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;All&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-deploy-the-gateway-api-resource&quot;&gt;Deploy the Gateway API resource&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Create namespace &lt;code&gt;istio-ingress&lt;/code&gt; and deploy the Gateway resource, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create namespace &lt;span class=&quot;hljs-built_in&quot;&gt;command&lt;/span&gt;kubectl create ns istio-ingress-- deploy the gateway api resourcekubectl apply -f kuberenetes-gateway-api.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once the Gateway is deployed, to validate and check the status of the service use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl -n istio-ingress get svc&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Output might look like below with random nodeports assigned&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                        AGEgateway-istio   LoadBalancer   &lt;span class=&quot;hljs-number&quot;&gt;10.96&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.201&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.160&lt;/span&gt;   &amp;lt;pending&amp;gt;     &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32753&lt;/span&gt;/TCP,&lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;30526&lt;/span&gt;/TCP   &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;m20s&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-edit-the-gateway-api-service-to-update-the-nodeport-to-match-kind-cluster-configuration&quot;&gt;Edit the Gateway API service to update the nodePort to match Kind cluster configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Edit the Gateway service using &lt;code&gt;kubectl -n istio-ingress edit svc/gateway-istio&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The nodePort(s) has to be updated like in below snippet.&lt;/li&gt;&lt;li&gt;The incoming traffic from port 8180 will be routed to 31000 nodePort, already updated in Kind cluster configuration.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ipFamilies:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IPv4&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ipFamilyPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SingleStack&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;appProtocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;tcp&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;status-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31021&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;#&amp;lt;--- update to 31021 port not used for this example&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;appProtocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31000&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;--- update this port from any to 31000 configured in kind config&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-kiali-server&quot;&gt;Deploy Kiali Server&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To deploy the Kiali server using helm chart, add the repo to helm CLI and download to local charts folder.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- add repo to the helm clihelm repo add kiali https://kiali.org/helm-chartshelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Navigate to charts folder and download the charts to local.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/helm pull kiali/kiali-server --untar&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Execute below command from the downloaded charts folder kaili-server.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The external_service urls are configured to access the Prometheus and Grafana. These components will be deployed by single chart later.&lt;/li&gt;&lt;li&gt;The components are deployed to monitor namespace, hence the url pattern is &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;:port&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm upgrade -i kiali-server . \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; auth.strategy=&lt;span class=&quot;hljs-string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.prometheus.url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-operated.monitor:9090&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.grafana.url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-grafana.monitor:80&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.grafana.in_cluster_url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-grafana.monitor:80&quot;&lt;/span&gt; \-n istio-system&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Verify status of the chart deployment and the status might look like below &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n istio-systemNAME         NAMESPACE      REVISION   UPDATED                       STATUS          CHART                   APP VERSIONistio-base   istio-system    1         2024-09-01 08:10:11 -0700 PDT deployed        base-1.23.0             1.23.0istiod       istio-system    1         2024-09-01 08:10:28 -0700 PDT deployed        istiod-1.23.0           1.23.0kiali-server istio-system    1         2024-09-01 08:34:58 -0700 PDT deployed        kiali-server-1.89.0     v1.89.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-httproute-resource-to-access-kiali-server&quot;&gt;Create HTTPRoute resource to access Kiali server&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Create HTTPRoute resource for kiali as shown in the below yaml content, save the config in a file named &lt;code&gt;kiali-http-route.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: kiali-http-route.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTPRoute&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kiali-http&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-system&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;parentRefs:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;hostnames:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;]  &lt;span class=&quot;hljs-comment&quot;&gt;# without hostname the service would not be accessible&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;matches:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PathPrefix&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/kiali&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;backendRefs:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kiali&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20001&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-deploy-kiali-httproute&quot;&gt;Deploy Kiali HTTPRoute&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;To deploy the kiali route use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- the resource will be deployed to istio-system namespace and uses the Gateway API previously deployedkubectl apply -f kiali-http-route.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-accessing-kiali-from-browser&quot;&gt;Accessing Kiali from browser&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The address to access the Kiali UI is - &lt;code&gt;http://127.0.0.1:8180/kiali&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The Kiali UI looks like in below snapshot. The Nginx backend app, Prometheus and Grafana where deployed here in the snapshot.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/2b7c821d-9646-4c51-9b04-e4816b6dda3e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ce544224-2814-4a44-afac-22484337685d&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/19ae2aba-fd4d-4ae8-9829-b27563679cf2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-Kiali UI might throw warning messages if the Prometheus chart is not deployed.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-deploy-prometheus&quot;&gt;Deploy Prometheus&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Add repo to helm local and download the chart to local charts folder&lt;/li&gt;&lt;li&gt;Note, below is not a production ready configuration, requires further hardening through configuration. Refer documentation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/helm pull prometheus-community/kube-prometheus-stack --untar&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-namespace-and-deploy-the-charts-to-kind-cluster&quot;&gt;Create namespace and deploy the charts to Kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create namespace monitor and deploy Prometheus, use below set of commands&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create namespacekubectl create ns monitor-- navigate to downloaded charts&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/kube-prometheus-stack-- deploy prometheushelm upgrade -i prometheus . \--namespace monitor \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus.service.nodePort=31100 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; grafana.service.nodePort=31110 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; grafana.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; alertmanager.service.nodePort=31120 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; alertmanager.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus-node-exporter.service.nodePort=31130 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus-node-exporter.service.type=NodePort&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-status-check-of-prometheus-chart-deployment&quot;&gt;Status check of Prometheus chart deployment&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Verify the status of chart deployment use the helm command mentioned below and the output of the status will be similar to below snippet.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n monitorNAME        NAMESPACE   REVISION  UPDATED                       STATUS    CHART                           APP VERSIONprometheus  monitor     1         2024-09-01 08:43:38 -0700 PDT deployed  kube-prometheus-stack-62.3.1    v0.76.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-access-prometheus-and-grafana&quot;&gt;Access Prometheus and Grafana&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Accessing Prometheus&lt;ul&gt;&lt;li&gt;To access the Prometheus use &lt;code&gt;http://127.0.0.1:9001/&lt;/code&gt; or &lt;code&gt;http://localhost:9001&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/3a8fca83-e7d9-4458-a1aa-afbdcc9fd557&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Accessing Grafana&lt;ul&gt;&lt;li&gt;To access the Grafana use &lt;code&gt;http://127.0.0.1:9002/&lt;/code&gt; or &lt;code&gt;http://localhost:9002&lt;/code&gt;, when prompted use username: &lt;code&gt;admin&lt;/code&gt; and password: &lt;code&gt;prom-operator&lt;/code&gt;.&lt;img src=&quot;https://github.com/user-attachments/assets/15b02a2b-d40d-46e1-9eab-a1454136cb5f&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/eee9ee05-fca4-4b08-857d-ace56c48f85c&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-creating-the-ngnix-backend-app&quot;&gt;Creating the NGNIX backend app&lt;/h3&gt;&lt;h4 id=&quot;heading-deploy-the-backend-app-to-kind-cluster&quot;&gt;Deploy the backend app to kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below YAML content is resource defintion for the backend apps including namespace, service and deployment.&lt;/li&gt;&lt;li&gt;The namespace label &lt;code&gt;istio-injection: enabled&lt;/code&gt; will automatically create the Istio Proxy when the backend pod is created.&lt;/li&gt;&lt;li&gt;Save the YAML content to a file named &lt;code&gt;backend_app_deployment.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: backend_app_deployment.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;istio-injection:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;nginx.conf:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    worker_processes auto;    error_log stderr notice;    events {      worker_connections 1024;    }    http {      variables_hash_max_size 1024;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;$remote_addr - $remote_user [%time_local] &quot;$request&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;off;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;real_ip_header&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;X-Real-IP;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;utf-8;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;server&lt;/span&gt; {        &lt;span class=&quot;hljs-string&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;hljs-string&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt; {          &lt;span class=&quot;hljs-string&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application/json;&lt;/span&gt;          &lt;span class=&quot;hljs-string&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;status&quot;:&quot;OK&quot;,&quot;message&quot;:&quot;Greetings!! from server&quot;,&quot;current_time&quot;:&quot;$time_iso8601&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        }      }    &lt;span class=&quot;hljs-string&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;         &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt;           &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;         &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;requests:&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;128Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;250m&quot;&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;limits:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;256Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;500m&quot;&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;tcp-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To deploy the backend app issue below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- the namespace will be created note, the label istio-injection is enabled &lt;span class=&quot;hljs-built_in&quot;&gt;which&lt;/span&gt; will create a envoy proxy sidecar automatically kubectl apply -f backend_app_deployment.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-define-httproute-for-the-backend-app&quot;&gt;Define HTTPRoute for the backend app&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To access the backend we need to define a HTTPRoute like below and save it to a file named &lt;code&gt;app-httproute.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# app-httproute.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTPRoute&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;parentRefs:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;hostnames:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;matches:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PathPrefix&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;backendRefs:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To deploy the HTTPRoute use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f app-httproute.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-access-the-backend-app-api&quot;&gt;Access the Backend app API&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;From browser use &lt;code&gt;http://127.0.0.1:8180/greet&lt;/code&gt; should see the response like below&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/4948d4c0-8e33-40bb-9c89-8ac0885c3cdd&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-istio-with-kubernetes-gateway-api&quot;&gt;Istio with Kubernetes Gateway API&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;In this blog have detailed deploying Istio in Kind cluster and configure Kubernetes Gateway API.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker desktop installed and running&lt;/li&gt;&lt;li&gt;Kind CLI&lt;/li&gt;&lt;li&gt;Helm CLI (v3.15.3+)&lt;/li&gt;&lt;li&gt;Understanding of Service Mesh (Istio basics and Gateway API)&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-istio-with-kubernetes-gateway-api-1&quot;&gt;Istio with Kubernetes Gateway API&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/&quot;&gt;Istio documentation&lt;/a&gt; recommends to use Kubernetes Gateway API since the release of version v1.1. &lt;/li&gt;&lt;li&gt;&lt;p&gt;In the Istio Ingress Gateway &lt;code&gt;VirtualService&lt;/code&gt; is created for routing, with Kubernetes Gateway API to route the &lt;code&gt;HTTPRoute&lt;/code&gt; is created that  configures the service of the app.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;To configure Kubernetes Gateway API in Kind cluster the Gateway API CRD should be deployed first. In this example the standard install is used. Referred from &lt;code&gt;https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-summary-of-components-deployed&quot;&gt;Summary of components deployed&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kind cluster creation with configuration. Few ports are exposed to access the apps.&lt;/li&gt;&lt;li&gt;Istio is deployed using helm charts. Istio - &lt;code&gt;base&lt;/code&gt; and &lt;code&gt;istiod&lt;/code&gt; charts are deployed with basic configuration. (Not production ready configuration).&lt;/li&gt;&lt;li&gt;Kiali Server (Istio Dashboard) is deployed using helm charts, configured to use the external services of Prometheus and Grafana deployed on monitor namespace.&lt;/li&gt;&lt;li&gt;Kubernetes Gateway API CRD deployed to cluster.&lt;/li&gt;&lt;li&gt;Gateway API custom resource deployed to cluster.&lt;/li&gt;&lt;li&gt;&lt;code&gt;HTTPRoute&lt;/code&gt; configured and deployed to access the Kiali from browser.&lt;/li&gt;&lt;li&gt;Prometheus community chart deployed which installs Prometheus, Grafana and AlertManager. All the components are deployed in monitor namespace. (Not production ready configuration). Refer &lt;a target=&quot;_blank&quot; href=&quot;https://artifacthub.io/packages/helm/prometheus-community/kube-prometheus-stack&quot;&gt;Chart documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Simple backend-app (NGINX) deployed to serve simple JSON response.&lt;/li&gt;&lt;li&gt;&lt;code&gt;HTTPRoute&lt;/code&gt; configured and deployed to access the backend-app.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Note&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The Istio helm charts are downloaded to local machine and then deployed.&lt;/li&gt;&lt;li&gt;It can also be deployed directly once the repo is added to helm CLI. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://istio.io/latest/docs/setup/install/helm/&quot;&gt;Istio documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-representation-of-the-app-deployed-in-the-kind-cluster&quot;&gt;Representation of the app deployed in the Kind cluster&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/30b72d2e-e316-4dda-b518-8261a284eeb2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-kind-cluster-creation&quot;&gt;Kind Cluster creation&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create Kind cluster named istio-dev with below configuration&lt;/li&gt;&lt;li&gt;Few ports exposed in the configuration&lt;ul&gt;&lt;li&gt;Port 9001 and 9002 used to access the Prometheus and Grafana&lt;/li&gt;&lt;li&gt;8180 exposed to access the gateway from the host machine. Note, once the Gateway service is created it has to be edited to configure the port.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kind-configuration&quot;&gt;Kind configuration&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;worker&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31000&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31043&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31100&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9001&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31110&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9002&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-command-to-create-kind-cluster&quot;&gt;Command to create kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;If the above kind cluster configuration is stored in a file cluster_config.yaml, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kind create cluster --config cluster_config.yaml --name istio-dev&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-istio&quot;&gt;Install Istio&lt;/h3&gt;&lt;h4 id=&quot;heading-download-the-charts-locally&quot;&gt;Download the charts locally&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To add the repo to the helm for the Istio charts&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;helm repo add istio https:&lt;span class=&quot;hljs-comment&quot;&gt;//istio-release.storage.googleapis.com/charts&lt;/span&gt;helm repo update&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The Istio charts are download to &lt;code&gt;charts/&lt;/code&gt; folder. The Istio base and istiod charts to local with below commands&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create and navigate charts foldermkdir charts&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/-- download install helm basehelm pull istio/base --untar-- download install helm istiodhelm pull istio/istiod --untar&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-namespace-to-deploy-the-istio-charts&quot;&gt;Create namespace to deploy the Istio charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create &lt;code&gt;istio-system&lt;/code&gt; namespace with below command, in which the Istio base and istiod charts will be deployed&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl create ns istio-system&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-istio-base-charts&quot;&gt;Deploy the Istio base charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Deploy Istio base charts to kind cluster.&lt;/li&gt;&lt;li&gt;The default revision is deployed in this case by passing &lt;code&gt;default&lt;/code&gt; in value defaultRevision. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- navigate to charts/base&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/basehelm upgrade -i istio-base . -n istio-system --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; defaultRevision=default&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-istio-istiod-charts&quot;&gt;Deploy the Istio istiod charts&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Deploy Istio istiod, before deploying Istio CRD make sure the Istio base is deployed&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- deploy the Istio/istiod-- navigate to charts/istiod&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/istiodhelm upgrade -i istiod . -n istio-system --&lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-chart-status-check&quot;&gt;Chart status check&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Once Charts are installed the status can be checked using below helm command. Chart status should be deployed. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n istio-systemNAME         NAMESPACE       REVISION   UPDATED                       STATUS          CHART                   APP VERSIONistio-base   istio-system    1          2024-09-01 08:10:11 -0700 PDT deployed        base-1.23.0             1.23.0istiod       istio-system    1          2024-09-01 08:10:28 -0700 PDT deployed        istiod-1.23.0           1.23.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-kuberented-gateway-api&quot;&gt;Deploy Kuberented Gateway API&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To deploy the Gateway API CRD, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-create-and-deploy-gateway-api-custom-resource&quot;&gt;Create and deploy Gateway API custom resource&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The Kubenetes Gateway API custom resource YAML content looks like below (refer &lt;code&gt;kuberenetes-gateway-api.yaml&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;Note, in case of Istio Ingress Gateway the apiVersion would be &lt;code&gt;networking.istio.io/v1alpha3&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# fileName: kuberenetes-gateway-api.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Gateway&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;gatewayClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;#hostname: &quot;127.0.0.1&quot;  # commented here but we can use &quot;*.example.com&quot; refer docs&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTP&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;allowedRoutes:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespaces:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;from:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;All&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-deploy-the-gateway-api-resource&quot;&gt;Deploy the Gateway API resource&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Create namespace &lt;code&gt;istio-ingress&lt;/code&gt; and deploy the Gateway resource, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create namespace &lt;span class=&quot;hljs-built_in&quot;&gt;command&lt;/span&gt;kubectl create ns istio-ingress-- deploy the gateway api resourcekubectl apply -f kuberenetes-gateway-api.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once the Gateway is deployed, to validate and check the status of the service use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl -n istio-ingress get svc&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Output might look like below with random nodeports assigned&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                        AGEgateway-istio   LoadBalancer   &lt;span class=&quot;hljs-number&quot;&gt;10.96&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.201&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.160&lt;/span&gt;   &amp;lt;pending&amp;gt;     &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;32753&lt;/span&gt;/TCP,&lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;30526&lt;/span&gt;/TCP   &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;m20s&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-edit-the-gateway-api-service-to-update-the-nodeport-to-match-kind-cluster-configuration&quot;&gt;Edit the Gateway API service to update the nodePort to match Kind cluster configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Edit the Gateway service using &lt;code&gt;kubectl -n istio-ingress edit svc/gateway-istio&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The nodePort(s) has to be updated like in below snippet.&lt;/li&gt;&lt;li&gt;The incoming traffic from port 8180 will be routed to 31000 nodePort, already updated in Kind cluster configuration.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ipFamilies:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IPv4&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ipFamilyPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SingleStack&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;appProtocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;tcp&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;status-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31021&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;#&amp;lt;--- update to 31021 port not used for this example&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15021&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;appProtocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31000&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;--- update this port from any to 31000 configured in kind config&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-kiali-server&quot;&gt;Deploy Kiali Server&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To deploy the Kiali server using helm chart, add the repo to helm CLI and download to local charts folder.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- add repo to the helm clihelm repo add kiali https://kiali.org/helm-chartshelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Navigate to charts folder and download the charts to local.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/helm pull kiali/kiali-server --untar&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Execute below command from the downloaded charts folder kaili-server.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The external_service urls are configured to access the Prometheus and Grafana. These components will be deployed by single chart later.&lt;/li&gt;&lt;li&gt;The components are deployed to monitor namespace, hence the url pattern is &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;:port&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm upgrade -i kiali-server . \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; auth.strategy=&lt;span class=&quot;hljs-string&quot;&gt;&quot;anonymous&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.prometheus.url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-operated.monitor:9090&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.grafana.url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-grafana.monitor:80&quot;&lt;/span&gt; \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; external_services.grafana.in_cluster_url=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://prometheus-grafana.monitor:80&quot;&lt;/span&gt; \-n istio-system&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Verify status of the chart deployment and the status might look like below &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n istio-systemNAME         NAMESPACE      REVISION   UPDATED                       STATUS          CHART                   APP VERSIONistio-base   istio-system    1         2024-09-01 08:10:11 -0700 PDT deployed        base-1.23.0             1.23.0istiod       istio-system    1         2024-09-01 08:10:28 -0700 PDT deployed        istiod-1.23.0           1.23.0kiali-server istio-system    1         2024-09-01 08:34:58 -0700 PDT deployed        kiali-server-1.89.0     v1.89.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-httproute-resource-to-access-kiali-server&quot;&gt;Create HTTPRoute resource to access Kiali server&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Create HTTPRoute resource for kiali as shown in the below yaml content, save the config in a file named &lt;code&gt;kiali-http-route.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: kiali-http-route.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTPRoute&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kiali-http&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-system&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;parentRefs:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;hostnames:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;]  &lt;span class=&quot;hljs-comment&quot;&gt;# without hostname the service would not be accessible&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;matches:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PathPrefix&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/kiali&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;backendRefs:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kiali&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20001&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-deploy-kiali-httproute&quot;&gt;Deploy Kiali HTTPRoute&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;To deploy the kiali route use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- the resource will be deployed to istio-system namespace and uses the Gateway API previously deployedkubectl apply -f kiali-http-route.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-accessing-kiali-from-browser&quot;&gt;Accessing Kiali from browser&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The address to access the Kiali UI is - &lt;code&gt;http://127.0.0.1:8180/kiali&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The Kiali UI looks like in below snapshot. The Nginx backend app, Prometheus and Grafana where deployed here in the snapshot.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/2b7c821d-9646-4c51-9b04-e4816b6dda3e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/ce544224-2814-4a44-afac-22484337685d&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/19ae2aba-fd4d-4ae8-9829-b27563679cf2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-Kiali UI might throw warning messages if the Prometheus chart is not deployed.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-deploy-prometheus&quot;&gt;Deploy Prometheus&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Add repo to helm local and download the chart to local charts folder&lt;/li&gt;&lt;li&gt;Note, below is not a production ready configuration, requires further hardening through configuration. Refer documentation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo update&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/helm pull prometheus-community/kube-prometheus-stack --untar&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-namespace-and-deploy-the-charts-to-kind-cluster&quot;&gt;Create namespace and deploy the charts to Kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create namespace monitor and deploy Prometheus, use below set of commands&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- create namespacekubectl create ns monitor-- navigate to downloaded charts&lt;span class=&quot;hljs-built_in&quot;&gt;cd&lt;/span&gt; charts/kube-prometheus-stack-- deploy prometheushelm upgrade -i prometheus . \--namespace monitor \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus.service.nodePort=31100 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; grafana.service.nodePort=31110 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; grafana.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; alertmanager.service.nodePort=31120 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; alertmanager.service.type=NodePort \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus-node-exporter.service.nodePort=31130 \--&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; prometheus-node-exporter.service.type=NodePort&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-status-check-of-prometheus-chart-deployment&quot;&gt;Status check of Prometheus chart deployment&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Verify the status of chart deployment use the helm command mentioned below and the output of the status will be similar to below snippet.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;$ helm ls -n monitorNAME        NAMESPACE   REVISION  UPDATED                       STATUS    CHART                           APP VERSIONprometheus  monitor     1         2024-09-01 08:43:38 -0700 PDT deployed  kube-prometheus-stack-62.3.1    v0.76.0&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-access-prometheus-and-grafana&quot;&gt;Access Prometheus and Grafana&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Accessing Prometheus&lt;ul&gt;&lt;li&gt;To access the Prometheus use &lt;code&gt;http://127.0.0.1:9001/&lt;/code&gt; or &lt;code&gt;http://localhost:9001&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/3a8fca83-e7d9-4458-a1aa-afbdcc9fd557&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Accessing Grafana&lt;ul&gt;&lt;li&gt;To access the Grafana use &lt;code&gt;http://127.0.0.1:9002/&lt;/code&gt; or &lt;code&gt;http://localhost:9002&lt;/code&gt;, when prompted use username: &lt;code&gt;admin&lt;/code&gt; and password: &lt;code&gt;prom-operator&lt;/code&gt;.&lt;img src=&quot;https://github.com/user-attachments/assets/15b02a2b-d40d-46e1-9eab-a1454136cb5f&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/eee9ee05-fca4-4b08-857d-ace56c48f85c&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-creating-the-ngnix-backend-app&quot;&gt;Creating the NGNIX backend app&lt;/h3&gt;&lt;h4 id=&quot;heading-deploy-the-backend-app-to-kind-cluster&quot;&gt;Deploy the backend app to kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below YAML content is resource defintion for the backend apps including namespace, service and deployment.&lt;/li&gt;&lt;li&gt;The namespace label &lt;code&gt;istio-injection: enabled&lt;/code&gt; will automatically create the Istio Proxy when the backend pod is created.&lt;/li&gt;&lt;li&gt;Save the YAML content to a file named &lt;code&gt;backend_app_deployment.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: backend_app_deployment.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;istio-injection:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;nginx.conf:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    worker_processes auto;    error_log stderr notice;    events {      worker_connections 1024;    }    http {      variables_hash_max_size 1024;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;$remote_addr - $remote_user [%time_local] &quot;$request&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;off;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;real_ip_header&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;X-Real-IP;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;utf-8;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;server&lt;/span&gt; {        &lt;span class=&quot;hljs-string&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;hljs-string&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt; {          &lt;span class=&quot;hljs-string&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application/json;&lt;/span&gt;          &lt;span class=&quot;hljs-string&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;status&quot;:&quot;OK&quot;,&quot;message&quot;:&quot;Greetings!! from server&quot;,&quot;current_time&quot;:&quot;$time_iso8601&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        }      }    &lt;span class=&quot;hljs-string&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;         &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt;           &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;         &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;requests:&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;128Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;250m&quot;&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;limits:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;256Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;500m&quot;&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;tcp-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To deploy the backend app issue below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;-- the namespace will be created note, the label istio-injection is enabled &lt;span class=&quot;hljs-built_in&quot;&gt;which&lt;/span&gt; will create a envoy proxy sidecar automatically kubectl apply -f backend_app_deployment.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-define-httproute-for-the-backend-app&quot;&gt;Define HTTPRoute for the backend app&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To access the backend we need to define a HTTPRoute like below and save it to a file named &lt;code&gt;app-httproute.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# app-httproute.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway.networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;HTTPRoute&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;parentRefs:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;gateway&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;istio-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;hostnames:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;matches:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PathPrefix&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;backendRefs:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To deploy the HTTPRoute use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f app-httproute.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-access-the-backend-app-api&quot;&gt;Access the Backend app API&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;From browser use &lt;code&gt;http://127.0.0.1:8180/greet&lt;/code&gt; should see the response like below&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/4948d4c0-8e33-40bb-9c89-8ac0885c3cdd&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Observability - Jaeger Distributed Tracings]]></title><description><![CDATA[Spring boot micrometer configured to create traces and spans. The Jaeger UI to display the traces with span that where manually created between application]]></description><link>https://thirumurthi.hashnode.dev/observability-jaeger-distributed-tracings</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/observability-jaeger-distributed-tracings</guid><category><![CDATA[jaeger]]></category><category><![CDATA[observability]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Mon, 26 Aug 2024 00:06:10 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-create-trace-and-spans-manually-in-spring-boot-applications&quot;&gt;Create trace and spans manually in spring boot applications&lt;/h2&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Jaeger installed and running (in this example deployed in kind cluster)&lt;/li&gt;&lt;li&gt;Understanding on traces and spans&lt;/li&gt;&lt;li&gt;Understanding on micrometer Spring configuration&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-requirement&quot;&gt;Requirement&lt;/h3&gt;&lt;p&gt;This blog details on how to create spans manually in Spring Boot application. This is based on a requirement in a project, to track the flow between application using Jaeger. To create the traces and spans manually so it can visualized in Jaeger UI and helps the business process on how much time it takes.&lt;/p&gt;&lt;p&gt;In order to demonstrate we have two Spring Boot application, use the tracer object configured in Spring boot to create the spans. The spans set with name with additional tags which is key value pair which can be viewed in Jaeger UI. In the example, the application named &lt;code&gt;invoker-app&lt;/code&gt; exposes a REST API (&lt;code&gt;/api/v2/execute&lt;/code&gt;), when invoked calls the REST API (&lt;code&gt;/app/run?traceId=xxx&amp;amp;spanId=yyy&lt;/code&gt;) of second application named &lt;code&gt;app-1&lt;/code&gt;. The &lt;code&gt;app-1&lt;/code&gt; application uses the traceId and spanId to create a trace context and adds to the current tracer.&lt;/p&gt;&lt;p&gt;The code snippet below is in app-1 application which creates traceContext with the traceId and spanId. The created traceContext is set to the configured tracer objects current Tracer Context scope. &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; contextWithCustomTraceId = tracer.traceContextBuilder()                    .traceId(traceId)                    .spanId(spanId)                    .sampled(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;)                    .build();&lt;span class=&quot;hljs-comment&quot;&gt;// use traceContext as a newScope&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; sc = tracer.currentTraceContext().newScope(contextWithCustomTraceId)) { &lt;span class=&quot;hljs-comment&quot;&gt;// create spans process any operation&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Representation of the REST API invocation between the apps, in this case invoker-app and app-1.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/589948c3-6365-4cce-a33d-bdf6adf19937&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;The expected flow from Jager UI looks like below, where the invoker-app span and app-1 span can be seen as child spans.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/551914ef-659a-4464-bea2-c0604727ff20&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Span with the tag added during creation.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/8e7ae5a0-9361-48e1-baaa-c82bb11d67d9&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;h4 id=&quot;heading-invoker-app&quot;&gt;Invoker app&lt;/h4&gt;&lt;p&gt;Below is the pom.xml with dependencies. Note the dependencies are same for both invoker-app and app-1 only change is the name of the apps.When using &lt;a target=&quot;_blank&quot; href=&quot;https://start.spring.io&quot;&gt;Spring starter&lt;/a&gt; create two projects, just copy paste the dependencies section. &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.3.2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.trace&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;invoker&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;invoker&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo project for Spring Boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;licenses&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;license&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;licenses&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developers&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developer&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;developers&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scm&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;connection&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developerConnection&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;tag&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scm&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;22&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-actuator&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing-bridge-brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;brave-instrumentation-okhttp3&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.reporter2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;zipkin-sender-urlconnection&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.reporter2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;zipkin-reporter-brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencyManagement&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing-bom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;${micrometer-tracing.version}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;import&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;brave-bom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;${brave.version}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;import&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencyManagement&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The application.yaml for the spring boot application, which includes the tracing endpoint url&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;management:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9145&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;sampling:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;probability:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zipkin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;endpoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;http://localhost:9411/api/v2/spans&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-invoker-app-controller&quot;&gt;Invoker app controller&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The invoker app uses the RestTemplate to create the REST API GET request to access the app-1 app.&lt;/li&gt;&lt;li&gt;The traceId and spandId is obtained from the tracer object configured and created by the Spring boot application during deployment.&lt;/li&gt;&lt;li&gt;The use of Random class to induce additional random delay after the span is created just for demonstration to view it in Jaeger UI.```javapackage com.trace.invoker;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;import io.micrometer.tracing.Span;import io.micrometer.tracing.Tracer;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.web.client.RestTemplateBuilder;import org.springframework.http.*;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;&lt;/p&gt;&lt;p&gt;import java.util.Random;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;&lt;/p&gt;&lt;p&gt;@RestController@RequestMapping(&quot;/api/v2/&quot;)@Slf4jpublic class AppInvokerController {&lt;/p&gt;&lt;p&gt;    private final Tracer tracer;&lt;/p&gt;&lt;p&gt;    AppInvokerController(Tracer tracer){        this.tracer = tracer;    }&lt;/p&gt;&lt;p&gt;    @GetMapping(&quot;/execute&quot;)    public String invokeTask() {&lt;/p&gt;&lt;p&gt;        // new span        Span span1 = tracer.nextSpan().name(&quot;invoker-api-parent&quot;).start();        // URL for second app app-1 application        String APPURL = &quot;http://localhost:8082/app/v1/run?traceId=%s&amp;amp;spanId=%s&quot;;        String traceId = tracer.currentSpan().context().traceId();        String spanId = span1.context().spanId();        String url = String.format(APPURL,traceId,spanId);&lt;/p&gt;&lt;p&gt;        RestTemplate clientTemplate = new RestTemplate();        log.info(&quot;tracer invoked app-1 invoked&quot;);&lt;/p&gt;&lt;p&gt;        HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.setContentType(MediaType.TEXT_PLAIN);&lt;/p&gt;&lt;p&gt;        HttpEntity request = new HttpEntity&amp;lt;&amp;gt;(&quot;&quot;,httpHeaders);&lt;/p&gt;&lt;p&gt;        try (Tracer.SpanInScope spanInScope = tracer.withSpan(span1.name(&quot;invoke-api&quot;).start())) {            span1.tag(&quot;appName&quot;,&quot;invokeApi&quot;);            span1.event(&quot;invoked from invoker api&quot;);            ResponseEntity response =                    clientTemplate.postForEntity(url,null,String.class);            log.info(&quot;response {}&quot;,response.getBody());&lt;/p&gt;&lt;p&gt;        }finally {            span1.end();        }        // New span- just for example to demonstrate the last step in invoker-app        Span span2 = tracer.nextSpan().name(&quot;last step&quot;).start();        span2.event(&quot;completed&quot;);        span2.tag(&quot;app&quot;,&quot;invoker&quot;);        try{            Thread.sleep(700);        } catch (InterruptedException e) {            log.warn(&quot;Interrupted exception&quot;);        }        span2.end();        return &quot;completed&quot;;    }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;pre&gt;&lt;code&gt;- RestTemplate bean is used by the tracer object to publish the trace and span to Jaeger server.&lt;span class=&quot;hljs-string&quot;&gt;``&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;`javapackage com.trace.invoker;import org.springframework.boot.web.client.RestTemplateBuilder;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;public class AppConfig {    @Bean    RestTemplate restTemplate(RestTemplateBuilder builder){        return builder.build();    }}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Application entry point usually class created by the spring starter itself.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.invoker;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvokerApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(InvokerApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-app-1-application&quot;&gt;app-1 application&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The pom.xml with dependencies is same as the invoker-app dependencies. The only change would be the name and artifactId.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The app-1 controller code,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;With the provided traceId and spandId a new tracerContext is build and added to the current tracer context scope.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;sampleThreadInvocation()&lt;/code&gt; uses Task Callable class (note, we can use Runnable as well) to run set of thread in parallel and create child spans with provided parent span&lt;/li&gt;&lt;li&gt;The &lt;code&gt;additionalProcess()&lt;/code&gt; method demonstrates creating the spans outside the thread.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Callable;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.ExecutorService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Executors;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/app/v1&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Tracer tracer;    Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    AppController(Tracer tracer){        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.tracer = tracer;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@PostMapping(&quot;/run&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam&lt;/span&gt; String traceId,                          &lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam&lt;/span&gt; String spanId)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;// traceId and spanId can&apos;t be null&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(!Objects.isNull(traceId) &amp;amp;&amp;amp; !Objects.isNull(spanId) ) {            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;traceId included - {}&quot;&lt;/span&gt;, traceId);           &lt;span class=&quot;hljs-comment&quot;&gt;// create trace context with teh traceId and spanId&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; contextWithCustomTraceId = tracer.traceContextBuilder()                    .traceId(traceId)                    .spanId(spanId)                    .sampled(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;)                    .build();            &lt;span class=&quot;hljs-comment&quot;&gt;// set the tracercontext to current trace context scope&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; sc = tracer.currentTraceContext().newScope(contextWithCustomTraceId)) {               &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; span =  tracer.spanBuilder().name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app-one-tracing&quot;&lt;/span&gt;).start();                &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(Tracer.SpanInScope spanInScope= tracer.withSpan(span)) {                    span.tag(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;run invoked&quot;&lt;/span&gt;);                    log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;tracing logs...&quot;&lt;/span&gt;);                    sleep(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;750&lt;/span&gt;));                    sampleThreadInvocation();                    additionalProcess(&lt;span class=&quot;hljs-string&quot;&gt;&quot;process-1&quot;&lt;/span&gt;);                    additionalProcess(&lt;span class=&quot;hljs-string&quot;&gt;&quot;process-2&quot;&lt;/span&gt;);                }&lt;span class=&quot;hljs-keyword&quot;&gt;finally&lt;/span&gt; {                    span.end();                }            }        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;completed invocation&quot;&lt;/span&gt;;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;additionalProcess&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String name)&lt;/span&gt;&lt;/span&gt;{        Span span = tracer.nextSpan(tracer.currentSpan());        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(Tracer.SpanInScope spanInScope= tracer.withSpan(span.name(name).start())){            SpanHelper spanHelper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; SpanHelper();            Span innerSpan = spanHelper.createSpan(tracer,span,&lt;span class=&quot;hljs-string&quot;&gt;&quot;ap-&quot;&lt;/span&gt;+name,&lt;span class=&quot;hljs-string&quot;&gt;&quot;proceed&quot;&lt;/span&gt;);            sleep(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;1100&lt;/span&gt;));            spanHelper.endSpan(innerSpan);            spanHelper.endSpan(span);        }    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sampleThreadInvocation&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;api invoked..&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(ExecutorService executor = Executors.newFixedThreadPool(&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;)) {            Span span = tracer.currentSpan();&lt;span class=&quot;hljs-comment&quot;&gt;//.name(&quot;api-parent&quot;).start();//currentSpan();&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;; i++) {                &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (Tracer.SpanInScope spanInScope = tracer.withSpan(span)) {                    Callable&amp;lt;Void&amp;gt; caller = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Task(tracer, span, &lt;span class=&quot;hljs-string&quot;&gt;&quot;task&quot;&lt;/span&gt; + i, random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;750&lt;/span&gt;), &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;);                    executor.submit(caller);                }            }            executor.shutdown();            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!executor.awaitTermination(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;, TimeUnit.SECONDS)) {                    executor.shutdownNow();                }            } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (InterruptedException interruptedException) {                executor.shutdownNow();            }        }        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;completed&quot;&lt;/span&gt;);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; duration)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {            Thread.sleep(duration);        } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (InterruptedException e) {            log.warn(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sleep interrupted&quot;&lt;/span&gt;);        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below is Task class just used to demonstrate the use of parallel threads and span creation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Callable;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Callable&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Void&lt;/span&gt;&amp;gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Tracer tracer;    SpanHelper spanHelper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; SpanHelper();    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Span span;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; String name;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; timeOut;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; useSpan;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, Span span, String name, &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; timeOut, &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; useSpan)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.tracer =tracer;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.span = span;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.name = name;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.timeOut = timeOut;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.useSpan = useSpan;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Void &lt;span class=&quot;hljs-title&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{        Span childSpan;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(useSpan){            childSpan = spanHelper.createSpan(tracer,span,Thread.currentThread().getName(),name);        }&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;{            childSpan = spanHelper.createSpan(tracer,Thread.currentThread().getName(), name);        }        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Running : {}&quot;&lt;/span&gt;,Thread.currentThread().getName());        Thread.sleep(timeOut);        spanHelper.endSpan(childSpan);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;;    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;SpanHelper class is a helper class used for creating the spans either with provides parent span or new span.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SpanHelper&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;Span &lt;span class=&quot;hljs-title&quot;&gt;createSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, String spanName, String tags)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;create new span..&quot;&lt;/span&gt;);        Span span = tracer.nextSpan(tracer.currentSpan());        span.name(spanName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;-&quot;&lt;/span&gt;+tags);        span.event(&lt;span class=&quot;hljs-string&quot;&gt;&quot;starting &quot;&lt;/span&gt;+spanName);        span.start();        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; span;    }    &lt;span class=&quot;hljs-function&quot;&gt;Span &lt;span class=&quot;hljs-title&quot;&gt;createSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, Span parentSpan, String spanName, String tags)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;create new child span..&quot;&lt;/span&gt;);        Span span = tracer.nextSpan(parentSpan);        span.name(spanName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;-&quot;&lt;/span&gt;+tags);        span.event(&lt;span class=&quot;hljs-string&quot;&gt;&quot;starting &quot;&lt;/span&gt;+spanName);        span.start();        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; span;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;endSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Span span)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(span != &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;){            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;closing the span {}&quot;&lt;/span&gt;,span);            span.end();        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The entry point of the app-1 application, usually generated by the spring boot starter&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppOneApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(AppOneApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;application.yaml configuration for the app-1 application&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8082&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;management:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zipkin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;endpoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;http://localhost:9411/api/v2/spans&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-jaeger-in-kind-cluster&quot;&gt;Jaeger in Kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Use the Kind cluster yaml configuration to create the cluster&lt;/li&gt;&lt;li&gt;Deploy Jaeger to the cluster&lt;/li&gt;&lt;li&gt;&lt;p&gt;Port forward the necessary ports so spring boot application can send traces and spans.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the below kind configuration yaml as &lt;code&gt;jaeger-cluster.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Use the command &lt;code&gt;kind create cluster --config jaeger-cluster.yaml&lt;/code&gt; to create the cluster, make sure the docker desktop is running.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaeger-cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use below set of command to deploy the Jaeger in Kind cluster, we use jaeger-all-in-one image which is not production ready.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the cert-manager from &lt;code&gt;https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml&lt;/code&gt; to &lt;code&gt;cert-manager-v1.15.3.yaml&lt;/code&gt;. Use kubectl apply command below to deploy to kind cluster&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f cert-manager_v1&lt;span class=&quot;hljs-number&quot;&gt;.15&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create the namespace with below command&lt;/p&gt;&lt;pre&gt;&lt;code&gt;kubectl create namespace observability&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the Jaeger operator yaml from &lt;code&gt;https://github.com/jaegertracing/jaeger-operator/releases/download/v1.60.0/jaeger-operator.yaml&lt;/code&gt; and save it as &lt;code&gt;jaeger-operator.yaml&lt;/code&gt;. Use below command to deploy to kind cluster&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f jaeger-operator.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the below jaeger-all-in-one configuration create a yaml file named &lt;code&gt;jaeger_allinone.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;allInOne&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;1&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;allInOne:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing/all-in-one:latest&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;2&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;options:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;3&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;log-level:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;4&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;5&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;options:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;6&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;7&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;max-traces:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100000&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingress:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;8&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;agent:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DaemonSet&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;9&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;scheduler.alpha.kubernetes.io/critical-pod:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;10&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Use below command to deploy the Jaeger all in one server.&lt;pre&gt;&lt;code&gt;kubectl apply -f jaeger_allinone.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h5 id=&quot;heading-port-forward-using-below-commands&quot;&gt;Port forward using below commands&lt;/h5&gt;&lt;pre&gt;&lt;code&gt;# below ports will be used by the spring boot application to send traces and spanskubectl port-forward svc/my-jaeger-collector &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14267&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14267&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;# below is to access the jaeger UI &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; localkubectl port-forward svc/my-jaeger-query &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-accessing-the-application&quot;&gt;Accessing the application&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;With the spring boot applications running and Jaeger deployed, use &lt;code&gt;http://localhost:8080/api/v2/execute&lt;/code&gt; to create traces.&lt;/li&gt;&lt;li&gt;The Jaeger UI can be viewed using &lt;code&gt;http://localhost:16686/&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-create-trace-and-spans-manually-in-spring-boot-applications&quot;&gt;Create trace and spans manually in spring boot applications&lt;/h2&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Jaeger installed and running (in this example deployed in kind cluster)&lt;/li&gt;&lt;li&gt;Understanding on traces and spans&lt;/li&gt;&lt;li&gt;Understanding on micrometer Spring configuration&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-requirement&quot;&gt;Requirement&lt;/h3&gt;&lt;p&gt;This blog details on how to create spans manually in Spring Boot application. This is based on a requirement in a project, to track the flow between application using Jaeger. To create the traces and spans manually so it can visualized in Jaeger UI and helps the business process on how much time it takes.&lt;/p&gt;&lt;p&gt;In order to demonstrate we have two Spring Boot application, use the tracer object configured in Spring boot to create the spans. The spans set with name with additional tags which is key value pair which can be viewed in Jaeger UI. In the example, the application named &lt;code&gt;invoker-app&lt;/code&gt; exposes a REST API (&lt;code&gt;/api/v2/execute&lt;/code&gt;), when invoked calls the REST API (&lt;code&gt;/app/run?traceId=xxx&amp;amp;spanId=yyy&lt;/code&gt;) of second application named &lt;code&gt;app-1&lt;/code&gt;. The &lt;code&gt;app-1&lt;/code&gt; application uses the traceId and spanId to create a trace context and adds to the current tracer.&lt;/p&gt;&lt;p&gt;The code snippet below is in app-1 application which creates traceContext with the traceId and spanId. The created traceContext is set to the configured tracer objects current Tracer Context scope. &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; contextWithCustomTraceId = tracer.traceContextBuilder()                    .traceId(traceId)                    .spanId(spanId)                    .sampled(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;)                    .build();&lt;span class=&quot;hljs-comment&quot;&gt;// use traceContext as a newScope&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; sc = tracer.currentTraceContext().newScope(contextWithCustomTraceId)) { &lt;span class=&quot;hljs-comment&quot;&gt;// create spans process any operation&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Representation of the REST API invocation between the apps, in this case invoker-app and app-1.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/589948c3-6365-4cce-a33d-bdf6adf19937&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;The expected flow from Jager UI looks like below, where the invoker-app span and app-1 span can be seen as child spans.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/551914ef-659a-4464-bea2-c0604727ff20&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Span with the tag added during creation.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/user-attachments/assets/8e7ae5a0-9361-48e1-baaa-c82bb11d67d9&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;h4 id=&quot;heading-invoker-app&quot;&gt;Invoker app&lt;/h4&gt;&lt;p&gt;Below is the pom.xml with dependencies. Note the dependencies are same for both invoker-app and app-1 only change is the name of the apps.When using &lt;a target=&quot;_blank&quot; href=&quot;https://start.spring.io&quot;&gt;Spring starter&lt;/a&gt; create two projects, just copy paste the dependencies section. &lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.3.2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.trace&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;invoker&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;invoker&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo project for Spring Boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;licenses&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;license&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;licenses&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developers&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developer&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;developers&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scm&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;connection&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;developerConnection&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;tag&lt;/span&gt;/&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scm&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;22&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-actuator&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing-bridge-brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;brave-instrumentation-okhttp3&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.reporter2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;zipkin-sender-urlconnection&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.reporter2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;zipkin-reporter-brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencyManagement&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.micrometer&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;micrometer-tracing-bom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;${micrometer-tracing.version}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;import&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.zipkin.brave&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;brave-bom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;${brave.version}&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;pom&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;type&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;import&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencyManagement&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The application.yaml for the spring boot application, which includes the tracing endpoint url&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;invoker&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;management:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9145&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;sampling:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;probability:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zipkin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;endpoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;http://localhost:9411/api/v2/spans&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-invoker-app-controller&quot;&gt;Invoker app controller&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The invoker app uses the RestTemplate to create the REST API GET request to access the app-1 app.&lt;/li&gt;&lt;li&gt;The traceId and spandId is obtained from the tracer object configured and created by the Spring boot application during deployment.&lt;/li&gt;&lt;li&gt;The use of Random class to induce additional random delay after the span is created just for demonstration to view it in Jaeger UI.```javapackage com.trace.invoker;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;import io.micrometer.tracing.Span;import io.micrometer.tracing.Tracer;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.boot.web.client.RestTemplateBuilder;import org.springframework.http.*;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;&lt;/p&gt;&lt;p&gt;import java.util.Random;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;&lt;/p&gt;&lt;p&gt;@RestController@RequestMapping(&quot;/api/v2/&quot;)@Slf4jpublic class AppInvokerController {&lt;/p&gt;&lt;p&gt;    private final Tracer tracer;&lt;/p&gt;&lt;p&gt;    AppInvokerController(Tracer tracer){        this.tracer = tracer;    }&lt;/p&gt;&lt;p&gt;    @GetMapping(&quot;/execute&quot;)    public String invokeTask() {&lt;/p&gt;&lt;p&gt;        // new span        Span span1 = tracer.nextSpan().name(&quot;invoker-api-parent&quot;).start();        // URL for second app app-1 application        String APPURL = &quot;http://localhost:8082/app/v1/run?traceId=%s&amp;amp;spanId=%s&quot;;        String traceId = tracer.currentSpan().context().traceId();        String spanId = span1.context().spanId();        String url = String.format(APPURL,traceId,spanId);&lt;/p&gt;&lt;p&gt;        RestTemplate clientTemplate = new RestTemplate();        log.info(&quot;tracer invoked app-1 invoked&quot;);&lt;/p&gt;&lt;p&gt;        HttpHeaders httpHeaders = new HttpHeaders();        httpHeaders.setContentType(MediaType.TEXT_PLAIN);&lt;/p&gt;&lt;p&gt;        HttpEntity request = new HttpEntity&amp;lt;&amp;gt;(&quot;&quot;,httpHeaders);&lt;/p&gt;&lt;p&gt;        try (Tracer.SpanInScope spanInScope = tracer.withSpan(span1.name(&quot;invoke-api&quot;).start())) {            span1.tag(&quot;appName&quot;,&quot;invokeApi&quot;);            span1.event(&quot;invoked from invoker api&quot;);            ResponseEntity response =                    clientTemplate.postForEntity(url,null,String.class);            log.info(&quot;response {}&quot;,response.getBody());&lt;/p&gt;&lt;p&gt;        }finally {            span1.end();        }        // New span- just for example to demonstrate the last step in invoker-app        Span span2 = tracer.nextSpan().name(&quot;last step&quot;).start();        span2.event(&quot;completed&quot;);        span2.tag(&quot;app&quot;,&quot;invoker&quot;);        try{            Thread.sleep(700);        } catch (InterruptedException e) {            log.warn(&quot;Interrupted exception&quot;);        }        span2.end();        return &quot;completed&quot;;    }&lt;/p&gt;&lt;p&gt;}&lt;/p&gt;&lt;pre&gt;&lt;code&gt;- RestTemplate bean is used by the tracer object to publish the trace and span to Jaeger server.&lt;span class=&quot;hljs-string&quot;&gt;``&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;`javapackage com.trace.invoker;import org.springframework.boot.web.client.RestTemplateBuilder;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;public class AppConfig {    @Bean    RestTemplate restTemplate(RestTemplateBuilder builder){        return builder.build();    }}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Application entry point usually class created by the spring starter itself.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.invoker;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvokerApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(InvokerApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-app-1-application&quot;&gt;app-1 application&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The pom.xml with dependencies is same as the invoker-app dependencies. The only change would be the name and artifactId.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The app-1 controller code,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;With the provided traceId and spandId a new tracerContext is build and added to the current tracer context scope.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;sampleThreadInvocation()&lt;/code&gt; uses Task Callable class (note, we can use Runnable as well) to run set of thread in parallel and create child spans with provided parent span&lt;/li&gt;&lt;li&gt;The &lt;code&gt;additionalProcess()&lt;/code&gt; method demonstrates creating the spans outside the thread.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Callable;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.ExecutorService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Executors;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/app/v1&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Tracer tracer;    Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    AppController(Tracer tracer){        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.tracer = tracer;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@PostMapping(&quot;/run&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam&lt;/span&gt; String traceId,                          &lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam&lt;/span&gt; String spanId)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;// traceId and spanId can&apos;t be null&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(!Objects.isNull(traceId) &amp;amp;&amp;amp; !Objects.isNull(spanId) ) {            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;traceId included - {}&quot;&lt;/span&gt;, traceId);           &lt;span class=&quot;hljs-comment&quot;&gt;// create trace context with teh traceId and spanId&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; contextWithCustomTraceId = tracer.traceContextBuilder()                    .traceId(traceId)                    .spanId(spanId)                    .sampled(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;)                    .build();            &lt;span class=&quot;hljs-comment&quot;&gt;// set the tracercontext to current trace context scope&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; sc = tracer.currentTraceContext().newScope(contextWithCustomTraceId)) {               &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; span =  tracer.spanBuilder().name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app-one-tracing&quot;&lt;/span&gt;).start();                &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(Tracer.SpanInScope spanInScope= tracer.withSpan(span)) {                    span.tag(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;run invoked&quot;&lt;/span&gt;);                    log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;tracing logs...&quot;&lt;/span&gt;);                    sleep(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;750&lt;/span&gt;));                    sampleThreadInvocation();                    additionalProcess(&lt;span class=&quot;hljs-string&quot;&gt;&quot;process-1&quot;&lt;/span&gt;);                    additionalProcess(&lt;span class=&quot;hljs-string&quot;&gt;&quot;process-2&quot;&lt;/span&gt;);                }&lt;span class=&quot;hljs-keyword&quot;&gt;finally&lt;/span&gt; {                    span.end();                }            }        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;completed invocation&quot;&lt;/span&gt;;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;additionalProcess&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String name)&lt;/span&gt;&lt;/span&gt;{        Span span = tracer.nextSpan(tracer.currentSpan());        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(Tracer.SpanInScope spanInScope= tracer.withSpan(span.name(name).start())){            SpanHelper spanHelper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; SpanHelper();            Span innerSpan = spanHelper.createSpan(tracer,span,&lt;span class=&quot;hljs-string&quot;&gt;&quot;ap-&quot;&lt;/span&gt;+name,&lt;span class=&quot;hljs-string&quot;&gt;&quot;proceed&quot;&lt;/span&gt;);            sleep(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;1100&lt;/span&gt;));            spanHelper.endSpan(innerSpan);            spanHelper.endSpan(span);        }    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sampleThreadInvocation&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;api invoked..&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;(ExecutorService executor = Executors.newFixedThreadPool(&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;)) {            Span span = tracer.currentSpan();&lt;span class=&quot;hljs-comment&quot;&gt;//.name(&quot;api-parent&quot;).start();//currentSpan();&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;; i++) {                &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; (Tracer.SpanInScope spanInScope = tracer.withSpan(span)) {                    Callable&amp;lt;Void&amp;gt; caller = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Task(tracer, span, &lt;span class=&quot;hljs-string&quot;&gt;&quot;task&quot;&lt;/span&gt; + i, random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;750&lt;/span&gt;), &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;);                    executor.submit(caller);                }            }            executor.shutdown();            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!executor.awaitTermination(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;, TimeUnit.SECONDS)) {                    executor.shutdownNow();                }            } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (InterruptedException interruptedException) {                executor.shutdownNow();            }        }        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;completed&quot;&lt;/span&gt;);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; duration)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {            Thread.sleep(duration);        } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (InterruptedException e) {            log.warn(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sleep interrupted&quot;&lt;/span&gt;);        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below is Task class just used to demonstrate the use of parallel threads and span creation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.Callable;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Callable&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Void&lt;/span&gt;&amp;gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Tracer tracer;    SpanHelper spanHelper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; SpanHelper();    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; Span span;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; String name;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; timeOut;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; useSpan;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, Span span, String name, &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; timeOut, &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; useSpan)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.tracer =tracer;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.span = span;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.name = name;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.timeOut = timeOut;        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.useSpan = useSpan;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Void &lt;span class=&quot;hljs-title&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{        Span childSpan;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(useSpan){            childSpan = spanHelper.createSpan(tracer,span,Thread.currentThread().getName(),name);        }&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;{            childSpan = spanHelper.createSpan(tracer,Thread.currentThread().getName(), name);        }        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Running : {}&quot;&lt;/span&gt;,Thread.currentThread().getName());        Thread.sleep(timeOut);        spanHelper.endSpan(childSpan);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;;    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;SpanHelper class is a helper class used for creating the spans either with provides parent span or new span.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Span;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.micrometer.tracing.Tracer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SpanHelper&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;Span &lt;span class=&quot;hljs-title&quot;&gt;createSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, String spanName, String tags)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;create new span..&quot;&lt;/span&gt;);        Span span = tracer.nextSpan(tracer.currentSpan());        span.name(spanName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;-&quot;&lt;/span&gt;+tags);        span.event(&lt;span class=&quot;hljs-string&quot;&gt;&quot;starting &quot;&lt;/span&gt;+spanName);        span.start();        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; span;    }    &lt;span class=&quot;hljs-function&quot;&gt;Span &lt;span class=&quot;hljs-title&quot;&gt;createSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Tracer tracer, Span parentSpan, String spanName, String tags)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;create new child span..&quot;&lt;/span&gt;);        Span span = tracer.nextSpan(parentSpan);        span.name(spanName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;-&quot;&lt;/span&gt;+tags);        span.event(&lt;span class=&quot;hljs-string&quot;&gt;&quot;starting &quot;&lt;/span&gt;+spanName);        span.start();        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; span;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;endSpan&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Span span)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(span != &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;){            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;closing the span {}&quot;&lt;/span&gt;,span);            span.end();        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The entry point of the app-1 application, usually generated by the spring boot starter&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.trace.app.one;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppOneApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(AppOneApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;application.yaml configuration for the app-1 application&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8082&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;management:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zipkin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tracing:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;endpoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;http://localhost:9411/api/v2/spans&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-jaeger-in-kind-cluster&quot;&gt;Jaeger in Kind cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Use the Kind cluster yaml configuration to create the cluster&lt;/li&gt;&lt;li&gt;Deploy Jaeger to the cluster&lt;/li&gt;&lt;li&gt;&lt;p&gt;Port forward the necessary ports so spring boot application can send traces and spans.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the below kind configuration yaml as &lt;code&gt;jaeger-cluster.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;Use the command &lt;code&gt;kind create cluster --config jaeger-cluster.yaml&lt;/code&gt; to create the cluster, make sure the docker desktop is running.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaeger-cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;7443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use below set of command to deploy the Jaeger in Kind cluster, we use jaeger-all-in-one image which is not production ready.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the cert-manager from &lt;code&gt;https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml&lt;/code&gt; to &lt;code&gt;cert-manager-v1.15.3.yaml&lt;/code&gt;. Use kubectl apply command below to deploy to kind cluster&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f cert-manager_v1&lt;span class=&quot;hljs-number&quot;&gt;.15&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create the namespace with below command&lt;/p&gt;&lt;pre&gt;&lt;code&gt;kubectl create namespace observability&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the Jaeger operator yaml from &lt;code&gt;https://github.com/jaegertracing/jaeger-operator/releases/download/v1.60.0/jaeger-operator.yaml&lt;/code&gt; and save it as &lt;code&gt;jaeger-operator.yaml&lt;/code&gt;. Use below command to deploy to kind cluster&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f jaeger-operator.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the below jaeger-all-in-one configuration create a yaml file named &lt;code&gt;jaeger_allinone.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;allInOne&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;1&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;allInOne:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing/all-in-one:latest&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;2&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;options:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;3&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;log-level:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;debug&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;4&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;memory&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;5&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;options:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;6&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;7&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;max-traces:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100000&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingress:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;8&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;agent:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DaemonSet&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;9&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;scheduler.alpha.kubernetes.io/critical-pod:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# &amp;lt;10&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Use below command to deploy the Jaeger all in one server.&lt;pre&gt;&lt;code&gt;kubectl apply -f jaeger_allinone.yaml&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h5 id=&quot;heading-port-forward-using-below-commands&quot;&gt;Port forward using below commands&lt;/h5&gt;&lt;pre&gt;&lt;code&gt;# below ports will be used by the spring boot application to send traces and spanskubectl port-forward svc/my-jaeger-collector &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14267&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14267&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;# below is to access the jaeger UI &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; localkubectl port-forward svc/my-jaeger-query &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-accessing-the-application&quot;&gt;Accessing the application&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;With the spring boot applications running and Jaeger deployed, use &lt;code&gt;http://localhost:8080/api/v2/execute&lt;/code&gt; to create traces.&lt;/li&gt;&lt;li&gt;The Jaeger UI can be viewed using &lt;code&gt;http://localhost:16686/&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Access Kubernetes Secrets In SpringBoot Application]]></title><description><![CDATA[Blog demonstrating accessing kubernetes secret from spring boot application without loading to environment variables.]]></description><link>https://thirumurthi.hashnode.dev/access-kubernetes-secrets-in-springboot-application</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/access-kubernetes-secrets-in-springboot-application</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[configuration management]]></category><category><![CDATA[secrets]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Thu, 04 Jul 2024 18:35:37 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h3 id=&quot;heading-access-kubernetes-secrets-in-spring-boot-application-without-loading-to-environment-variables-of-the-pod&quot;&gt;Access Kubernetes secrets in Spring Boot application without loading to environment variables of the pod.&lt;/h3&gt;&lt;p&gt;This blog will show how to access Kubernetes secrets in a Spring application without setting properties as environment variable in the container.&lt;/p&gt;&lt;p&gt;To better understand this blog, basic knowledge of Spring framework and Kubernetes (especially how to create secrets and mount secrets to access as environment variables in Pods) is recommended.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker desktop &lt;/li&gt;&lt;li&gt;Kind CLI&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-spring-configuration-management&quot;&gt;Spring configuration management&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Spring Boot framework already provides multiple way to externalize the configuration. Instead of specifying the properties in application.yaml we can created as environment variable. For example, say if we need to enable a specific Spring profile the environment variable SPRING_PROFILES_ACTIVE can be set with specific profile when running the application. &lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-access-kubernetes-secret-in-spring-boot-application-without-configuring-to-environment-variable&quot;&gt;Access Kubernetes secret in Spring Boot application without configuring to environment variable&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this approach the secret will be read by the Spring Boot application without loading to the environment variables.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The secret is mount in the pod manifest&lt;/li&gt;&lt;li&gt;The mount path of the secret is configured in Spring boot application with &lt;code&gt;spring.config.import&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-demonstration-of-configuration-management&quot;&gt;Demonstration of configuration management&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create a simple secret resource named secret-msg in Kubernetes cluster. Use below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl create secret generic secret-msg --&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-literal=MESSAGE=&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-k8s-secret-store&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The created secret is mounted in Pod manifest. Below is the snippet of how secret is mounted.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/secrets/&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;readOnly:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The Spring Boot application.yaml file is configured with the mounted secret path.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.config.import:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;optional:configtree:/etc/secrets/&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In Spring Boot controller, we can access the secret using the Value annotation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${message:default-from-app}&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String message;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-the-spring-boot-application-code-and-kubernetes-manifests&quot;&gt;The Spring Boot application code and Kubernetes manifests&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use &lt;a target=&quot;_blank&quot; href=&quot;https://start.spring.io&quot;&gt;Spring Boot starter&lt;/a&gt; to create the Spring Boot application, include &lt;code&gt;spring-boot-starter-web&lt;/code&gt; dependency. Extract the zip file and configure in preferred IDE.  Following are additional files to set the Spring Boot application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;application.yaml&lt;/code&gt; content&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;config.import:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;optional:configtree:/etc/secrets/&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The controller class includes &lt;code&gt;@value&lt;/code&gt; annotation to read value from the message property, it is set with default value. This helps identify which values is being fetched when the application is running.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/v1&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConfigController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String RESPONSE= &lt;span class=&quot;hljs-string&quot;&gt;&quot;{\&quot;secret-msg\&quot;: \&quot;%s\&quot;}&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${message:default-from-app}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String message;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;message&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; String.format(RESPONSE,message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To create docker image use the below content in the Dockerfile. Before using the Dockerfile to create the image the jar must be created. Note, this is not the ideal approach for production.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configtree is the project name used for demonstration. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; openjdk:&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;-jdk-slim&lt;span class=&quot;hljs-keyword&quot;&gt;VOLUME&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; /tmp&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; target/configtree-1.0.0.jar app.jar&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;EXPOSE&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8091&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;/app.jar&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To build the docker image use below command, place the Dockerfile in the root of the Spring boot project application.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;docker build -t configtree-app .&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The kind configuration used for this demonstration.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30095&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Command to create the kind cluster. Make sure the Docker desktop is running and issue below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind create cluster --config deploy/kind-config.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The image is not published to Docker hub, in order to use the image in Kind cluster it needs to be loaded using below command. The cluster name in this case is configtree and the image name is configtree-app&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind load docker-image configtree-app --name configtree&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kubernetes deployment manifest for the spring boot application looks like below. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Note, the mounted secret path is configured in the application yaml.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configree&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app:latest&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/secrets/&lt;/span&gt;          &lt;span class=&quot;hljs-comment&quot;&gt;# secret mount path&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;readOnly:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;secret:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;secretName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;# name of the created secret&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;NodePort service, this helps us to access the application running in the pod without port-forwarding.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-svc&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;NodePort&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once deployed the application can be accessed which will render the message value from secret.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;curl localhost:&lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;/v1/message{&lt;span class=&quot;hljs-string&quot;&gt;&quot;secret-msg&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;from-k8s-secret-store&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/5f0f44bd-c9de-4dfd-bbef-09d4b116167c&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;h4 id=&quot;heading-other-approach-to-load-secret-to-pod-environment-variables&quot;&gt;Other approach to load secret to Pod environment variables&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;There are other options in Kubernetes to configure the secret as environment variable to the pod. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data&quot;&gt;Kubernetes documentation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Pod manifest to load all secret to Pod environment variable using &lt;code&gt;secretRef&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-ref&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;envars-container&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;envFrom:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;secretRef:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Alternatively we can use &lt;code&gt;secretKeyRef&lt;/code&gt; to set as environment variable once specific key in the secret.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secrets-key-ref&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;envars-container&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;env:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MESSAGE&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;valueFrom:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;secretKeyRef:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MESSAGE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h3 id=&quot;heading-access-kubernetes-secrets-in-spring-boot-application-without-loading-to-environment-variables-of-the-pod&quot;&gt;Access Kubernetes secrets in Spring Boot application without loading to environment variables of the pod.&lt;/h3&gt;&lt;p&gt;This blog will show how to access Kubernetes secrets in a Spring application without setting properties as environment variable in the container.&lt;/p&gt;&lt;p&gt;To better understand this blog, basic knowledge of Spring framework and Kubernetes (especially how to create secrets and mount secrets to access as environment variables in Pods) is recommended.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker desktop &lt;/li&gt;&lt;li&gt;Kind CLI&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-spring-configuration-management&quot;&gt;Spring configuration management&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Spring Boot framework already provides multiple way to externalize the configuration. Instead of specifying the properties in application.yaml we can created as environment variable. For example, say if we need to enable a specific Spring profile the environment variable SPRING_PROFILES_ACTIVE can be set with specific profile when running the application. &lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-access-kubernetes-secret-in-spring-boot-application-without-configuring-to-environment-variable&quot;&gt;Access Kubernetes secret in Spring Boot application without configuring to environment variable&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this approach the secret will be read by the Spring Boot application without loading to the environment variables.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The secret is mount in the pod manifest&lt;/li&gt;&lt;li&gt;The mount path of the secret is configured in Spring boot application with &lt;code&gt;spring.config.import&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-demonstration-of-configuration-management&quot;&gt;Demonstration of configuration management&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create a simple secret resource named secret-msg in Kubernetes cluster. Use below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl create secret generic secret-msg --&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-literal=MESSAGE=&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-k8s-secret-store&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The created secret is mounted in Pod manifest. Below is the snippet of how secret is mounted.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/secrets/&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;readOnly:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The Spring Boot application.yaml file is configured with the mounted secret path.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring.config.import:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;optional:configtree:/etc/secrets/&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In Spring Boot controller, we can access the secret using the Value annotation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${message:default-from-app}&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String message;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-the-spring-boot-application-code-and-kubernetes-manifests&quot;&gt;The Spring Boot application code and Kubernetes manifests&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use &lt;a target=&quot;_blank&quot; href=&quot;https://start.spring.io&quot;&gt;Spring Boot starter&lt;/a&gt; to create the Spring Boot application, include &lt;code&gt;spring-boot-starter-web&lt;/code&gt; dependency. Extract the zip file and configure in preferred IDE.  Following are additional files to set the Spring Boot application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;application.yaml&lt;/code&gt; content&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;application.name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;config.import:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;optional:configtree:/etc/secrets/&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;server.port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The controller class includes &lt;code&gt;@value&lt;/code&gt; annotation to read value from the message property, it is set with default value. This helps identify which values is being fetched when the application is running.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/v1&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConfigController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String RESPONSE= &lt;span class=&quot;hljs-string&quot;&gt;&quot;{\&quot;secret-msg\&quot;: \&quot;%s\&quot;}&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${message:default-from-app}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String message;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;message&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; String.format(RESPONSE,message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To create docker image use the below content in the Dockerfile. Before using the Dockerfile to create the image the jar must be created. Note, this is not the ideal approach for production.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configtree is the project name used for demonstration. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; openjdk:&lt;span class=&quot;hljs-number&quot;&gt;22&lt;/span&gt;-jdk-slim&lt;span class=&quot;hljs-keyword&quot;&gt;VOLUME&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; /tmp&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; target/configtree-1.0.0.jar app.jar&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;EXPOSE&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8091&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;/app.jar&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To build the docker image use below command, place the Dockerfile in the root of the Spring boot project application.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;docker build -t configtree-app .&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The kind configuration used for this demonstration.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30095&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Command to create the kind cluster. Make sure the Docker desktop is running and issue below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind create cluster --config deploy/kind-config.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The image is not published to Docker hub, in order to use the image in Kind cluster it needs to be loaded using below command. The cluster name in this case is configtree and the image name is configtree-app&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind load docker-image configtree-app --name configtree&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kubernetes deployment manifest for the spring boot application looks like below. &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Note, the mounted secret path is configured in the application yaml.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configree&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app:latest&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/secrets/&lt;/span&gt;          &lt;span class=&quot;hljs-comment&quot;&gt;# secret mount path&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;readOnly:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-volume&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;secret:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;secretName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;# name of the created secret&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;NodePort service, this helps us to access the application running in the pod without port-forwarding.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-svc&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;NodePort&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;configtree-port&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30095&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once deployed the application can be accessed which will render the message value from secret.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;curl localhost:&lt;span class=&quot;hljs-number&quot;&gt;8095&lt;/span&gt;/v1/message{&lt;span class=&quot;hljs-string&quot;&gt;&quot;secret-msg&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;from-k8s-secret-store&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/5f0f44bd-c9de-4dfd-bbef-09d4b116167c&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;hr /&gt;&lt;h4 id=&quot;heading-other-approach-to-load-secret-to-pod-environment-variables&quot;&gt;Other approach to load secret to Pod environment variables&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;There are other options in Kubernetes to configure the secret as environment variable to the pod. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kubernetes.io/docs/tasks/inject-data-application/distribute-credentials-secure/#define-container-environment-variables-using-secret-data&quot;&gt;Kubernetes documentation&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Pod manifest to load all secret to Pod environment variable using &lt;code&gt;secretRef&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-ref&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;envars-container&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;envFrom:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;secretRef:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Alternatively we can use &lt;code&gt;secretKeyRef&lt;/code&gt; to set as environment variable once specific key in the secret.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Pod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secrets-key-ref&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;envars-container&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;env:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MESSAGE&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;valueFrom:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;secretKeyRef:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret-msg&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;MESSAGE&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Apache Apisix and Zitadel OIDC provider]]></title><description><![CDATA[This blog post provides details to configure development environment to run Apisix and Zitadel in single cluster.]]></description><link>https://thirumurthi.hashnode.dev/apache-apisix-and-zitadel-oidc-provider</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/apache-apisix-and-zitadel-oidc-provider</guid><category><![CDATA[Apache APISIX]]></category><category><![CDATA[zitadel]]></category><category><![CDATA[nginx]]></category><category><![CDATA[kind]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 12 May 2024 06:24:55 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h1 id=&quot;heading-deploying-apache-apisix-and-zitadel-in-kubernetes&quot;&gt;Deploying Apache Apisix and Zitadel in Kubernetes&lt;/h1&gt;&lt;p&gt;In this blog will be demonstrating how to setup Apisix and Zitadel in Kind Kubernetes cluster for development.&lt;/p&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;p&gt;Software to be installed&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Docker desktop&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kind&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Helm&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kubectl&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Basic understanding on Gateway and OpenId Connect.&lt;/p&gt;&lt;h2 id=&quot;heading-what-is-apache-apisix&quot;&gt;What is Apache Apisix?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Apache Apisix is opensource API Gateway based on Nginx and etcd.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this demonstration Apache Apisix is installed to cluster using helm chart, along with Apisix Dashboard and Apisix Ingress controller.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This is only for development and &lt;strong&gt;not&lt;/strong&gt; production grade. For more info refer the &lt;a target=&quot;_blank&quot; href=&quot;https://apisix.apache.org&quot;&gt;Apache Apisix&lt;/a&gt; documentation.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-what-is-zitadel&quot;&gt;What is Zitadel?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Zitadel provides identity management service along with authentication management. Zitadel can also be installed as standalone application, refer &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.com/docs/guides/start/quickstart&quot;&gt;Zitadel&lt;/a&gt; documentation.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this demonstration Zitadel application is installed with helm chart along with UI dashboard.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Prior to deploying Zitadel application the define a domain name, this value should be set in the configuration &lt;code&gt;ExternalDomain&lt;/code&gt; either in override values or passed as helm command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Zitadel can be installed with either Cockroach db or Postgres db. In this demonstartion Postgres db is used.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;Externaldomain&lt;/code&gt; value is also used as part of default username and for password check the documentation.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-installing-kind-cluster&quot;&gt;Installing Kind Cluster&lt;/h2&gt;&lt;p&gt;Below yaml defines the Kind cluster configuration, with Docker desktop running we can create the the cluster with this configuration.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The ingress option is enabled in the kind cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Apisix exposes the Gateway service as NodePort or Loadbalancer. In here NodePort service is used and port 30080 is exposed.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;By configuring the ports in &lt;code&gt;extraPortMappings&lt;/code&gt; the Apisix Dashboard can be accessed doesn&apos;t require port-forwarding.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: kind-cluster.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-zitadel&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kubeadmConfigPatches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    kind: InitConfiguration    nodeRegistration:      kubeletExtraArgs:        node-labels: &quot;ingress-ready=true&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30080&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the content of kind configuration to a file named &lt;code&gt;kind-cluster.yaml&lt;/code&gt; and use below command to create cluster.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kind create cluster --config kind-cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-installing-apisix&quot;&gt;Installing Apisix&lt;/h2&gt;&lt;p&gt;To install Apsix with helm charts, add the helm repo to local and issue update command like below.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add apisix https://charts.apiseven.comhelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In here we pull the chart to local and use it. To download the latest chart to local use the command below.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm pull apisix/apisix --untar&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Alternatively, you can download the helm charts from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/apache/apisix-helm-chart&quot;&gt;Apisix Helm Chart repo&lt;/a&gt;, requires understanding on helm charts.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In the downloaded helm chart update the chart version of &lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;apisix-dashboard&lt;/code&gt; and &lt;code&gt;apisix-ingress-controller&lt;/code&gt; in &lt;code&gt;chart.yaml&lt;/code&gt; file to latest version (below is the version number at the time if this writing)&lt;/p&gt;&lt;p&gt;After updating the version issue the command &lt;code&gt;helm dependency update&lt;/code&gt; from the chart directory, helm will pull the specified version of dependent chart under the &lt;code&gt;charts&lt;/code&gt; folder.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;appVersion:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.9&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;sources:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://github.com/apache/apisix-helm-chart&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;dependencies:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;etcd&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.bitnami.com/bitnami&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;etcd.enabled&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-dashboard&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.2&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.apiseven.com&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dashboard.enabled&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dashboard&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-ingress-controller&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.14&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.apiseven.com&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-controller.enabled&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-controller&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-custom-override-values-yaml-for-apisix-chart&quot;&gt;Custom override values yaml for Apisix chart&lt;/h3&gt;&lt;p&gt;The override values file for Apisix deploymentis used for this deployment. Note, only few configuration is updated like image tag name of initContainer, http service ports for Apisix service. Refer the documentation for mode customization, but for local development this should suffice.&lt;/p&gt;&lt;p&gt;The Apisix discovery registry is enabled with Kubernetes cluster. There are other registry option which can be configured, refer documentation.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: apisix-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apache/apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tag:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.8&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;-debian&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;initContainer:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;busybox&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tag:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;serviceAccount:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;rbac:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;NodePort&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;externalTrafficPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;externalIPs:&lt;/span&gt; []  &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9080&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30080&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;# port used in kind cluster configuration&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apisix:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enableIPv6:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enableServerTokens:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;admin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ClusterIP&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;externalIPs:&lt;/span&gt; []    &lt;span class=&quot;hljs-attr&quot;&gt;ip:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;cors:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;credentials:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;admin:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;edd1c9f034335f136f87ad84b625c8f1&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Default value as in values yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;viewer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;4054f7cf07e344346cd3f287985e76a2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;discovery:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;registry:&lt;/span&gt;     &lt;span class=&quot;hljs-attr&quot;&gt;kubernetes:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;schema:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${KUBERNETES_SERVICE_HOST}&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${KUBERNETES_SERVICE_PORT}&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;externalEtcd:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http://etcd.host:2379&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;existingSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;secretPasswordKey:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;etcd-root-password&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;etcd:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;/apisix&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;timeout:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;auth:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;rbac:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;rootPassword:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;existingSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;certFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;certKeyFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;verify:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;sni:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2379&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Apisix Dashboard configuration&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;dashboard:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;conf:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;etcd:&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# -- Supports defining multiple etcd host addresses for an etcd cluster&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;endpoints:&lt;/span&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-etcd:2379&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;/apisix&quot;&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;~&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# -- Ingress controller configuration&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;ingress-controller:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;apisix:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;adminAPIVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;v3&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the above content in a file &lt;code&gt;apisix-values.yaml&lt;/code&gt; as override values yaml within the apisix chart directory.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below command will install &lt;code&gt;Apisix&lt;/code&gt;, &lt;code&gt;Apisix Dashboard&lt;/code&gt; and &lt;code&gt;Apisix Ingress Controller&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-bash&quot;&gt;helm upgrade --install apisix -f apisix-values.yaml . \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.type=NodePort \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.http.nodePort=30080 \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; ingress-controller.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; dashboard.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; \    --create-namespace \    --namespace ingress-apisix \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; ingress-controller.config.apisix.serviceNamespace=ingress-apisix&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Not all the configuration in override values yaml is customized, compare it with default values yaml file.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Also, the line &lt;code&gt;--set service.type=NodePort --set service.http.nodePort=30080&lt;/code&gt; in helm command can be removed since they are already added override yaml.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;To check the status of Apisix deployments use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl -n ingress-apisix get pods,svc&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/6625d78f-b0ba-4fa9-8714-a0b32af11f56&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-install-ingress-route-for-apisix-dashboard&quot;&gt;Install Ingress route for Apisix dashboard&lt;/h3&gt;&lt;p&gt;Once the &lt;code&gt;Apisix ingress controller&lt;/code&gt; pod is in running state,Apisix dashboard ingress route can be configured to access from browser.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Info :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Apisix Ingress controller&lt;/code&gt; uses CRD&apos;s to resolve Apisix routes and also resolves Ingress resource definition. It creates route and registers in apisix application as well.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;The ingress configuration is similar to the Kubernetes Ingress resources, in below yaml file any traffic from &lt;a target=&quot;_blank&quot; href=&quot;http://apisix.localhost/&quot;&gt;&lt;code&gt;http://apisix.localhost/&lt;/code&gt;&lt;/a&gt; will be routed to &lt;code&gt;apisix-dashboard&lt;/code&gt; service to port 80.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#filename:  apisix-dashboard-ingress.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-dashboard-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-apisix&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# The namespace where the apisix is installed&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingressClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix.localhost&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;backend:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-dashboard&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;number:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;pathType:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Prefix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the ingress configuration in &lt;code&gt;apisix-dashboard-ingress.yaml&lt;/code&gt; and use below command to deploy.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubect apply -f apisix-dashboard-ingress.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-configure-hosts-file-with-domain-name-for-loop-back-address&quot;&gt;Configure hosts file with domain name for loop back address&lt;/h3&gt;&lt;p&gt;Open the hosts file and add below domains for loop back address (127.0.0.1)&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;127.0.0.1 localhost apisix.localhost zitadel.local backend.localhost&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, open a browser and we should be able to access the Apisix dashboard.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;To login the user name and password is admin&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/2786d503-3e4b-400e-894b-690c0176bc29&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;The configured routes will be displayed in the dashbord like&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/42c554ba-e304-423e-9d98-911ca312fef7&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Info :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Installing &lt;code&gt;Apisix ingress controller&lt;/code&gt; is optional, if &lt;strong&gt;not&lt;/strong&gt; installed the route configuration should be created and updated manually.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is optional only if Apisix ingress controller is NOT installed. To update the route configuration manually to Apisix.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Port forward the &lt;code&gt;apisix-admin&lt;/code&gt; service use command - &lt;code&gt;kubectl -n ingress-apisix port-forward svc apisix-admin 9180:9180&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol start=&quot;2&quot;&gt;&lt;li&gt;&lt;p&gt;Obtain the admin key from the override values yaml under &lt;code&gt;apisix.admin.credentials.admin&lt;/code&gt;. In this demonstration this default value as mentioned in Apisix documentation.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;ol start=&quot;3&quot;&gt;&lt;li&gt;Use Curl command to configure route. Below is the curl command to configure Apisix dashboard route.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;  curl http://127.0.0.1:9180/apisix/admin/routes/1 \      -H &lt;span class=&quot;hljs-string&quot;&gt;&quot;X-API-KEY: &lt;span class=&quot;hljs-variable&quot;&gt;$admin_key&lt;/span&gt;&quot;&lt;/span&gt; -X PUT -i -d &lt;span class=&quot;hljs-string&quot;&gt;&apos;      {        &quot;name&quot;: &quot;apisix-dashboard-route&quot;,        &quot;desc&quot;: &quot;Route for apisix dashboard&quot;,        &quot;labels&quot;: {&quot;created-by&quot;: &quot;user&quot;},        &quot;uris&quot;: [&quot;/&quot;,&quot;/*&quot;],        &quot;host&quot;: &quot;apisix.localhost&quot;,        &quot;upstream&quot;: {            &quot;name&quot;: &quot;apisix-dashboard-upstream&quot;,            &quot;desc&quot;: &quot;upstream for apisix dashboard route&quot;,            &quot;labels&quot;: {&quot;created-by&quot;: &quot;user&quot;},            &quot;type&quot;: &quot;roundrobin&quot;,            &quot;hash_on&quot;: &quot;vars&quot;,            &quot;scheme&quot;: &quot;http&quot;,            &quot;pass_host&quot;: &quot;pass&quot;,            &quot;nodes&quot;: [{&quot;host&quot;:&quot;apisix-dashboard.ingress-apisix&quot;,&quot;port&quot;:80, &quot;weight&quot;: 100 }],            &quot;timeout&quot;: { &quot;connect&quot;: 60,&quot;send&quot;: 60,&quot;read&quot;: 60 }          }      }&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-apisix-route-configuration-representation&quot;&gt;Apisix route configuration representation&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/d14ccbb6-4f76-4266-984d-306e4f78528b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Sample Apisix Dashboard route view showing all three parts &lt;code&gt;route&lt;/code&gt;, &lt;code&gt;plugins&lt;/code&gt; and &lt;code&gt;upstream&lt;/code&gt; in route configuration.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/e25f6128-2016-4e5c-9f4c-1d25e546e592&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-installing-zitadel&quot;&gt;Installing Zitadel&lt;/h2&gt;&lt;p&gt;Zitadel installed with secure Postgres, below are the steps involved&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Installing certificates&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Installing Postgres DB&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Installing Zitadel&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In order to configure the standalone Zitadel we need to define the &lt;code&gt;ExternalDomain&lt;/code&gt; and &lt;code&gt;ExternalPort&lt;/code&gt; in the Zitadel override yaml configuration.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Latter in this blog, we configure a Nginx backend application to be accessed using Apisix route with oidc-connector plugin to connect to Zitadel.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Apisix pod tries to discover the Zitadel OIDC url within the pod which does not resolve &lt;a target=&quot;_blank&quot; href=&quot;http://zitadel.localhost&quot;&gt;&lt;code&gt;http://zitadel.localhost&lt;/code&gt;&lt;/a&gt;. As a workaround, have created the helm release with the name &lt;code&gt;zitadel&lt;/code&gt; (this creates the service as &lt;code&gt;zitadel&lt;/code&gt;)and the app installed in &lt;code&gt;local&lt;/code&gt; namespace. With this configuration, the url looks like &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.local&quot;&gt;&lt;code&gt;https://zitadel.local&lt;/code&gt;&lt;/a&gt;, Apisix pod is able to resolve this url since kubernetes DNS resolution &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;&lt;/code&gt; is also same as the &lt;code&gt;ExternalDomain&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-installing-certificates&quot;&gt;Installing certificates&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The certificate configuration yaml file is provided in the Zitadel documentation so we use that as such without any customization. Below are the instruction to deploy.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Create namespace&lt;/span&gt;kubectl create namespace &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Generate TLS certificates&lt;/span&gt;kubectl apply -f https://raw.githubusercontent.com/zitadel/zitadel-charts/main/examples/2-postgres-secure/certs-job.yaml -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# wait till the job is completed &lt;/span&gt;kubectl &lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt; --&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt;=condition=complete job/create-certs -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-postgres&quot;&gt;Install Postgres&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is the Postgres override values yaml file which will be used for Postgres deployment.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: postgres-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;volumePermissions:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certificatesSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;tls.crt&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certKeyFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;tls.key&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;auth:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;postgresPassword:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the above content in a file &lt;code&gt;postgres-values.yaml&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Use below commands to install the 15.2.11 (latest version at the time of writting).&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo updatehelm install --&lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt; db bitnami/postgresql --version 15.2.11 --values postgres-values.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-zitadel-app&quot;&gt;Install Zitadel app&lt;/h3&gt;&lt;p&gt;To add the helm repo to local&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add zitadel https://charts.zitadel.comhelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Zitadel override values yaml file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# zitadel-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;zitadel:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;masterkey:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;x123456789012345678901234567891y&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;configmapConfig:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalSecure:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# modify the external domain to localhost or any domain exists&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# currently this value will be overrided from helm command with set&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalDomain:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# add this configuration since we have ingress&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;TLS:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Postgres:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;db-postgresql&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5432&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxOpenConns:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxIdleConns:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxConnLifetime:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;30m&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxConnIdleTime:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;5m&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;User:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;SSL:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;Mode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;verify-full&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Admin:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;SSL:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;Mode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;verify-full&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;secretConfig:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Postgres:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;User:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;xyz&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Admin:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;abc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslCaCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslAdminCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslUserCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel-cert&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the content in file named &lt;code&gt;zitadel-values.yaml&lt;/code&gt;, Note, the service port is set as 80, instead of default 8080 which will be configured in Apisix ingress configuration yaml as well.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Use below command to deploy the zitadel in &lt;code&gt;local&lt;/code&gt; namespace.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm upgrade --install zitadel -f ./zitadel-values.yaml . \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; zitadel.configmapConfig.ExternalDomain=zitadel.local \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; zitadel.configmapConfig.ExternalPort=80 \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.port=80 \    --create-namespace \    --namespace &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-creating-zitadel-apisix-route&quot;&gt;Creating Zitadel Apisix route&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Apisix route configuration&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# apisix-zitadel-ingress.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-zitadel-ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingressClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel.local&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;backend:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;number:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;pathType:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Prefix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the yaml content to &lt;code&gt;apisix-zitadel-ingress.yaml&lt;/code&gt; and use below command to install zitadel ingress route.    &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f apisix-zitadel-ingress.yaml -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Zitadel UI should be accessible via &lt;a target=&quot;_blank&quot; href=&quot;http://zitadel.local&quot;&gt;&lt;code&gt;http://zitadel.local&lt;/code&gt;&lt;/a&gt; from browser. In the login page when prompted the username is &lt;code&gt;zitadel-admin@zitadel.zitadel.local&lt;/code&gt; and default password is &lt;code&gt;Password1!&lt;/code&gt;. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.com/docs/self-hosting/deploy/linux&quot;&gt;documentation&lt;/a&gt; for more info.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Upon first access the UI looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/55668ec2-59bb-4662-ad81-9c28f61bf797&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-create-nginx-backend-app-access-with-apisix-and-zitadel-configuration&quot;&gt;Create Nginx Backend app access with Apisix and Zitadel configuration&lt;/h2&gt;&lt;h3 id=&quot;heading-creating-simple-nginx-backend-application&quot;&gt;Creating simple Nginx backend application&lt;/h3&gt;&lt;p&gt;Below is the manifest file to deploy simple NGINX app with an endpoint &lt;code&gt;/greet&lt;/code&gt; which responds back with JSON object.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;nginx.conf:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    worker_processes auto;    error_log stderr notice;    events {      worker_connections 1024;    }    http {      variables_hash_max_size 1024;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;$remote_addr - $remote_user [%time_local] &quot;$request&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;off;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;real_ip_header&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;X-Real-IP;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;utf-8;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;server&lt;/span&gt; {        &lt;span class=&quot;hljs-string&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;hljs-string&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt; {          &lt;span class=&quot;hljs-string&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application/json;&lt;/span&gt;          &lt;span class=&quot;hljs-string&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;status&quot;:&quot;OK&quot;,&quot;message&quot;:&quot;Greetings!! from server&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        }      }    &lt;span class=&quot;hljs-string&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;         &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt;           &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;         &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;requests:&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;128Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;250m&quot;&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;limits:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;256Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;500m&quot;&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before updating the Apisix route, to configure Zitadel as oidc-connector plugin, create Project and Application in Zitadel for client_id and client_secret.&lt;/p&gt;&lt;p&gt;Using Zitadel UI, create a project and input a project name.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Click the &lt;code&gt;Create an application&lt;/code&gt; and input name for application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Select &lt;code&gt;Web&lt;/code&gt; and click continue.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/74fc4c3d-855e-4052-bef0-66e0cbf0473b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Select &lt;code&gt;code&lt;/code&gt; (the screen looks like below)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/3641f8d8-aa16-40c1-a2f2-528facfaee79&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Input the redirect url, enable the &lt;code&gt;Development Mode&lt;/code&gt; since we are using &lt;code&gt;http&lt;/code&gt; url. In the &lt;code&gt;Redirect URIshttp://backend.localhost/greet/redirect&lt;/code&gt;. This is the URL Zitadel redirects after successful authentication.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/1386a352-06ea-4b80-bdc4-217aa0cf37c8&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Upon saving the screen displays &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; make a note of it. Once closed this will not be displayed, else we need to re-create it.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the screen where URLs provided by the Zitadel Identity Provider.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/054b1a96-32aa-48a9-9b50-ea814a9e9ada&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;In the Apisix route configuration below the plugins &lt;code&gt;redirect_uri:&lt;/code&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet/redirect&quot;&gt;&lt;code&gt;http://backend.localhost/greet/redirect&lt;/code&gt;&lt;/a&gt;which should match the route config.&lt;/p&gt;&lt;p&gt;Note, if the redirect_uri match the route config exactly, noticed issues in the Apisix logs when accessing the backend app, refer &lt;a target=&quot;_blank&quot; href=&quot;https://apisix.apache.org/docs/apisix/plugins/openid-connect/#troubleshooting&quot;&gt;zitadel documentation&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this case the host is &lt;code&gt;backend.localhost&lt;/code&gt; and uri is &lt;code&gt;/*&lt;/code&gt; and we configured uri as &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet/redirect&quot;&gt;&lt;code&gt;http://backend.localhost/greet/redirect&lt;/code&gt;&lt;/a&gt;. The redirect in the uri is not configured in the backend app on Nginx config.&lt;/p&gt;&lt;p&gt;Complete Apisix route configuration using the Apisix dashboard and the completed configuration looks like below. Update the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; from the Zitadel application.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;uri&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;/*&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend-app&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;methods&quot;&lt;/span&gt;: [    &lt;span class=&quot;hljs-string&quot;&gt;&quot;GET&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-string&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;  ],  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend.localhost&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;plugins&quot;&lt;/span&gt;: {    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;openid-connect&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;_meta&quot;&lt;/span&gt;: {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;disable&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      },      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;bearer_only&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;client_id&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;****clientid created in zitadel app****&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;client_secret&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;*** Zitadel app client secret *****&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;discovery&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://zitadel.local/.well-known/openid-configuration&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;introspection_endpoint&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://zitadel.local/oauth/v2/introspect&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;realm&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;master&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;redirect_uri&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://backend.localhost/greet/redirect&quot;&lt;/span&gt;    }  },  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;upstream&quot;&lt;/span&gt;: {    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;nodes&quot;&lt;/span&gt;: [      {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend-svc.backend-app&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;port&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;weight&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;      }    ],    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;timeout&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;connect&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;send&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;read&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;    },    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;roundrobin&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;scheme&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;pass_host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;pass&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;keepalive_pool&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;idle_timeout&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;requests&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;size&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;320&lt;/span&gt;    }  },  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;status&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Click the Route section on Apisix Dashboard to create the Route configuration, shown in below snapshot.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/28c5ad66-b657-4842-ada8-05a16f030dc9&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Update the upstream configuration, the Host configuration is &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;&lt;/code&gt; of the backend application service.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/da51ef6d-697f-43be-9511-2a49df16443e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Edit the openid-connect plugin and update the configuration&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/fef1c9c3-ad07-40a9-8dec-86c705877380&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Enable the plugin and click submit to create the route configuration.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/83c2c7dd-08a2-47ba-b8ae-4edb4d6194c2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-accessing-backend-app-from-browser&quot;&gt;Accessing backend app from browser&lt;/h3&gt;&lt;p&gt;The &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet&quot;&gt;&lt;code&gt;http://backend.localhost/greet&lt;/code&gt;&lt;/a&gt; redirects to &lt;code&gt;zitadel.local&lt;/code&gt; Zitadel login page.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/cd579785-f392-4a26-9cf5-3d5c8f9d9b6a&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/7932aa16-5995-46b7-8fd5-ad925210b2ef&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;After successful authentication the JSON payload will be displayed in the browser.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/c9b405aa-0230-4657-83b3-2218b99f99b2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;In certain case if browser throws 500 internal server error check the Apisix container logs to see if the correct redirect url is logged.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/807f6c09-fda8-4e00-a299-22405df90c81&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h1 id=&quot;heading-deploying-apache-apisix-and-zitadel-in-kubernetes&quot;&gt;Deploying Apache Apisix and Zitadel in Kubernetes&lt;/h1&gt;&lt;p&gt;In this blog will be demonstrating how to setup Apisix and Zitadel in Kind Kubernetes cluster for development.&lt;/p&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;p&gt;Software to be installed&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Docker desktop&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kind&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Helm&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kubectl&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Basic understanding on Gateway and OpenId Connect.&lt;/p&gt;&lt;h2 id=&quot;heading-what-is-apache-apisix&quot;&gt;What is Apache Apisix?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Apache Apisix is opensource API Gateway based on Nginx and etcd.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this demonstration Apache Apisix is installed to cluster using helm chart, along with Apisix Dashboard and Apisix Ingress controller.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This is only for development and &lt;strong&gt;not&lt;/strong&gt; production grade. For more info refer the &lt;a target=&quot;_blank&quot; href=&quot;https://apisix.apache.org&quot;&gt;Apache Apisix&lt;/a&gt; documentation.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-what-is-zitadel&quot;&gt;What is Zitadel?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Zitadel provides identity management service along with authentication management. Zitadel can also be installed as standalone application, refer &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.com/docs/guides/start/quickstart&quot;&gt;Zitadel&lt;/a&gt; documentation.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this demonstration Zitadel application is installed with helm chart along with UI dashboard.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Prior to deploying Zitadel application the define a domain name, this value should be set in the configuration &lt;code&gt;ExternalDomain&lt;/code&gt; either in override values or passed as helm command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Zitadel can be installed with either Cockroach db or Postgres db. In this demonstartion Postgres db is used.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;Externaldomain&lt;/code&gt; value is also used as part of default username and for password check the documentation.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-installing-kind-cluster&quot;&gt;Installing Kind Cluster&lt;/h2&gt;&lt;p&gt;Below yaml defines the Kind cluster configuration, with Docker desktop running we can create the the cluster with this configuration.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The ingress option is enabled in the kind cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Apisix exposes the Gateway service as NodePort or Loadbalancer. In here NodePort service is used and port 30080 is exposed.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;By configuring the ports in &lt;code&gt;extraPortMappings&lt;/code&gt; the Apisix Dashboard can be accessed doesn&apos;t require port-forwarding.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: kind-cluster.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-zitadel&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kubeadmConfigPatches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    kind: InitConfiguration    nodeRegistration:      kubeletExtraArgs:        node-labels: &quot;ingress-ready=true&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30080&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the content of kind configuration to a file named &lt;code&gt;kind-cluster.yaml&lt;/code&gt; and use below command to create cluster.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kind create cluster --config kind-cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-installing-apisix&quot;&gt;Installing Apisix&lt;/h2&gt;&lt;p&gt;To install Apsix with helm charts, add the helm repo to local and issue update command like below.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add apisix https://charts.apiseven.comhelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In here we pull the chart to local and use it. To download the latest chart to local use the command below.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm pull apisix/apisix --untar&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Alternatively, you can download the helm charts from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/apache/apisix-helm-chart&quot;&gt;Apisix Helm Chart repo&lt;/a&gt;, requires understanding on helm charts.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;In the downloaded helm chart update the chart version of &lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;apisix-dashboard&lt;/code&gt; and &lt;code&gt;apisix-ingress-controller&lt;/code&gt; in &lt;code&gt;chart.yaml&lt;/code&gt; file to latest version (below is the version number at the time if this writing)&lt;/p&gt;&lt;p&gt;After updating the version issue the command &lt;code&gt;helm dependency update&lt;/code&gt; from the chart directory, helm will pull the specified version of dependent chart under the &lt;code&gt;charts&lt;/code&gt; folder.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;appVersion:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.9&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;sources:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://github.com/apache/apisix-helm-chart&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;dependencies:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;etcd&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.bitnami.com/bitnami&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;etcd.enabled&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-dashboard&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.2&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.apiseven.com&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dashboard.enabled&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dashboard&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-ingress-controller&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.14&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;https://charts.apiseven.com&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;condition:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-controller.enabled&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;alias:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-controller&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-custom-override-values-yaml-for-apisix-chart&quot;&gt;Custom override values yaml for Apisix chart&lt;/h3&gt;&lt;p&gt;The override values file for Apisix deploymentis used for this deployment. Note, only few configuration is updated like image tag name of initContainer, http service ports for Apisix service. Refer the documentation for mode customization, but for local development this should suffice.&lt;/p&gt;&lt;p&gt;The Apisix discovery registry is enabled with Kubernetes cluster. There are other registry option which can be configured, refer documentation.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: apisix-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;repository:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apache/apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tag:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.8&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;-debian&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;initContainer:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;busybox&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tag:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;serviceAccount:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;rbac:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;NodePort&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;externalTrafficPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;externalIPs:&lt;/span&gt; []  &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9080&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30080&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;# port used in kind cluster configuration&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apisix:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enableIPv6:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enableServerTokens:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;admin:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ClusterIP&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;externalIPs:&lt;/span&gt; []    &lt;span class=&quot;hljs-attr&quot;&gt;ip:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;servicePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9180&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;cors:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;credentials:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;admin:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;edd1c9f034335f136f87ad84b625c8f1&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# Default value as in values yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;viewer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;4054f7cf07e344346cd3f287985e76a2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;discovery:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;registry:&lt;/span&gt;     &lt;span class=&quot;hljs-attr&quot;&gt;kubernetes:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;schema:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${KUBERNETES_SERVICE_HOST}&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;${KUBERNETES_SERVICE_PORT}&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;externalEtcd:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;http://etcd.host:2379&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;existingSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;secretPasswordKey:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;etcd-root-password&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;etcd:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;/apisix&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;timeout:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;auth:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;rbac:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;create:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;rootPassword:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;existingSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;certFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;certKeyFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;verify:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;sni:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2379&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Apisix Dashboard configuration&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;dashboard:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;conf:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;etcd:&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;# -- Supports defining multiple etcd host addresses for an etcd cluster&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;endpoints:&lt;/span&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-etcd:2379&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;prefix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;/apisix&quot;&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;~&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# -- Ingress controller configuration&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;ingress-controller:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;IfNotPresent&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;apisix:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;adminAPIVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;v3&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the above content in a file &lt;code&gt;apisix-values.yaml&lt;/code&gt; as override values yaml within the apisix chart directory.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below command will install &lt;code&gt;Apisix&lt;/code&gt;, &lt;code&gt;Apisix Dashboard&lt;/code&gt; and &lt;code&gt;Apisix Ingress Controller&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-bash&quot;&gt;helm upgrade --install apisix -f apisix-values.yaml . \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.type=NodePort \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.http.nodePort=30080 \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; ingress-controller.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; dashboard.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; \    --create-namespace \    --namespace ingress-apisix \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; ingress-controller.config.apisix.serviceNamespace=ingress-apisix&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Not all the configuration in override values yaml is customized, compare it with default values yaml file.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Also, the line &lt;code&gt;--set service.type=NodePort --set service.http.nodePort=30080&lt;/code&gt; in helm command can be removed since they are already added override yaml.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;To check the status of Apisix deployments use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl -n ingress-apisix get pods,svc&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/6625d78f-b0ba-4fa9-8714-a0b32af11f56&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-install-ingress-route-for-apisix-dashboard&quot;&gt;Install Ingress route for Apisix dashboard&lt;/h3&gt;&lt;p&gt;Once the &lt;code&gt;Apisix ingress controller&lt;/code&gt; pod is in running state,Apisix dashboard ingress route can be configured to access from browser.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Info :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Apisix Ingress controller&lt;/code&gt; uses CRD&apos;s to resolve Apisix routes and also resolves Ingress resource definition. It creates route and registers in apisix application as well.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;The ingress configuration is similar to the Kubernetes Ingress resources, in below yaml file any traffic from &lt;a target=&quot;_blank&quot; href=&quot;http://apisix.localhost/&quot;&gt;&lt;code&gt;http://apisix.localhost/&lt;/code&gt;&lt;/a&gt; will be routed to &lt;code&gt;apisix-dashboard&lt;/code&gt; service to port 80.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#filename:  apisix-dashboard-ingress.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-dashboard-ingress&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ingress-apisix&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# The namespace where the apisix is installed&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingressClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix.localhost&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;backend:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix-dashboard&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;number:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;pathType:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Prefix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the ingress configuration in &lt;code&gt;apisix-dashboard-ingress.yaml&lt;/code&gt; and use below command to deploy.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubect apply -f apisix-dashboard-ingress.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-configure-hosts-file-with-domain-name-for-loop-back-address&quot;&gt;Configure hosts file with domain name for loop back address&lt;/h3&gt;&lt;p&gt;Open the hosts file and add below domains for loop back address (127.0.0.1)&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;127.0.0.1 localhost apisix.localhost zitadel.local backend.localhost&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, open a browser and we should be able to access the Apisix dashboard.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;To login the user name and password is admin&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/2786d503-3e4b-400e-894b-690c0176bc29&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;The configured routes will be displayed in the dashbord like&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/42c554ba-e304-423e-9d98-911ca312fef7&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Info :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Installing &lt;code&gt;Apisix ingress controller&lt;/code&gt; is optional, if &lt;strong&gt;not&lt;/strong&gt; installed the route configuration should be created and updated manually.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is optional only if Apisix ingress controller is NOT installed. To update the route configuration manually to Apisix.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Port forward the &lt;code&gt;apisix-admin&lt;/code&gt; service use command - &lt;code&gt;kubectl -n ingress-apisix port-forward svc apisix-admin 9180:9180&lt;/code&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol start=&quot;2&quot;&gt;&lt;li&gt;&lt;p&gt;Obtain the admin key from the override values yaml under &lt;code&gt;apisix.admin.credentials.admin&lt;/code&gt;. In this demonstration this default value as mentioned in Apisix documentation.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;ol start=&quot;3&quot;&gt;&lt;li&gt;Use Curl command to configure route. Below is the curl command to configure Apisix dashboard route.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;  curl http://127.0.0.1:9180/apisix/admin/routes/1 \      -H &lt;span class=&quot;hljs-string&quot;&gt;&quot;X-API-KEY: &lt;span class=&quot;hljs-variable&quot;&gt;$admin_key&lt;/span&gt;&quot;&lt;/span&gt; -X PUT -i -d &lt;span class=&quot;hljs-string&quot;&gt;&apos;      {        &quot;name&quot;: &quot;apisix-dashboard-route&quot;,        &quot;desc&quot;: &quot;Route for apisix dashboard&quot;,        &quot;labels&quot;: {&quot;created-by&quot;: &quot;user&quot;},        &quot;uris&quot;: [&quot;/&quot;,&quot;/*&quot;],        &quot;host&quot;: &quot;apisix.localhost&quot;,        &quot;upstream&quot;: {            &quot;name&quot;: &quot;apisix-dashboard-upstream&quot;,            &quot;desc&quot;: &quot;upstream for apisix dashboard route&quot;,            &quot;labels&quot;: {&quot;created-by&quot;: &quot;user&quot;},            &quot;type&quot;: &quot;roundrobin&quot;,            &quot;hash_on&quot;: &quot;vars&quot;,            &quot;scheme&quot;: &quot;http&quot;,            &quot;pass_host&quot;: &quot;pass&quot;,            &quot;nodes&quot;: [{&quot;host&quot;:&quot;apisix-dashboard.ingress-apisix&quot;,&quot;port&quot;:80, &quot;weight&quot;: 100 }],            &quot;timeout&quot;: { &quot;connect&quot;: 60,&quot;send&quot;: 60,&quot;read&quot;: 60 }          }      }&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-apisix-route-configuration-representation&quot;&gt;Apisix route configuration representation&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/d14ccbb6-4f76-4266-984d-306e4f78528b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Sample Apisix Dashboard route view showing all three parts &lt;code&gt;route&lt;/code&gt;, &lt;code&gt;plugins&lt;/code&gt; and &lt;code&gt;upstream&lt;/code&gt; in route configuration.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/e25f6128-2016-4e5c-9f4c-1d25e546e592&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-installing-zitadel&quot;&gt;Installing Zitadel&lt;/h2&gt;&lt;p&gt;Zitadel installed with secure Postgres, below are the steps involved&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Installing certificates&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Installing Postgres DB&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Installing Zitadel&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In order to configure the standalone Zitadel we need to define the &lt;code&gt;ExternalDomain&lt;/code&gt; and &lt;code&gt;ExternalPort&lt;/code&gt; in the Zitadel override yaml configuration.&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Note :-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Latter in this blog, we configure a Nginx backend application to be accessed using Apisix route with oidc-connector plugin to connect to Zitadel.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Apisix pod tries to discover the Zitadel OIDC url within the pod which does not resolve &lt;a target=&quot;_blank&quot; href=&quot;http://zitadel.localhost&quot;&gt;&lt;code&gt;http://zitadel.localhost&lt;/code&gt;&lt;/a&gt;. As a workaround, have created the helm release with the name &lt;code&gt;zitadel&lt;/code&gt; (this creates the service as &lt;code&gt;zitadel&lt;/code&gt;)and the app installed in &lt;code&gt;local&lt;/code&gt; namespace. With this configuration, the url looks like &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.local&quot;&gt;&lt;code&gt;https://zitadel.local&lt;/code&gt;&lt;/a&gt;, Apisix pod is able to resolve this url since kubernetes DNS resolution &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;&lt;/code&gt; is also same as the &lt;code&gt;ExternalDomain&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-installing-certificates&quot;&gt;Installing certificates&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The certificate configuration yaml file is provided in the Zitadel documentation so we use that as such without any customization. Below are the instruction to deploy.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Create namespace&lt;/span&gt;kubectl create namespace &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Generate TLS certificates&lt;/span&gt;kubectl apply -f https://raw.githubusercontent.com/zitadel/zitadel-charts/main/examples/2-postgres-secure/certs-job.yaml -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# wait till the job is completed &lt;/span&gt;kubectl &lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt; --&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt;=condition=complete job/create-certs -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-postgres&quot;&gt;Install Postgres&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is the Postgres override values yaml file which will be used for Postgres deployment.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# filename: postgres-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;volumePermissions:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certificatesSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;tls.crt&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;certKeyFilename:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;tls.key&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;auth:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;postgresPassword:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the above content in a file &lt;code&gt;postgres-values.yaml&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Use below commands to install the 15.2.11 (latest version at the time of writting).&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo updatehelm install --&lt;span class=&quot;hljs-built_in&quot;&gt;wait&lt;/span&gt; db bitnami/postgresql --version 15.2.11 --values postgres-values.yaml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-zitadel-app&quot;&gt;Install Zitadel app&lt;/h3&gt;&lt;p&gt;To add the helm repo to local&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm repo add zitadel https://charts.zitadel.comhelm repo update&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Zitadel override values yaml file&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# zitadel-values.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;zitadel:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;masterkey:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;x123456789012345678901234567891y&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;configmapConfig:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalSecure:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# modify the external domain to localhost or any domain exists&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# currently this value will be overrided from helm command with set&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalDomain:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;# add this configuration since we have ingress&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;ExternalPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;TLS:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Enabled:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Postgres:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;db-postgresql&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5432&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxOpenConns:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxIdleConns:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxConnLifetime:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;30m&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;MaxConnIdleTime:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;5m&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;User:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;SSL:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;Mode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;verify-full&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Admin:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;SSL:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;Mode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;verify-full&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;secretConfig:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;Database:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;Postgres:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;User:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;xyz&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;Admin:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;Password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;abc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslCaCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslAdminCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;postgres-cert&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;dbSslUserCrtSecret:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel-cert&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicaCount:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the content in file named &lt;code&gt;zitadel-values.yaml&lt;/code&gt;, Note, the service port is set as 80, instead of default 8080 which will be configured in Apisix ingress configuration yaml as well.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Use below command to deploy the zitadel in &lt;code&gt;local&lt;/code&gt; namespace.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;helm upgrade --install zitadel -f ./zitadel-values.yaml . \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; zitadel.configmapConfig.ExternalDomain=zitadel.local \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; zitadel.configmapConfig.ExternalPort=80 \    --&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt; service.port=80 \    --create-namespace \    --namespace &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-creating-zitadel-apisix-route&quot;&gt;Creating Zitadel Apisix route&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Apisix route configuration&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# apisix-zitadel-ingress.yaml&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;api6-zitadel-ingress&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ingressClassName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apisix&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;rules:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;host:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel.local&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;http:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;backend:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;zitadel&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;number:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;pathType:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Prefix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save the yaml content to &lt;code&gt;apisix-zitadel-ingress.yaml&lt;/code&gt; and use below command to install zitadel ingress route.    &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;kubectl apply -f apisix-zitadel-ingress.yaml -n &lt;span class=&quot;hljs-built_in&quot;&gt;local&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The Zitadel UI should be accessible via &lt;a target=&quot;_blank&quot; href=&quot;http://zitadel.local&quot;&gt;&lt;code&gt;http://zitadel.local&lt;/code&gt;&lt;/a&gt; from browser. In the login page when prompted the username is &lt;code&gt;zitadel-admin@zitadel.zitadel.local&lt;/code&gt; and default password is &lt;code&gt;Password1!&lt;/code&gt;. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://zitadel.com/docs/self-hosting/deploy/linux&quot;&gt;documentation&lt;/a&gt; for more info.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Upon first access the UI looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/55668ec2-59bb-4662-ad81-9c28f61bf797&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-create-nginx-backend-app-access-with-apisix-and-zitadel-configuration&quot;&gt;Create Nginx Backend app access with Apisix and Zitadel configuration&lt;/h2&gt;&lt;h3 id=&quot;heading-creating-simple-nginx-backend-application&quot;&gt;Creating simple Nginx backend application&lt;/h3&gt;&lt;p&gt;Below is the manifest file to deploy simple NGINX app with an endpoint &lt;code&gt;/greet&lt;/code&gt; which responds back with JSON object.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;nginx.conf:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    worker_processes auto;    error_log stderr notice;    events {      worker_connections 1024;    }    http {      variables_hash_max_size 1024;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;log_format&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;$remote_addr - $remote_user [%time_local] &quot;$request&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;&lt;/span&gt;                      &lt;span class=&quot;hljs-string&quot;&gt;&apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;access_log&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;off;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;real_ip_header&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;X-Real-IP;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;charset&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;utf-8;&lt;/span&gt;      &lt;span class=&quot;hljs-string&quot;&gt;server&lt;/span&gt; {        &lt;span class=&quot;hljs-string&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;hljs-string&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/greet&lt;/span&gt; {          &lt;span class=&quot;hljs-string&quot;&gt;default_type&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application/json;&lt;/span&gt;          &lt;span class=&quot;hljs-string&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;status&quot;:&quot;OK&quot;,&quot;message&quot;:&quot;Greetings!! from server&quot;}&apos;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;;&lt;/span&gt;        }      }    &lt;span class=&quot;hljs-string&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;       &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;         &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt;           &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx.conf&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;         &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx-config&lt;/span&gt;           &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/etc/nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;requests:&lt;/span&gt;             &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;128Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;250m&quot;&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;limits:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;memory:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;256Mi&quot;&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;cpu:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;500m&quot;&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-svc&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-app&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;backend-server&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before updating the Apisix route, to configure Zitadel as oidc-connector plugin, create Project and Application in Zitadel for client_id and client_secret.&lt;/p&gt;&lt;p&gt;Using Zitadel UI, create a project and input a project name.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Click the &lt;code&gt;Create an application&lt;/code&gt; and input name for application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Select &lt;code&gt;Web&lt;/code&gt; and click continue.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/74fc4c3d-855e-4052-bef0-66e0cbf0473b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Select &lt;code&gt;code&lt;/code&gt; (the screen looks like below)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/3641f8d8-aa16-40c1-a2f2-528facfaee79&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Input the redirect url, enable the &lt;code&gt;Development Mode&lt;/code&gt; since we are using &lt;code&gt;http&lt;/code&gt; url. In the &lt;code&gt;Redirect URIshttp://backend.localhost/greet/redirect&lt;/code&gt;. This is the URL Zitadel redirects after successful authentication.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/1386a352-06ea-4b80-bdc4-217aa0cf37c8&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Upon saving the screen displays &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; make a note of it. Once closed this will not be displayed, else we need to re-create it.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the screen where URLs provided by the Zitadel Identity Provider.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/054b1a96-32aa-48a9-9b50-ea814a9e9ada&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;In the Apisix route configuration below the plugins &lt;code&gt;redirect_uri:&lt;/code&gt; &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet/redirect&quot;&gt;&lt;code&gt;http://backend.localhost/greet/redirect&lt;/code&gt;&lt;/a&gt;which should match the route config.&lt;/p&gt;&lt;p&gt;Note, if the redirect_uri match the route config exactly, noticed issues in the Apisix logs when accessing the backend app, refer &lt;a target=&quot;_blank&quot; href=&quot;https://apisix.apache.org/docs/apisix/plugins/openid-connect/#troubleshooting&quot;&gt;zitadel documentation&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In this case the host is &lt;code&gt;backend.localhost&lt;/code&gt; and uri is &lt;code&gt;/*&lt;/code&gt; and we configured uri as &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet/redirect&quot;&gt;&lt;code&gt;http://backend.localhost/greet/redirect&lt;/code&gt;&lt;/a&gt;. The redirect in the uri is not configured in the backend app on Nginx config.&lt;/p&gt;&lt;p&gt;Complete Apisix route configuration using the Apisix dashboard and the completed configuration looks like below. Update the &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; from the Zitadel application.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;uri&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;/*&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend-app&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;methods&quot;&lt;/span&gt;: [    &lt;span class=&quot;hljs-string&quot;&gt;&quot;GET&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-string&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;  ],  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend.localhost&quot;&lt;/span&gt;,  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;plugins&quot;&lt;/span&gt;: {    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;openid-connect&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;_meta&quot;&lt;/span&gt;: {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;disable&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      },      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;bearer_only&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;client_id&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;****clientid created in zitadel app****&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;client_secret&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;*** Zitadel app client secret *****&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;discovery&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://zitadel.local/.well-known/openid-configuration&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;introspection_endpoint&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://zitadel.local/oauth/v2/introspect&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;realm&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;master&quot;&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;redirect_uri&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://backend.localhost/greet/redirect&quot;&lt;/span&gt;    }  },  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;upstream&quot;&lt;/span&gt;: {    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;nodes&quot;&lt;/span&gt;: [      {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;backend-svc.backend-app&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;port&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;8081&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;weight&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;      }    ],    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;timeout&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;connect&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;send&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;read&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;    },    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;roundrobin&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;scheme&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;http&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;pass_host&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;pass&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;keepalive_pool&quot;&lt;/span&gt;: {      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;idle_timeout&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;requests&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;,      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;size&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;320&lt;/span&gt;    }  },  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;status&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Click the Route section on Apisix Dashboard to create the Route configuration, shown in below snapshot.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/28c5ad66-b657-4842-ada8-05a16f030dc9&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Update the upstream configuration, the Host configuration is &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;&lt;/code&gt; of the backend application service.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/da51ef6d-697f-43be-9511-2a49df16443e&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Edit the openid-connect plugin and update the configuration&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/fef1c9c3-ad07-40a9-8dec-86c705877380&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;Enable the plugin and click submit to create the route configuration.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/83c2c7dd-08a2-47ba-b8ae-4edb4d6194c2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-accessing-backend-app-from-browser&quot;&gt;Accessing backend app from browser&lt;/h3&gt;&lt;p&gt;The &lt;a target=&quot;_blank&quot; href=&quot;http://backend.localhost/greet&quot;&gt;&lt;code&gt;http://backend.localhost/greet&lt;/code&gt;&lt;/a&gt; redirects to &lt;code&gt;zitadel.local&lt;/code&gt; Zitadel login page.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/cd579785-f392-4a26-9cf5-3d5c8f9d9b6a&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/7932aa16-5995-46b7-8fd5-ad925210b2ef&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;After successful authentication the JSON payload will be displayed in the browser.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/c9b405aa-0230-4657-83b3-2218b99f99b2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;In certain case if browser throws 500 internal server error check the Apisix container logs to see if the correct redirect url is logged.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/807f6c09-fda8-4e00-a299-22405df90c81&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Operator SDK - Create Controller and CRD to deploy Spring app in K8S cluster]]></title><description><![CDATA[The blog shows how to create CRD and controller logic using Operator SDK with simple spring project.]]></description><link>https://thirumurthi.hashnode.dev/operator-sdk-create-controller-and-crd-to-deploy-spring-app-in-k8s-cluster</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/operator-sdk-create-controller-and-crd-to-deploy-spring-app-in-k8s-cluster</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[operator SDK]]></category><category><![CDATA[CRD]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 19 Aug 2023 14:34:21 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-operator-pattern-to-deploy-springboot-application&quot;&gt;Operator pattern to deploy SpringBoot application&lt;/h2&gt;&lt;p&gt;In this article we will be using Operator SDK to create Custom Resource Definition (CRD) and Controller logic to deploy a Spring application in Kubernetes cluster.&lt;/p&gt;&lt;p&gt;With reference to my previous &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/extend-kubernetes-api-with-operator-sdk&quot;&gt;operator-sdk blog&lt;/a&gt;, we will use the same scaffolded and initialized project structure to create the CRD and reconcile logic. The reconciler logic will programmatically create Kubernetes resources object (using k8s.io/core libraries) like Deployment, ConfigMap, Service and deploy them to the cluster.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes&lt;/li&gt;&lt;li&gt;KinD CLI installed and Cluster running&lt;/li&gt;&lt;li&gt;WSL2 installed &lt;/li&gt;&lt;li&gt;GoLang installed in WSL2&lt;/li&gt;&lt;li&gt;Operator-SDK cli installed in WSL2&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To demonstrate the use of Operator SDK in design and create CRD, update reconcile logic and deployment workflow - created a SpringBoot application that exposes an end point in 8080 port. This end point will render the response by reading the value from configuration file or environment variable.&lt;/p&gt;&lt;h3 id=&quot;heading-resources-required-to-deploy-spring-application&quot;&gt;Resources required to deploy Spring application?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;ConfigMap&lt;ul&gt;&lt;li&gt;The application.yaml content is deployed as ConfigMap resource. The deployment manifest should mount the ConfigMap as volume, so Spring application can access it. The mounted configMap is passed as external configuration, using &lt;code&gt;--spring.config.location&lt;/code&gt; option when starting the Spring application. For more details refer the Kubernetes documentation.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Deployment &lt;ul&gt;&lt;li&gt;The deployment will deploy the Spring application in the container.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Service&lt;ul&gt;&lt;li&gt;The service created will forward traffic to 8080 port.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-operator-pattern-key-components&quot;&gt;Operator pattern key components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Custom Resource Definition (CRD), Custom Resource (CR) and Controller/Operator are the key components&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-crd-andamp-cr&quot;&gt;CRD &amp;amp; CR&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Custom Resource Definition (CRD) and Custom Resource (CR) plays a crucial part and should be designed based on requirements.&lt;/li&gt;&lt;li&gt;The Kubernetes API can be extended with Custom Resource Definition (CRD), this defines the schema for the Custom Resource (CR).&lt;/li&gt;&lt;li&gt;Once the CRD is defined we can create an instance of the Custom Resource.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-controller&quot;&gt;Controller&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The controller in Operator SDK is responsible for watching for events and reconciling the Custom Resource (CR) to desire state based on logic defined in  reconciliation flow. Without controller just deploying the CRD to cluster doesn&apos;t do anything.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-use-of-operator-sdk&quot;&gt;Use of Operator SDK&lt;/h3&gt;&lt;p&gt;With Operator SDK we can design and define the Customer Resource Definition (CRD) with corresponding reconciler logic. Part of the reconcile logic we can deploy different Kubernetes resources.&lt;/p&gt;&lt;h4 id=&quot;heading-design-consideration-of-crd-and-cr&quot;&gt;Design consideration of CRD and CR&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;spec&lt;/code&gt; section in the Custom Resource (CR) will be the design starting point at least for beginners, the properties that are required to deploy the application goes under this section. In the Operator SDK project structure this file will be generated under &lt;code&gt;config/samples/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In Custom Resource (CR) code below the &lt;code&gt;spec&lt;/code&gt; section includes &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;deployment&lt;/code&gt; properties. The name will be arbitrary name can be read and applied in the reconciler logic accordingly.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;deployment&lt;/code&gt; section further includes &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;pod&lt;/code&gt;, &lt;code&gt;config&lt;/code&gt; and &lt;code&gt;service&lt;/code&gt; section.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;pod&lt;/code&gt; section includes the properties related to Pod manifest,  like image, container port, etc. This will be read in the reconciler logic in Operator SDK project and a deployment object will be created to be deployed in cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;config&lt;/code&gt; section will include the data to create the ConfigMap resource.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;service&lt;/code&gt; section include &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;spec&lt;/code&gt;. The &lt;code&gt;spec&lt;/code&gt; section in the &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; uses the k8s.io/core library object, so we can use the regular Service manifest properties like &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;targetPort&lt;/code&gt;, etc.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;By reading further we will see how to deployed the CR to cluster.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet.greetapp.com/v1alpha1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Greet&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/instance:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/part-of:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/managed-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/created-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;deployment:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pod:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;thirumurthi/app:v1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Always&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;mountName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/opt/app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;podPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;]      &lt;span class=&quot;hljs-attr&quot;&gt;args:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;app.jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;--spring.config.location=file:/opt/app/application.yaml&quot;&lt;/span&gt;]    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;fileName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application.yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|        env.name: k8s-kind-dev-env        greeting.source: from-k8s-configMap&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;svc-port&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-operator-sdk-typego-file-which-holds-the-actual-details&quot;&gt;Operator SDK type.go file which holds the actual details&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;With reference to the CR above, we can compare it with the Operator SDK generated &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; file content where we can easily follow the pattern.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Note:-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; file includes different Go struct data types defined which will in a way used in the Custom Resource YAML.&lt;/li&gt;&lt;li&gt;&lt;code&gt;pod&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt; a custom Go struct datatype is defined.&lt;/li&gt;&lt;li&gt;In &lt;code&gt;service&lt;/code&gt;, the &lt;code&gt;spec&lt;/code&gt; uses the k8s.io/core api &lt;em&gt;corev1.ServiceSpec&lt;/em&gt; with which we can specify regular Service manifest properties.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; v1alpha1&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    corev1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/core/v1&quot;&lt;/span&gt;    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// GreetSpec defines the desired state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetSpec &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;//Name of the resource&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MaxLength=25&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MinLength=1&lt;/span&gt;    Name       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;     &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Deployment Deployment &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;deployment&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Deployment &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name      &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Pod       PodInfo &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;pod&quot;`&lt;/span&gt;    Replicas  &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;replicas,omitempty&quot;`&lt;/span&gt;    ConfigMap Config  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;config,omitempty&quot;`&lt;/span&gt;    Service   Service &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;service,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Config &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name     &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    FileName &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;fileName,omitempty&quot;`&lt;/span&gt;    Data     &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;data,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; PodInfo &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Image           &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;image&quot;`&lt;/span&gt;    ImagePullPolicy &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;imagePullPolicy,omitempty&quot;`&lt;/span&gt;    MountName       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;mountName,omitempty&quot;`&lt;/span&gt;    MountPath       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;mountPath,omitempty&quot;`&lt;/span&gt;    PodPort         &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;podPort,omitempty&quot;`&lt;/span&gt;    Command         []&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;command,omitempty&quot;`&lt;/span&gt;    Args            []&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;args,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Service &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    Spec corev1.ServiceSpec &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Important: Run &quot;make&quot; to regenerate code after modifying this file&lt;/span&gt;    Status &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//Don&apos;t leave any space between the marker&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.displayName=&quot;Greet App&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.resources=&quot;Deployment,v1,\&quot;A Kubernetes Deployment of greet app\&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetList contains a list of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetList &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ListMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Items           []Greet &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;items&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    SchemeBuilder.Register(&amp;amp;Greet{}, &amp;amp;GreetList{})}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-image-creation-of-spring-application&quot;&gt;Image creation of Spring application&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;First, build the jar artifact for the SpringBoot application, using &lt;code&gt;maven clean install&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;With the Dockerfile defined we can use Docker CLI to build image using &lt;code&gt;docker build&lt;/code&gt; and &lt;code&gt;docker push&lt;/code&gt; to push the image to Dockerhub.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-approaches-to-deploy-the-spring-application&quot;&gt;Approaches to deploy the Spring application&lt;/h3&gt;&lt;h4 id=&quot;heading-using-individual-resource-manifests-no-operator-sdk&quot;&gt;Using individual resource manifests (no Operator SDK)&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;The conventional way of deploying the app is to create different resource manifest YAML either in single file or different file. In this case we have to create three manifests for ConfigMap, Service and Deployment resources.&lt;/li&gt;&lt;/ol&gt;&lt;h4 id=&quot;heading-using-operator-sdk&quot;&gt;Using Operator SDK&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;With the Operator SDK project we need to define the CRD in here we have used GoLang and build the reconciler logic.&lt;/li&gt;&lt;li&gt;Using the utilities provided in Operator SDK, we generate the CRD files and Controller image. &lt;/li&gt;&lt;li&gt;Once we developed the controller logic, in order to deploy the Spring application we need to deploy the controller image as deployment, then the CRD manifest and the Custom Resource (CR) to the cluster. This CR includes the image of the Spring application.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Note:- &lt;/p&gt;&lt;ul&gt;&lt;li&gt;During development the &lt;code&gt;api/v1alpha1/*types.go&lt;/code&gt; file will be updated with custom Go struct datatypes, whenever we update this file we need to execute &lt;code&gt;make generate manifests&lt;/code&gt; command in WSL2 terminal to generate the CRDs YAML file.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-spring-application-code&quot;&gt;Spring application code&lt;/h3&gt;&lt;h4 id=&quot;heading-springboot-application-entry-point&quot;&gt;SpringBoot application entry point&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestParam;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Bean&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;GreetConfiguration &lt;span class=&quot;hljs-title&quot;&gt;getGreetConfig&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; GreetConfiguration();    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(AppApplication.class, args);    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${env.name:no-env-provided}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String envName;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; record &lt;span class=&quot;hljs-title&quot;&gt;Greeting&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String content,String source)&lt;/span&gt; &lt;/span&gt;{ }    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/hello&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Greeting &lt;span class=&quot;hljs-title&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam(value = &quot;name&quot;, defaultValue = &quot;anonymous&quot;)&lt;/span&gt; String name)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Greeting(String.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello %s!&quot;&lt;/span&gt;, name),                            String.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;%s-%s&quot;&lt;/span&gt;,getGreetConfig().getSource().toUpperCase(),envName));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-spring-configuration-class&quot;&gt;Spring Configuration class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Configuration class to read the application.yaml when application context is loaded&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.context.properties.ConfigurationProperties;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Configuration;&lt;span class=&quot;hljs-meta&quot;&gt;@Configuration&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@ConfigurationProperties(prefix=&quot;greeting&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;GreetConfiguration&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String source = &lt;span class=&quot;hljs-string&quot;&gt;&quot;from-spring-code&quot;&lt;/span&gt;;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-dependencies&quot;&gt;Dependencies&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.1.2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Simple app with &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;spring-cloud.version&lt;/span&gt;&amp;gt;&lt;/span&gt;2022.0.3&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;spring-cloud.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;       &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;           &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.0.0-M4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note:- &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Leave the &lt;code&gt;application.properties&lt;/code&gt; file empty when building the jar.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-dockerfile&quot;&gt;Dockerfile&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; eclipse-temurin:&lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;-jdk-alpine&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; JAR_FILE&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${JAR_FILE}&lt;/span&gt; app.jar&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;/app.jar&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-image-creation-of-spring-application-1&quot;&gt;Image creation of Spring application&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create the jar file using&lt;code&gt;mvn clean install&lt;/code&gt;. The jar file will be created in &lt;code&gt;target\&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once the Jar file is generated, use below command to build the docker image.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker build --build-arg JAR_FILE=target&lt;span class=&quot;hljs-comment&quot;&gt;/*.jar -t local/app .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We can run the Spring application image in Docker Desktop wiht below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker run --name app -e ENV_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;docker-env&quot;&lt;/span&gt; -p &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt; -d local/app:latest&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note:-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;env.name&lt;/code&gt; value is passed as docker environment variable &lt;code&gt;ENV_NAME&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;After the container is ready, the endpoint &lt;code&gt;http://localhost:8080/api/hello?name=test&lt;/code&gt; should return response&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-output-running-application-in-docker&quot;&gt;Output - Running application in Docker&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;$ curl -i http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/hello?name=test&lt;/span&gt;HTTP/&lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt;                                                    Content-Type: application/json                                  Transfer-Encoding: chunked                                      &lt;span class=&quot;hljs-attr&quot;&gt;Date&lt;/span&gt;: Tue, &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt; Aug &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt; GMT                             {&lt;span class=&quot;hljs-string&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello test!&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;source&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-SPRING-CODE-docker-env&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Passing GREETING_SOURCE environment variable in Docker run command the output looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker run --name app -e ENV_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;docker-env&quot;&lt;/span&gt; -e GREETING_SOURCE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;from-docker-cli&quot;&lt;/span&gt; -p &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt; -d local/app:latest&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Output&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl -i http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/hello?name=test                                &lt;/span&gt;HTTP/&lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; Content-Type: application/jsonTransfer-Encoding: chunked&lt;span class=&quot;hljs-attr&quot;&gt;Date&lt;/span&gt;: Tue, &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt; Aug &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;40&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;40&lt;/span&gt; GMT{&lt;span class=&quot;hljs-string&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello test!&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;source&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-DOCKER-CLI-docker-env&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-push-spring-app-image-to-dockerhub&quot;&gt;Push Spring app image to Dockerhub&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The images can pushed to the Dockerhub with below command. Use appropriate repository name.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker build --build-arg JAR_FILE=target&lt;span class=&quot;hljs-comment&quot;&gt;/*.jar -t &amp;lt;repoistory-name&amp;gt;/app:v1 .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-spring-app-with-manifest-without-operator-sdk&quot;&gt;Deploy Spring  app with manifest without Operator SDK&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once the image is pushed to Dockerhub or private registry, we can deploy the Spring application and the Deployment manifest looks like below. Assuming the ConfigMap is created as &lt;code&gt;app-cfg&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-deploy&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;repository-name&amp;gt;/app:v1&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Always&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-pod&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-port&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/opt/app&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount-vol&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-cfg&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount-vol&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-spring-application-with-operator-sdk&quot;&gt;Deploy Spring application with Operator SDK&lt;/h3&gt;&lt;h4 id=&quot;heading-crds&quot;&gt;CRDs&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The  fragment of code from &lt;code&gt;api/v1alpha1/*types.go&lt;/code&gt; file where we define custom Go struct data types, which will generate the CRDs accordingly.&lt;/li&gt;&lt;li&gt;The Service struct uses the k8s.io/api/core  &lt;code&gt;corev1.ServiceSpec&lt;/code&gt; so we can use &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;targetPort&lt;/code&gt; properties like in regular Service manifest file. This is an example to demonstrate that it is always not necessary to define all the properties we can reuse the k8s.io core library object as well.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Deployment &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name      &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Pod       PodInfo &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;pod&quot;`&lt;/span&gt;    Replicas  &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;replicas,omitempty&quot;`&lt;/span&gt;    ConfigMap Config  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;config,omitempty&quot;`&lt;/span&gt;    Service   Service &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;service,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Service &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    Spec corev1.ServiceSpec &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-reconciler-logic&quot;&gt;Reconciler logic&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;Reconcile()&lt;/code&gt; method calls three different function which creates the Service, ConfigMap and Deployment resource.&lt;ul&gt;&lt;li&gt;Function &lt;code&gt;checkAndCreateConfigMapResource()&lt;/code&gt;, &lt;code&gt;checkAndCreateServiceResource&lt;/code&gt;, and &lt;code&gt;checkAndCreateDeploymentResource()&lt;/code&gt; follows the same logic to create or update only difference is which object is being initialized in each method.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;When the CR is applied, the create event will be triggered and the resources will be deployed. If the CR is deployed with any updates, the update event will update the resources. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; controllers&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;context&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;time&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;gopkg.in/yaml.v2&quot;&lt;/span&gt;    appsv1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/apps/v1&quot;&lt;/span&gt;    corev1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/core/v1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/api/errors&quot;&lt;/span&gt;    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/runtime&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/types&quot;&lt;/span&gt;    ctrl &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime/pkg/client&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime/pkg/log&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/client-go/tools/record&quot;&lt;/span&gt;    greetv1alpha1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;github.com/thirumurthis/app-operator/api/v1alpha1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// GreetReconciler reconciles a Greet object&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// added Recorder to the struct&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetReconciler &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    client.Client    Scheme   *runtime.Scheme    Recorder record.EventRecorder}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets,verbs=get;list;watch;create;update;patch;delete&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets/status,verbs=get;update;patch&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets/finalizers,verbs=update&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=deployments,verbs=get;list;watch;create;update;patch;delete&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=pods,verbs=get;list;create;update;patch&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)    instance := &amp;amp;greetv1alpha1.Greet{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, req.NamespacedName, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, client.IgnoreNotFound(err)    }    appName := instance.Spec.Name    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;, instance.Spec.Name))        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;, appName))    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)    }    checkAndCreateConfigMapResource(r, instance, ctx)    checkAndCreateServiceResource(r, instance, ctx)    checkAndCreateDeploymentResource(r, instance, ctx)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Status.Status == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {        instance.Status.Status = &lt;span class=&quot;hljs-string&quot;&gt;&quot;OK&quot;&lt;/span&gt;        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - is set to OK&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Status().Update(ctx, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, client.IgnoreNotFound(err)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// SetupWithManager sets up the controller with the Manager.&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SetupWithManager&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(mgr ctrl.Manager)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;error&lt;/span&gt;&lt;/span&gt; {    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.NewControllerManagedBy(mgr).        For(&amp;amp;greetv1alpha1.Greet{}).        Owns(&amp;amp;appsv1.Deployment{}).        Complete(r)}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateConfigMapResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    fileName := instance.Spec.Deployment.ConfigMap.FileName    data := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    content := instance.Spec.Deployment.ConfigMap.Data    data[fileName] = content    identifiedConfigMap := &amp;amp;corev1.ConfigMap{}    configMapName := instance.Spec.Deployment.ConfigMap.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-cfg&quot;&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;data in config %v&quot;&lt;/span&gt;, data))    configMap := &amp;amp;corev1.ConfigMap{        ObjectMeta: metav1.ObjectMeta{            Name:      configMapName,            Namespace: instance.Namespace,        },        Data: data,    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx,        types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedConfigMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating ConfigMap&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;ConfigMap&quot;&lt;/span&gt;, configMapName)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, configMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating ConfigMap %v&quot;&lt;/span&gt;, configMap))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, configMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateServiceResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    labels := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    labels[&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;] = instance.Spec.Name    serviceSpec := instance.Spec.Deployment.Service.Spec    identifiedService := &amp;amp;corev1.Service{}    name := instance.Spec.Deployment.Service.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-svc&quot;&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;data in service %v&quot;&lt;/span&gt;, serviceSpec))    service := &amp;amp;corev1.Service{        ObjectMeta: metav1.ObjectMeta{            Name:      name,            Namespace: instance.Namespace,            Labels:    labels,        },        Spec: serviceSpec,    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedService); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating Service&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Service&quot;&lt;/span&gt;, serviceSpec)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, service); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating service %v&quot;&lt;/span&gt;, service))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, service); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateDeploymentResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    labels := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    labels[&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;] = instance.Spec.Name    deploymentName := instance.Spec.Deployment.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-deploy&quot;&lt;/span&gt;    replicas := instance.Spec.Deployment.Replicas    imageUrl := instance.Spec.Deployment.Pod.Image    imagePullPolicy := instance.Spec.Deployment.Pod.ImagePullPolicy    mountName := instance.Spec.Deployment.Pod.MountName    mountPath := instance.Spec.Deployment.Pod.MountPath    port := instance.Spec.Deployment.Pod.PodPort    configMapName := instance.Spec.Deployment.ConfigMap.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-cfg&quot;&lt;/span&gt;    identifiedDeployment := &amp;amp;appsv1.Deployment{}    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Deployment - %s %s %s %d&quot;&lt;/span&gt;, deploymentName, imageUrl, imagePullPolicy, replicas))    volumeName := mountName + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-vol&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; containers []corev1.Container    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; policyNameType corev1.PullPolicy    container := corev1.Container{}    container.Image = imageUrl    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; containerPorts []corev1.ContainerPort    cPort := corev1.ContainerPort{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; port == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {        port = &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    }    cPort.ContainerPort = port    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; portName &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;    portName = instance.Spec.Deployment.Name    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(instance.Spec.Deployment.Name) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; {        portName = instance.Spec.Deployment.Name[:&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]    }    cPort.Name = portName + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-port&quot;&lt;/span&gt;    containerPorts = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(containerPorts, cPort)    container.Ports = containerPorts    container.Name = instance.Spec.Deployment.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-pod&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//pod command&lt;/span&gt;    container.Command = instance.Spec.Deployment.Pod.Command    container.Args = instance.Spec.Deployment.Pod.Args    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(imagePullPolicy) == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {        policyNameType = corev1.PullAlways    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Always&quot;&lt;/span&gt; {        policyNameType = corev1.PullAlways    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;IfNotPresent&quot;&lt;/span&gt; {        policyNameType = corev1.PullIfNotPresent    }    container.ImagePullPolicy = policyNameType    container.VolumeMounts = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(container.VolumeMounts, corev1.VolumeMount{        Name:      volumeName,        MountPath: mountPath,    })    containers = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(containers, container)    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Container - %#v&quot;&lt;/span&gt;, containers))    volume := corev1.Volume{        Name: volumeName,        VolumeSource: corev1.VolumeSource{            ConfigMap: &amp;amp;corev1.ConfigMapVolumeSource{                LocalObjectReference: corev1.LocalObjectReference{                    Name: configMapName,                },            },        },    }    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; volumes []corev1.Volume    volumes = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(volumes, volume)    deployer := &amp;amp;appsv1.Deployment{        ObjectMeta: metav1.ObjectMeta{            Name:      deploymentName,            Namespace: instance.Namespace,            Labels:    labels,        },        Spec: appsv1.DeploymentSpec{            Replicas: &amp;amp;replicas,            Selector: &amp;amp;metav1.LabelSelector{                MatchLabels: labels,            },            Template: corev1.PodTemplateSpec{                ObjectMeta: metav1.ObjectMeta{                    Labels: labels,                },                Spec: corev1.PodSpec{                    Containers: containers,                    Volumes:    volumes,                },            },        },    }    &lt;span class=&quot;hljs-comment&quot;&gt;// Used to deserialize&lt;/span&gt;    deployUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deployer)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Error occurred in unstructuring&quot;&lt;/span&gt;)    }    encoder, err := yaml.Marshal(deployUnstructured)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Error occurred in transforming&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-comment&quot;&gt;//prints the yaml format of the deployment object created&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;%#v&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(encoder)))    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;yaml: \n%#v\n&quot;&lt;/span&gt;, deployer))    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx,        types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedDeployment); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating Deployment&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deploy&quot;&lt;/span&gt;, deployer)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, deployer); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-comment&quot;&gt;//instance as the owner and controller&lt;/span&gt;        ctrl.SetControllerReference(instance, deployer, r.Scheme)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating deployment %v&quot;&lt;/span&gt;, deployer))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, deployer); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-comment&quot;&gt;//instance as the owner and controller&lt;/span&gt;        ctrl.SetControllerReference(instance, deployer, r.Scheme)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The Custom Resource file content is show above.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The CRD file can be found from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/crd/bases/greet.greetapp.com_greets.yaml&quot;&gt;Github&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-deployment-tips&quot;&gt;Deployment tips&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;During local development to run the operator in KinD we can use &lt;code&gt;make generate manifests install run&lt;/code&gt; command. &lt;/li&gt;&lt;li&gt;Upon deploying the Custom Resource the logs will be displayed like in below snapshot. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/d296ea1a-e8e8-48ff-9684-5bfc721f2e2f&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy the Custom Resource manifests use save the content to a file and use the &lt;code&gt;kubectl apply -f &amp;lt;file-name-with-content&amp;gt;.yaml&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In below the deployment has pod, config, service sections. The reconcile code will use these values to deploy them in Kuberented cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note the config in the Custom Resource (CR) file&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;fileName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application.yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|        env.name: k8s-kind-dev-env        greeting.source: from-k8s-configMap&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once application is deployed, with nginx container we can hit the endpoint and validate the response, which will look like in below snapshot&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/c0658ac8-04b2-46b2-be79-d334b35cb03a&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-creating-controller-image&quot;&gt;Creating controller image&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;From WSL2 we can use below command to create the controller image and push it to Dockerhub.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt; make docker-build docker-push IMG=thirumurthi/app-op:v1&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploying-spring-app-using-controller-image-crd-and-cr&quot;&gt;Deploying Spring app using Controller Image, CRD and CR&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy Spring app in test or production like environment we need to follow below steps&lt;/p&gt;&lt;h4 id=&quot;heading-deploy-the-controller-in-deployment-manifest&quot;&gt;Deploy the Controller in Deployment manifest&lt;/h4&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the deployment manifest to deploy the controller.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;operator-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;thirumurthi/app-op:v1&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-crd&quot;&gt;Deploy the CRD&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/crd/bases/greet.greetapp.com_greets.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-cr&quot;&gt;Deploy the CR&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/samples/greet_v1alpha1_greet.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Note:- &lt;ul&gt;&lt;li&gt;When I tried to deploy the controller as deployment, there was an due to permission and it requires a ServiceAccount to be created. The ServiceAccount can be created in Operator SDK but for simplicity executed the following command manually.&lt;/li&gt;&lt;li&gt;The exception message that you would notice in case if ServiceAccount is not created.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;E0816 &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;51&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14.671318&lt;/span&gt;       &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; reflector.go:&lt;span class=&quot;hljs-number&quot;&gt;148&lt;/span&gt;] pkg/mod/k8s.io/client-go@v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;/tools/cache/reflector.go:&lt;span class=&quot;hljs-number&quot;&gt;231&lt;/span&gt;: Failed to watch *v1alpha1.Greet: failed to list *v1alpha1.Greet: greets.greet.greetapp.com is forbidden: User &lt;span class=&quot;hljs-string&quot;&gt;&quot;system:serviceaccount:default:default&quot;&lt;/span&gt; cannot list resource &lt;span class=&quot;hljs-string&quot;&gt;&quot;greets&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; API group &lt;span class=&quot;hljs-string&quot;&gt;&quot;greet.greetapp.com&quot;&lt;/span&gt; at the cluster scope&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt; To manually create the ServiceAccount we can use below command&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code&gt;kubectl create clusterrole deployr --verb=get,list,watch,create,&lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;,patch,update --resource=deployments.appskubectl create clusterrolebinding deployr-srvacct-&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;-binding --clusterrole=deployr --serviceaccount=&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;:&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output-after-deploying-the-controller-crd-and-cr&quot;&gt;Output after deploying the Controller, CRD and CR&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once Controller, CRD and CR are deployed the list of resources and the output accessing the deployed spring application looks like below snapshot.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/fbe560a4-0cf7-4691-9bff-eecae614298b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-operator-pattern-to-deploy-springboot-application&quot;&gt;Operator pattern to deploy SpringBoot application&lt;/h2&gt;&lt;p&gt;In this article we will be using Operator SDK to create Custom Resource Definition (CRD) and Controller logic to deploy a Spring application in Kubernetes cluster.&lt;/p&gt;&lt;p&gt;With reference to my previous &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/extend-kubernetes-api-with-operator-sdk&quot;&gt;operator-sdk blog&lt;/a&gt;, we will use the same scaffolded and initialized project structure to create the CRD and reconcile logic. The reconciler logic will programmatically create Kubernetes resources object (using k8s.io/core libraries) like Deployment, ConfigMap, Service and deploy them to the cluster.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes&lt;/li&gt;&lt;li&gt;KinD CLI installed and Cluster running&lt;/li&gt;&lt;li&gt;WSL2 installed &lt;/li&gt;&lt;li&gt;GoLang installed in WSL2&lt;/li&gt;&lt;li&gt;Operator-SDK cli installed in WSL2&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;To demonstrate the use of Operator SDK in design and create CRD, update reconcile logic and deployment workflow - created a SpringBoot application that exposes an end point in 8080 port. This end point will render the response by reading the value from configuration file or environment variable.&lt;/p&gt;&lt;h3 id=&quot;heading-resources-required-to-deploy-spring-application&quot;&gt;Resources required to deploy Spring application?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;ConfigMap&lt;ul&gt;&lt;li&gt;The application.yaml content is deployed as ConfigMap resource. The deployment manifest should mount the ConfigMap as volume, so Spring application can access it. The mounted configMap is passed as external configuration, using &lt;code&gt;--spring.config.location&lt;/code&gt; option when starting the Spring application. For more details refer the Kubernetes documentation.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Deployment &lt;ul&gt;&lt;li&gt;The deployment will deploy the Spring application in the container.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Service&lt;ul&gt;&lt;li&gt;The service created will forward traffic to 8080 port.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-operator-pattern-key-components&quot;&gt;Operator pattern key components&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Custom Resource Definition (CRD), Custom Resource (CR) and Controller/Operator are the key components&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-crd-andamp-cr&quot;&gt;CRD &amp;amp; CR&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Custom Resource Definition (CRD) and Custom Resource (CR) plays a crucial part and should be designed based on requirements.&lt;/li&gt;&lt;li&gt;The Kubernetes API can be extended with Custom Resource Definition (CRD), this defines the schema for the Custom Resource (CR).&lt;/li&gt;&lt;li&gt;Once the CRD is defined we can create an instance of the Custom Resource.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-controller&quot;&gt;Controller&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The controller in Operator SDK is responsible for watching for events and reconciling the Custom Resource (CR) to desire state based on logic defined in  reconciliation flow. Without controller just deploying the CRD to cluster doesn&apos;t do anything.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-use-of-operator-sdk&quot;&gt;Use of Operator SDK&lt;/h3&gt;&lt;p&gt;With Operator SDK we can design and define the Customer Resource Definition (CRD) with corresponding reconciler logic. Part of the reconcile logic we can deploy different Kubernetes resources.&lt;/p&gt;&lt;h4 id=&quot;heading-design-consideration-of-crd-and-cr&quot;&gt;Design consideration of CRD and CR&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;spec&lt;/code&gt; section in the Custom Resource (CR) will be the design starting point at least for beginners, the properties that are required to deploy the application goes under this section. In the Operator SDK project structure this file will be generated under &lt;code&gt;config/samples/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In Custom Resource (CR) code below the &lt;code&gt;spec&lt;/code&gt; section includes &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;deployment&lt;/code&gt; properties. The name will be arbitrary name can be read and applied in the reconciler logic accordingly.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;deployment&lt;/code&gt; section further includes &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;pod&lt;/code&gt;, &lt;code&gt;config&lt;/code&gt; and &lt;code&gt;service&lt;/code&gt; section.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;pod&lt;/code&gt; section includes the properties related to Pod manifest,  like image, container port, etc. This will be read in the reconciler logic in Operator SDK project and a deployment object will be created to be deployed in cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;config&lt;/code&gt; section will include the data to create the ConfigMap resource.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;service&lt;/code&gt; section include &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;spec&lt;/code&gt;. The &lt;code&gt;spec&lt;/code&gt; section in the &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; uses the k8s.io/core library object, so we can use the regular Service manifest properties like &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;targetPort&lt;/code&gt;, etc.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;By reading further we will see how to deployed the CR to cluster.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet.greetapp.com/v1alpha1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Greet&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/instance:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/part-of:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/managed-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/created-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;deployment:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;pod:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;thirumurthi/app:v1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Always&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;mountName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/opt/app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;podPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;]      &lt;span class=&quot;hljs-attr&quot;&gt;args:&lt;/span&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;app.jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;--spring.config.location=file:/opt/app/application.yaml&quot;&lt;/span&gt;]    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;fileName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application.yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|        env.name: k8s-kind-dev-env        greeting.source: from-k8s-configMap&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;service:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;svc-port&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-operator-sdk-typego-file-which-holds-the-actual-details&quot;&gt;Operator SDK type.go file which holds the actual details&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;With reference to the CR above, we can compare it with the Operator SDK generated &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; file content where we can easily follow the pattern.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Note:-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;api/v1alpha1/*type.go&lt;/code&gt; file includes different Go struct data types defined which will in a way used in the Custom Resource YAML.&lt;/li&gt;&lt;li&gt;&lt;code&gt;pod&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt; a custom Go struct datatype is defined.&lt;/li&gt;&lt;li&gt;In &lt;code&gt;service&lt;/code&gt;, the &lt;code&gt;spec&lt;/code&gt; uses the k8s.io/core api &lt;em&gt;corev1.ServiceSpec&lt;/em&gt; with which we can specify regular Service manifest properties.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; v1alpha1&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    corev1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/core/v1&quot;&lt;/span&gt;    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// GreetSpec defines the desired state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetSpec &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;//Name of the resource&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MaxLength=25&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MinLength=1&lt;/span&gt;    Name       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;     &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Deployment Deployment &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;deployment&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Deployment &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name      &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Pod       PodInfo &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;pod&quot;`&lt;/span&gt;    Replicas  &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;replicas,omitempty&quot;`&lt;/span&gt;    ConfigMap Config  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;config,omitempty&quot;`&lt;/span&gt;    Service   Service &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;service,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Config &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name     &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    FileName &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;fileName,omitempty&quot;`&lt;/span&gt;    Data     &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;data,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; PodInfo &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Image           &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;image&quot;`&lt;/span&gt;    ImagePullPolicy &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;imagePullPolicy,omitempty&quot;`&lt;/span&gt;    MountName       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;mountName,omitempty&quot;`&lt;/span&gt;    MountPath       &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;mountPath,omitempty&quot;`&lt;/span&gt;    PodPort         &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;podPort,omitempty&quot;`&lt;/span&gt;    Command         []&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;command,omitempty&quot;`&lt;/span&gt;    Args            []&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;args,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Service &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    Spec corev1.ServiceSpec &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Important: Run &quot;make&quot; to regenerate code after modifying this file&lt;/span&gt;    Status &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//Don&apos;t leave any space between the marker&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.displayName=&quot;Greet App&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.resources=&quot;Deployment,v1,\&quot;A Kubernetes Deployment of greet app\&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetList contains a list of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetList &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ListMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Items           []Greet &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;items&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    SchemeBuilder.Register(&amp;amp;Greet{}, &amp;amp;GreetList{})}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-image-creation-of-spring-application&quot;&gt;Image creation of Spring application&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;First, build the jar artifact for the SpringBoot application, using &lt;code&gt;maven clean install&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;With the Dockerfile defined we can use Docker CLI to build image using &lt;code&gt;docker build&lt;/code&gt; and &lt;code&gt;docker push&lt;/code&gt; to push the image to Dockerhub.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-approaches-to-deploy-the-spring-application&quot;&gt;Approaches to deploy the Spring application&lt;/h3&gt;&lt;h4 id=&quot;heading-using-individual-resource-manifests-no-operator-sdk&quot;&gt;Using individual resource manifests (no Operator SDK)&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;The conventional way of deploying the app is to create different resource manifest YAML either in single file or different file. In this case we have to create three manifests for ConfigMap, Service and Deployment resources.&lt;/li&gt;&lt;/ol&gt;&lt;h4 id=&quot;heading-using-operator-sdk&quot;&gt;Using Operator SDK&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;With the Operator SDK project we need to define the CRD in here we have used GoLang and build the reconciler logic.&lt;/li&gt;&lt;li&gt;Using the utilities provided in Operator SDK, we generate the CRD files and Controller image. &lt;/li&gt;&lt;li&gt;Once we developed the controller logic, in order to deploy the Spring application we need to deploy the controller image as deployment, then the CRD manifest and the Custom Resource (CR) to the cluster. This CR includes the image of the Spring application.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Note:- &lt;/p&gt;&lt;ul&gt;&lt;li&gt;During development the &lt;code&gt;api/v1alpha1/*types.go&lt;/code&gt; file will be updated with custom Go struct datatypes, whenever we update this file we need to execute &lt;code&gt;make generate manifests&lt;/code&gt; command in WSL2 terminal to generate the CRDs YAML file.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-spring-application-code&quot;&gt;Spring application code&lt;/h3&gt;&lt;h4 id=&quot;heading-springboot-application-entry-point&quot;&gt;SpringBoot application entry point&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestParam;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Bean&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;GreetConfiguration &lt;span class=&quot;hljs-title&quot;&gt;getGreetConfig&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; GreetConfiguration();    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(AppApplication.class, args);    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${env.name:no-env-provided}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String envName;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; record &lt;span class=&quot;hljs-title&quot;&gt;Greeting&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String content,String source)&lt;/span&gt; &lt;/span&gt;{ }    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/hello&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Greeting &lt;span class=&quot;hljs-title&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestParam(value = &quot;name&quot;, defaultValue = &quot;anonymous&quot;)&lt;/span&gt; String name)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Greeting(String.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello %s!&quot;&lt;/span&gt;, name),                            String.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;%s-%s&quot;&lt;/span&gt;,getGreetConfig().getSource().toUpperCase(),envName));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-spring-configuration-class&quot;&gt;Spring Configuration class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Configuration class to read the application.yaml when application context is loaded&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.context.properties.ConfigurationProperties;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Configuration;&lt;span class=&quot;hljs-meta&quot;&gt;@Configuration&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@ConfigurationProperties(prefix=&quot;greeting&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;GreetConfiguration&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String source = &lt;span class=&quot;hljs-string&quot;&gt;&quot;from-spring-code&quot;&lt;/span&gt;;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-dependencies&quot;&gt;Dependencies&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.1.2&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- lookup parent from repository --&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Simple app with &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;spring-cloud.version&lt;/span&gt;&amp;gt;&lt;/span&gt;2022.0.3&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;spring-cloud.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;       &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;           &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;maven-surefire-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.0.0-M4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note:- &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Leave the &lt;code&gt;application.properties&lt;/code&gt; file empty when building the jar.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-dockerfile&quot;&gt;Dockerfile&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-Dockerfile&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; eclipse-temurin:&lt;span class=&quot;hljs-number&quot;&gt;17&lt;/span&gt;-jdk-alpine&lt;span class=&quot;hljs-keyword&quot;&gt;ARG&lt;/span&gt; JAR_FILE&lt;span class=&quot;hljs-keyword&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; &lt;span class=&quot;hljs-variable&quot;&gt;${JAR_FILE}&lt;/span&gt; app.jar&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;bash&quot;&gt; [&lt;span class=&quot;hljs-string&quot;&gt;&quot;java&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;-jar&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;/app.jar&quot;&lt;/span&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-image-creation-of-spring-application-1&quot;&gt;Image creation of Spring application&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create the jar file using&lt;code&gt;mvn clean install&lt;/code&gt;. The jar file will be created in &lt;code&gt;target\&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once the Jar file is generated, use below command to build the docker image.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker build --build-arg JAR_FILE=target&lt;span class=&quot;hljs-comment&quot;&gt;/*.jar -t local/app .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We can run the Spring application image in Docker Desktop wiht below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker run --name app -e ENV_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;docker-env&quot;&lt;/span&gt; -p &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt; -d local/app:latest&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note:-&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;env.name&lt;/code&gt; value is passed as docker environment variable &lt;code&gt;ENV_NAME&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;After the container is ready, the endpoint &lt;code&gt;http://localhost:8080/api/hello?name=test&lt;/code&gt; should return response&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-output-running-application-in-docker&quot;&gt;Output - Running application in Docker&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;$ curl -i http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/hello?name=test&lt;/span&gt;HTTP/&lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt;                                                    Content-Type: application/json                                  Transfer-Encoding: chunked                                      &lt;span class=&quot;hljs-attr&quot;&gt;Date&lt;/span&gt;: Tue, &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt; Aug &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14&lt;/span&gt; GMT                             {&lt;span class=&quot;hljs-string&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello test!&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;source&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-SPRING-CODE-docker-env&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Passing GREETING_SOURCE environment variable in Docker run command the output looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker run --name app -e ENV_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;docker-env&quot;&lt;/span&gt; -e GREETING_SOURCE=&lt;span class=&quot;hljs-string&quot;&gt;&quot;from-docker-cli&quot;&lt;/span&gt; -p &lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;8080&lt;/span&gt; -d local/app:latest&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Output&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl -i http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/hello?name=test                                &lt;/span&gt;HTTP/&lt;span class=&quot;hljs-number&quot;&gt;1.1&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt; Content-Type: application/jsonTransfer-Encoding: chunked&lt;span class=&quot;hljs-attr&quot;&gt;Date&lt;/span&gt;: Tue, &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt; Aug &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;40&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;40&lt;/span&gt; GMT{&lt;span class=&quot;hljs-string&quot;&gt;&quot;content&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Hello test!&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;source&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-DOCKER-CLI-docker-env&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-push-spring-app-image-to-dockerhub&quot;&gt;Push Spring app image to Dockerhub&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The images can pushed to the Dockerhub with below command. Use appropriate repository name.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;docker build --build-arg JAR_FILE=target&lt;span class=&quot;hljs-comment&quot;&gt;/*.jar -t &amp;lt;repoistory-name&amp;gt;/app:v1 .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-spring-app-with-manifest-without-operator-sdk&quot;&gt;Deploy Spring  app with manifest without Operator SDK&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once the image is pushed to Dockerhub or private registry, we can deploy the Spring application and the Deployment manifest looks like below. Assuming the ConfigMap is created as &lt;code&gt;app-cfg&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-deploy&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;repository-name&amp;gt;/app:v1&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;imagePullPolicy:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Always&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-pod&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-port&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;volumeMounts:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;mountPath:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/opt/app&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount-vol&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;configMap:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-cfg&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-mount-vol&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-spring-application-with-operator-sdk&quot;&gt;Deploy Spring application with Operator SDK&lt;/h3&gt;&lt;h4 id=&quot;heading-crds&quot;&gt;CRDs&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The  fragment of code from &lt;code&gt;api/v1alpha1/*types.go&lt;/code&gt; file where we define custom Go struct data types, which will generate the CRDs accordingly.&lt;/li&gt;&lt;li&gt;The Service struct uses the k8s.io/api/core  &lt;code&gt;corev1.ServiceSpec&lt;/code&gt; so we can use &lt;code&gt;port&lt;/code&gt;, &lt;code&gt;targetPort&lt;/code&gt; properties like in regular Service manifest file. This is an example to demonstrate that it is always not necessary to define all the properties we can reuse the k8s.io core library object as well.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Deployment &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name      &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    Pod       PodInfo &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;pod&quot;`&lt;/span&gt;    Replicas  &lt;span class=&quot;hljs-keyword&quot;&gt;int32&lt;/span&gt;   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;replicas,omitempty&quot;`&lt;/span&gt;    ConfigMap Config  &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;config,omitempty&quot;`&lt;/span&gt;    Service   Service &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;service,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Service &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name,omitempty&quot;`&lt;/span&gt;    Spec corev1.ServiceSpec &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-reconciler-logic&quot;&gt;Reconciler logic&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;Reconcile()&lt;/code&gt; method calls three different function which creates the Service, ConfigMap and Deployment resource.&lt;ul&gt;&lt;li&gt;Function &lt;code&gt;checkAndCreateConfigMapResource()&lt;/code&gt;, &lt;code&gt;checkAndCreateServiceResource&lt;/code&gt;, and &lt;code&gt;checkAndCreateDeploymentResource()&lt;/code&gt; follows the same logic to create or update only difference is which object is being initialized in each method.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;When the CR is applied, the create event will be triggered and the resources will be deployed. If the CR is deployed with any updates, the update event will update the resources. &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; controllers&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;context&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;time&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;gopkg.in/yaml.v2&quot;&lt;/span&gt;    appsv1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/apps/v1&quot;&lt;/span&gt;    corev1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/api/core/v1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/api/errors&quot;&lt;/span&gt;    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/runtime&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/types&quot;&lt;/span&gt;    ctrl &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime/pkg/client&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/controller-runtime/pkg/log&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/client-go/tools/record&quot;&lt;/span&gt;    greetv1alpha1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;github.com/thirumurthis/app-operator/api/v1alpha1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// GreetReconciler reconciles a Greet object&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// added Recorder to the struct&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetReconciler &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    client.Client    Scheme   *runtime.Scheme    Recorder record.EventRecorder}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets,verbs=get;list;watch;create;update;patch;delete&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets/status,verbs=get;update;patch&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=greets/finalizers,verbs=update&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=deployments,verbs=get;list;watch;create;update;patch;delete&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:rbac:groups=greet.greetapp.com,resources=pods,verbs=get;list;create;update;patch&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)    instance := &amp;amp;greetv1alpha1.Greet{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, req.NamespacedName, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, client.IgnoreNotFound(err)    }    appName := instance.Spec.Name    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;, instance.Spec.Name))        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;, appName))    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)    }    checkAndCreateConfigMapResource(r, instance, ctx)    checkAndCreateServiceResource(r, instance, ctx)    checkAndCreateDeploymentResource(r, instance, ctx)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Status.Status == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {        instance.Status.Status = &lt;span class=&quot;hljs-string&quot;&gt;&quot;OK&quot;&lt;/span&gt;        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - is set to OK&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Status().Update(ctx, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, client.IgnoreNotFound(err)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// SetupWithManager sets up the controller with the Manager.&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SetupWithManager&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(mgr ctrl.Manager)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;error&lt;/span&gt;&lt;/span&gt; {    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.NewControllerManagedBy(mgr).        For(&amp;amp;greetv1alpha1.Greet{}).        Owns(&amp;amp;appsv1.Deployment{}).        Complete(r)}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateConfigMapResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    fileName := instance.Spec.Deployment.ConfigMap.FileName    data := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    content := instance.Spec.Deployment.ConfigMap.Data    data[fileName] = content    identifiedConfigMap := &amp;amp;corev1.ConfigMap{}    configMapName := instance.Spec.Deployment.ConfigMap.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-cfg&quot;&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;data in config %v&quot;&lt;/span&gt;, data))    configMap := &amp;amp;corev1.ConfigMap{        ObjectMeta: metav1.ObjectMeta{            Name:      configMapName,            Namespace: instance.Namespace,        },        Data: data,    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx,        types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedConfigMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating ConfigMap&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;ConfigMap&quot;&lt;/span&gt;, configMapName)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, configMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating ConfigMap %v&quot;&lt;/span&gt;, configMap))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, configMap); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateServiceResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    labels := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    labels[&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;] = instance.Spec.Name    serviceSpec := instance.Spec.Deployment.Service.Spec    identifiedService := &amp;amp;corev1.Service{}    name := instance.Spec.Deployment.Service.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-svc&quot;&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;data in service %v&quot;&lt;/span&gt;, serviceSpec))    service := &amp;amp;corev1.Service{        ObjectMeta: metav1.ObjectMeta{            Name:      name,            Namespace: instance.Namespace,            Labels:    labels,        },        Spec: serviceSpec,    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedService); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating Service&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Service&quot;&lt;/span&gt;, serviceSpec)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, service); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating service %v&quot;&lt;/span&gt;, service))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, service); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;checkAndCreateDeploymentResource&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler, instance *greetv1alpha1.Greet,    ctx context.Context)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    labels := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;)    labels[&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;] = instance.Spec.Name    deploymentName := instance.Spec.Deployment.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-deploy&quot;&lt;/span&gt;    replicas := instance.Spec.Deployment.Replicas    imageUrl := instance.Spec.Deployment.Pod.Image    imagePullPolicy := instance.Spec.Deployment.Pod.ImagePullPolicy    mountName := instance.Spec.Deployment.Pod.MountName    mountPath := instance.Spec.Deployment.Pod.MountPath    port := instance.Spec.Deployment.Pod.PodPort    configMapName := instance.Spec.Deployment.ConfigMap.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-cfg&quot;&lt;/span&gt;    identifiedDeployment := &amp;amp;appsv1.Deployment{}    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Deployment - %s %s %s %d&quot;&lt;/span&gt;, deploymentName, imageUrl, imagePullPolicy, replicas))    volumeName := mountName + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-vol&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; containers []corev1.Container    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; policyNameType corev1.PullPolicy    container := corev1.Container{}    container.Image = imageUrl    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; containerPorts []corev1.ContainerPort    cPort := corev1.ContainerPort{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; port == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {        port = &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    }    cPort.ContainerPort = port    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; portName &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;    portName = instance.Spec.Deployment.Name    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(instance.Spec.Deployment.Name) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; {        portName = instance.Spec.Deployment.Name[:&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]    }    cPort.Name = portName + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-port&quot;&lt;/span&gt;    containerPorts = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(containerPorts, cPort)    container.Ports = containerPorts    container.Name = instance.Spec.Deployment.Name + &lt;span class=&quot;hljs-string&quot;&gt;&quot;-pod&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//pod command&lt;/span&gt;    container.Command = instance.Spec.Deployment.Pod.Command    container.Args = instance.Spec.Deployment.Pod.Args    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(imagePullPolicy) == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {        policyNameType = corev1.PullAlways    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Always&quot;&lt;/span&gt; {        policyNameType = corev1.PullAlways    }    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; imagePullPolicy == &lt;span class=&quot;hljs-string&quot;&gt;&quot;IfNotPresent&quot;&lt;/span&gt; {        policyNameType = corev1.PullIfNotPresent    }    container.ImagePullPolicy = policyNameType    container.VolumeMounts = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(container.VolumeMounts, corev1.VolumeMount{        Name:      volumeName,        MountPath: mountPath,    })    containers = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(containers, container)    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Container - %#v&quot;&lt;/span&gt;, containers))    volume := corev1.Volume{        Name: volumeName,        VolumeSource: corev1.VolumeSource{            ConfigMap: &amp;amp;corev1.ConfigMapVolumeSource{                LocalObjectReference: corev1.LocalObjectReference{                    Name: configMapName,                },            },        },    }    &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; volumes []corev1.Volume    volumes = &lt;span class=&quot;hljs-built_in&quot;&gt;append&lt;/span&gt;(volumes, volume)    deployer := &amp;amp;appsv1.Deployment{        ObjectMeta: metav1.ObjectMeta{            Name:      deploymentName,            Namespace: instance.Namespace,            Labels:    labels,        },        Spec: appsv1.DeploymentSpec{            Replicas: &amp;amp;replicas,            Selector: &amp;amp;metav1.LabelSelector{                MatchLabels: labels,            },            Template: corev1.PodTemplateSpec{                ObjectMeta: metav1.ObjectMeta{                    Labels: labels,                },                Spec: corev1.PodSpec{                    Containers: containers,                    Volumes:    volumes,                },            },        },    }    &lt;span class=&quot;hljs-comment&quot;&gt;// Used to deserialize&lt;/span&gt;    deployUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deployer)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Error occurred in unstructuring&quot;&lt;/span&gt;)    }    encoder, err := yaml.Marshal(deployUnstructured)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Log.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Error occurred in transforming&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-comment&quot;&gt;//prints the yaml format of the deployment object created&lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;%#v&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(encoder)))    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;yaml: \n%#v\n&quot;&lt;/span&gt;, deployer))    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx,        types.NamespacedName{Name: instance.Name, Namespace: instance.Namespace},        identifiedDeployment); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; &amp;amp;&amp;amp; errors.IsNotFound(err) {        log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating Deployment&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deploy&quot;&lt;/span&gt;, deployer)        &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//r.Log.Info(&quot;Creating ConfigMap&quot;, &quot;ConfigMap&quot;, configMap)&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Create(ctx, deployer); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while creating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-comment&quot;&gt;//instance as the owner and controller&lt;/span&gt;        ctrl.SetControllerReference(instance, deployer, r.Scheme)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{Requeue: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {        log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Updating deployment %v&quot;&lt;/span&gt;, deployer))        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Update(ctx, deployer); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            &lt;span class=&quot;hljs-comment&quot;&gt;// Error occurred while updating the ConfigMap&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, err        }        &lt;span class=&quot;hljs-comment&quot;&gt;//instance as the owner and controller&lt;/span&gt;        ctrl.SetControllerReference(instance, deployer, r.Scheme)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{RequeueAfter: time.Duration(&lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; * time.Second)}, err    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The Custom Resource file content is show above.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The CRD file can be found from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/crd/bases/greet.greetapp.com_greets.yaml&quot;&gt;Github&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-deployment-tips&quot;&gt;Deployment tips&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;During local development to run the operator in KinD we can use &lt;code&gt;make generate manifests install run&lt;/code&gt; command. &lt;/li&gt;&lt;li&gt;Upon deploying the Custom Resource the logs will be displayed like in below snapshot. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/d296ea1a-e8e8-48ff-9684-5bfc721f2e2f&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy the Custom Resource manifests use save the content to a file and use the &lt;code&gt;kubectl apply -f &amp;lt;file-name-with-content&amp;gt;.yaml&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In below the deployment has pod, config, service sections. The reconcile code will use these values to deploy them in Kuberented cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note the config in the Custom Resource (CR) file&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;fileName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;application.yaml&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|        env.name: k8s-kind-dev-env        greeting.source: from-k8s-configMap&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once application is deployed, with nginx container we can hit the endpoint and validate the response, which will look like in below snapshot&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/c0658ac8-04b2-46b2-be79-d334b35cb03a&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-creating-controller-image&quot;&gt;Creating controller image&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;From WSL2 we can use below command to create the controller image and push it to Dockerhub.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt; make docker-build docker-push IMG=thirumurthi/app-op:v1&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploying-spring-app-using-controller-image-crd-and-cr&quot;&gt;Deploying Spring app using Controller Image, CRD and CR&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy Spring app in test or production like environment we need to follow below steps&lt;/p&gt;&lt;h4 id=&quot;heading-deploy-the-controller-in-deployment-manifest&quot;&gt;Deploy the Controller in Deployment manifest&lt;/h4&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the deployment manifest to deploy the controller.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;operator-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;thirumurthi/app-op:v1&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-controller&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-crd&quot;&gt;Deploy the CRD&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/crd/bases/greet.greetapp.com_greets.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-deploy-the-cr&quot;&gt;Deploy the CR&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/thirumurthis/projects/blob/main/go-operator/app-op/config/samples/greet_v1alpha1_greet.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Note:- &lt;ul&gt;&lt;li&gt;When I tried to deploy the controller as deployment, there was an due to permission and it requires a ServiceAccount to be created. The ServiceAccount can be created in Operator SDK but for simplicity executed the following command manually.&lt;/li&gt;&lt;li&gt;The exception message that you would notice in case if ServiceAccount is not created.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;E0816 &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;51&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;14.671318&lt;/span&gt;       &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; reflector.go:&lt;span class=&quot;hljs-number&quot;&gt;148&lt;/span&gt;] pkg/mod/k8s.io/client-go@v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;/tools/cache/reflector.go:&lt;span class=&quot;hljs-number&quot;&gt;231&lt;/span&gt;: Failed to watch *v1alpha1.Greet: failed to list *v1alpha1.Greet: greets.greet.greetapp.com is forbidden: User &lt;span class=&quot;hljs-string&quot;&gt;&quot;system:serviceaccount:default:default&quot;&lt;/span&gt; cannot list resource &lt;span class=&quot;hljs-string&quot;&gt;&quot;greets&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; API group &lt;span class=&quot;hljs-string&quot;&gt;&quot;greet.greetapp.com&quot;&lt;/span&gt; at the cluster scope&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt; To manually create the ServiceAccount we can use below command&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code&gt;kubectl create clusterrole deployr --verb=get,list,watch,create,&lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;,patch,update --resource=deployments.appskubectl create clusterrolebinding deployr-srvacct-&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;-binding --clusterrole=deployr --serviceaccount=&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;:&lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output-after-deploying-the-controller-crd-and-cr&quot;&gt;Output after deploying the Controller, CRD and CR&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once Controller, CRD and CR are deployed the list of resources and the output accessing the deployed spring application looks like below snapshot.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/projects/assets/6425536/fbe560a4-0cf7-4691-9bff-eecae614298b&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Extend Kubernetes API with operator-sdk]]></title><description><![CDATA[Using operator sdk to create new Kubernetes api resources]]></description><link>https://thirumurthi.hashnode.dev/extend-kubernetes-api-with-operator-sdk</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/extend-kubernetes-api-with-operator-sdk</guid><category><![CDATA[operator SDK]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 29 Jul 2023 16:40:56 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;This article gives a brief overview of how to use Operator SDK (Go) to create Custom Resource Definition and Controller to extend Kubernetes API and manage Custom Resources.&lt;/p&gt;&lt;p&gt;This is a hands-on article and requires a good understanding in Kubernetes and how operators work. The operator code can be downloaded from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/tree/main/go-operator/app-op&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-extending-kubernetes-api-with-operator-sdk&quot;&gt;Extending Kubernetes API with Operator-SDK&lt;/h2&gt;&lt;p&gt;In this blog, have explained how to use operator-sdk to create additional resource in Kubernetes cluster. To start with you we first scaffold the project and create api using the operator-sdk cli, this gives us a starting point to develop the CRD&apos;s and Controllers. Note, not all points are explained in detail, only focus on necessary aspect required in developing operators.&lt;/p&gt;&lt;p&gt;I used Windows machine for development. The &lt;em&gt;operator-sdk&lt;/em&gt; CLI was installed in WSL2. The scaffolded operator-sdk project can be opened in Visual Studio code for development to update code.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes and Operators&lt;/li&gt;&lt;li&gt;Docker Desktop&lt;/li&gt;&lt;li&gt;KIND CLI (we will use KinD cluster, install in Windows)&lt;/li&gt;&lt;li&gt;kubectl Installed in WSL2 and Windows&lt;/li&gt;&lt;li&gt;Go installed in WSL2&lt;/li&gt;&lt;li&gt;GNU make installed and updated in WSL2&lt;/li&gt;&lt;li&gt;Operator-SDK CLI installed in WSL2&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-about-operator-framework&quot;&gt;About Operator framework&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Operator framework provides tools to extend the Kubernetes API, &lt;code&gt;kubectl api-resource&lt;/code&gt; will list the existing resources from the cluster API with operator framework we can create a new resource and deploy it to the cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Operator-SDK CLI provides option to scaffold the project and updates the project with the resource coordinates like Kind, Version and Group used to identify once the new resource is deployed to cluster. Few of the files will be edited, &lt;code&gt;api/&amp;lt;version&amp;gt;/&amp;lt;kind-name&amp;gt;_type.go&lt;/code&gt; file contains the go struct where we can define the properties this will be used to generate CRD. The reconciler logic goes into &lt;code&gt;controllers/&amp;lt;kind-name&amp;gt;_controller.go&lt;/code&gt;, the entry point will be the &lt;code&gt;main.go&lt;/code&gt; file. The operator-sdk project utilizes &lt;em&gt;kubebuilder&lt;/em&gt; underneath. The details are explained later. The operator-sdk already has the code to create new manager in &lt;code&gt;main.go&lt;/code&gt; and provides the basic code structure for reconciler logic under &lt;code&gt;controllers/&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once the CRD is deployed to the cluster, we need a controller logic which will monitor for any changes to the resources. For example, when the resource is created the controller will know of this event and in operator will invoke the defined function.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-install-golang-in-wsl2&quot;&gt;Install GoLang in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install GoLang, refer this &lt;a target=&quot;_blank&quot; href=&quot;https://go.dev/doc/install&quot;&gt;Go documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;wget https://dl.google.com/go/go1.20.4.linux-amd64.tar.gzsudo tar -xvf go1.20.4.linux-amd64.tar.gzsudo mv go /usr/local&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Open the &lt;code&gt;~/.bashrc&lt;/code&gt; file and add the below variables so it will update as environment variables&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;export GOROOT=/usr/local/goexport GOPATH=$HOME/goexport PATH=$GOPATH/bin:$GOROOT/bin:$PATH&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To find the Go version, issuing &lt;code&gt;go version&lt;/code&gt; command we should see the response like below.    &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ go versiongo version go1.20.4 linux/amd64&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-kind-cli-in-windows&quot;&gt;Install KinD CLI in Windows&lt;/h3&gt;&lt;p&gt;Download and install KinD CLI, this can be installed via Chocolatey, refer the &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kind&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The KinD cluster Kubernetes cluster configuration details.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;~$ kubectl version -o yamlclientVersion:  buildDate: &quot;2023-05-17T14:20:07Z&quot;  compiler: gc  gitCommit: 7f6f68fdabc4df88cfea2dcf9a19b2b830f1e647  gitTreeState: clean  gitVersion: v1.27.2  goVersion: go1.20.4  major: &quot;1&quot;  minor: &quot;27&quot;  platform: linux/amd64kustomizeVersion: v5.0.1serverVersion:  buildDate: &quot;2023-06-15T00:36:28Z&quot;  compiler: gc  gitCommit: 25b4e43193bcda6c7328a6d147b1fb73a33f1598  gitTreeState: clean  gitVersion: v1.27.3  goVersion: go1.20.5  major: &quot;1&quot;  minor: &quot;27&quot;  platform: linux/amd64&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-gnu-make-in-wsl2&quot;&gt;Install GNU make in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install GNU make version, simply use &lt;code&gt;sudo apt install make&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ make -versionGNU Make 4.3Built for x86_64-pc-linux-gnuCopyright (C) 1988-2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-operator-sdk-cli-in-wsl2&quot;&gt;Install Operator-SDK CLI in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To install operator-sdk refer the Operator SDK &lt;a target=&quot;_blank&quot; href=&quot;https://sdk.operatorframework.io/docs/installation/&quot;&gt;documentation&lt;/a&gt;, it is self explainotary.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once installed, we can view the version refer below snippet for command and output response.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ operator-sdk versionoperator-sdk version: &quot;v1.30.0&quot;, commit: &quot;b794fe909abc1affa1f28cfb75ceaf3bf79187e6&quot;, kubernetes version: &quot;1.26.0&quot;, go version: &quot;go1.19.10&quot;, GOOS: &quot;linux&quot;, GOARCH: &quot;amd64&quot;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-creating-new-operator-sdk-project-for-development&quot;&gt;Creating new Operator-SDK project for development&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Create a new folder, using the operator-sdk CLI we can initalize the project. The &lt;code&gt;operator-sdk init&lt;/code&gt; command will scaffold the necessary files. The command looks like below, the switch options explained below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;operator-sdk init --domain greetapp.com --repo github.com/thirumurthis/app-operator&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-of-operator-sdk-init-command&quot;&gt;Output of operator-sdk init command&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;Writing kustomize manifests for you to edit...Writing scaffold for you to edit...Get controller runtime:$ go get sigs.k8s.io/controller-runtime@v0.14.1Update dependencies:$ go mod tidyNext: define a resource with:$ operator-sdk create api&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The switch option in the operator-sdk command above used to scaffold a project.&lt;ul&gt;&lt;li&gt;&lt;code&gt;--domain&lt;/code&gt; in the command is required which will identify the resource when using &lt;code&gt;kubectl api-resource&lt;/code&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ kubectl api-resources | grep -e greet -e NAMENAME        SHORTNAMES   APIVERSION                             NAMESPACED   KINDgreets                   greet.greetapp.com/v1alpha1            true         Greet&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;--repo&lt;/code&gt; is used to specify that this project is outside go path.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;heading-update-the-scaffolded-project-with-the-api-with-operator-sdk-cli&quot;&gt;Update the scaffolded project with the API with operator-sdk CLI&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;As mentioned above the API is identified by Kubernetes cluster using Kind, Version and Group, we are using operator-sdk with these coordinates as switch options to update the already created operator-sdk project.&lt;/li&gt;&lt;li&gt;This will update the project structure by updating generated &lt;code&gt;_type.go&lt;/code&gt; file and other files.&lt;/li&gt;&lt;li&gt;The output of &lt;code&gt;operator-sdk init&lt;/code&gt; command also directs this step to be next.&lt;/li&gt;&lt;li&gt;The kind and version will be used in the CRD manifest.&lt;/li&gt;&lt;li&gt;Command to use operator-sdk CLI to create API on the scaffolded project.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ operator-sdk create api --group greet --version v1alpha1 --kind Greet --resource --controller&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;--resource&lt;/code&gt; and &lt;code&gt;--controller&lt;/code&gt; switch will update the resources and creates the controller. If not provided in the command, the CLI will prompt from user whether resources and controller required to be created for the project.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-output-of-operator-sdk-create-api-command&quot;&gt;Output of operator-sdk create api command&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;Writing kustomize manifests for you to edit...Writing scaffold for you to edit...api/v1alpha1/deploymentscaler_types.gocontrollers/deploymentscaler_controller.goUpdate dependencies:$ go mod tidyRunning make:$ make generatemkdir -p /mnt/c/goOperator/deploymentscaler/bintest -s /mnt/c/goOperator/deploymentscaler/bin/controller-gen &amp;amp;&amp;amp; /mnt/c/goOperator/deploymentscaler/bin/controller-gen --version | grep -q v0.11.1 || \GOBIN=/mnt/c/goOperator/deploymentscaler/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1/mnt/c/goOperator/deploymentscaler/bin/controller-gen object:headerFile=&quot;hack/boilerplate.go.txt&quot; paths=&quot;./...&quot;Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:$ make manifests&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The operator-sdk project includes a Makefile with bunch of useful commands that is useful during development.&lt;/li&gt;&lt;li&gt;In WSL2 terminal, if we are already navigated to the project folder issue &lt;code&gt;make manifests&lt;/code&gt; which will generate CRD file. This yaml file will be under &lt;code&gt;config/crd/bases/&lt;/code&gt;, in this case the file name will start with greet.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-update-the-go-mod-with-the-latest-library-version&quot;&gt;Update the go mod with the latest library version&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;This step is optional, the &lt;code&gt;go.mod&lt;/code&gt; file is updated in the project structure so the latest Kubernetes libraries will be used. These are the latest version at the time of writing this article.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;go.mod&lt;/code&gt; file with the updated version looks like below. Once the file is updated, issue &lt;code&gt;go mod tidy&lt;/code&gt; to download the latest libraries. &lt;code&gt;go.mod&lt;/code&gt; file is more like dependency manager for Go, like maven for Java or pacakge.json in node.js.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.19&lt;/span&gt;require (        github.com/onsi/ginkgo/v2 v2&lt;span class=&quot;hljs-number&quot;&gt;.9&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.5&lt;/span&gt;        github.com/onsi/gomega v1&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.7&lt;/span&gt;        k8s.io/apimachinery v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;        k8s.io/client-&lt;span class=&quot;hljs-keyword&quot;&gt;go&lt;/span&gt; v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;        sigs.k8s.io/controller-runtime v0&lt;span class=&quot;hljs-number&quot;&gt;.15&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-adding-new-property-to-the-crd&quot;&gt;Adding new property to the CRD&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Let&apos;s add new property to the CRD called &lt;code&gt;Name&lt;/code&gt;, latter we will see how we can read this value from the reconciler code and print this in log&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;Name&lt;/code&gt; property should be updated in the api/v1alpha1/&lt;code&gt;*_types.go&lt;/code&gt;, where &lt;code&gt;v1alpha1&lt;/code&gt; is the version used in the &lt;code&gt;operator-sdk create api&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The new property is updated in the &lt;code&gt;GreetSpec&lt;/code&gt; struct.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;On top of the new property, we add two markers to perform length validation (comments marked as 1 and 2).&lt;/li&gt;&lt;li&gt;Other section of the &lt;code&gt;greet_type.go&lt;/code&gt; file remains unchanged&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Note:- &lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The comment &lt;code&gt;//Name of the resource&lt;/code&gt; above new property will be displayed in the CRD as description. &lt;/li&gt;&lt;li&gt;To create a new CRD from the project use &lt;code&gt;make manifests&lt;/code&gt; command in WSL2 the file will be created under &apos;config/crd/bases/&apos;. Once deployed to the cluster the same can be viewed using &lt;code&gt;kubectl explain &amp;lt;crd-resource-name&amp;gt;&lt;/code&gt; command.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; v1alpha1&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetSpec &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;//Name of the resource &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MaxLength=15   // ---&amp;gt;  1 maker for validation&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MinLength=1    // ---&amp;gt;  2 maker for validation&lt;/span&gt;    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//------------------&amp;gt; 3 new property for the CRD&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetList contains a list of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetList &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ListMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Items           []Greet &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;items&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    SchemeBuilder.Register(&amp;amp;Greet{}, &amp;amp;GreetList{})}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the above code change, if we issue make manifests command, the CRD YAML file gets created under &lt;code&gt;config/crd/bases/&lt;/code&gt;. The newly added properties will look like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;resource&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;maxLength:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;minLength:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;string&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;required:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;name&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;object&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-update-the-controller-code-to-read-the-new-property&quot;&gt;Update the controller code to read the new property&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Whenever the &lt;code&gt;api/v1alpha1/greet_types1&lt;/code&gt;file is updated, we need to use &lt;code&gt;make generate&lt;/code&gt; command. This command will perform updates the project with the newly included properties.&lt;/li&gt;&lt;li&gt;Below is the reconciler Go code created by operator-sdk under &lt;code&gt;controllers&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;In the Reconcile function, the &lt;code&gt;log.Log&lt;/code&gt; is used to log simple message&lt;/li&gt;&lt;li&gt;We initialize an instance of the Greet CRD object which has Name property&lt;/li&gt;&lt;li&gt;The &lt;code&gt;r.Get()&lt;/code&gt; will fetch the CRD instance from the Cluster, in case of error when obtaining the object simply return.&lt;/li&gt;&lt;li&gt;If the CRD instance is available, we get the name and log it.&lt;/li&gt;&lt;li&gt;At this point there are NO changes to other files in the project.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;) &lt;span class=&quot;hljs-comment&quot;&gt;// -------------&amp;gt; Logs the message passed&lt;/span&gt;    instance := &amp;amp;greetv1alpha1.Greet{}   &lt;span class=&quot;hljs-comment&quot;&gt;//--------------&amp;gt; initalize an instance of the CRD &lt;/span&gt;    err := r.Get(ctx, req.NamespacedName, instance)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }    appName := instance.Spec.Name        &lt;span class=&quot;hljs-comment&quot;&gt;// Get the name from the CR deployed &lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app Name for CRD is - %s &quot;&lt;/span&gt;,appName))    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {      log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;,instance.Spec.Name))    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {      log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-create-the-custom-resource-for-the-greet-crd&quot;&gt;Create the Custom resource for the Greet CRD&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The skeleton of the Custom Resource file will be created when we issue &lt;code&gt;make manifests&lt;/code&gt;, where the newly added property is used here &lt;code&gt;name: first-app&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet.greetapp.com/v1alpha1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Greet&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/instance:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/part-of:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/managed-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/created-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# TODO(user): Add fields here&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-operator-to-local-kind-cluster&quot;&gt;Deploy operator to local KinD cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The operator-sdk includes additional make targets, to help in development. Issuing below command will deploy the controller changes to local kind cluster. The output looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;In below output first deployed operator changes using &lt;code&gt;make generate install run&lt;/code&gt;, then deployed the Custom Resource manifest. &lt;/li&gt;&lt;li&gt;Once the operator sees the CR deployment a create event is received by reconciler and the based on the logic to print the log the log info will be printed.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;If make generate install run from the WSL2 terminal was not able to find the Kubernetes cluster, you can copy the kube config from the windows .kube to WSL2 path.&lt;/li&gt;&lt;li&gt;Form WSL2 terminal, you can use below command to copy,&lt;pre&gt;&lt;code&gt;cp /mnt/c/Users/&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;username&lt;/span&gt;&amp;gt;&lt;/span&gt;/.kube/config ~/.kube/config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ make generate install run....go run ./main.go2023-07-23T13:28:13-07:00       INFO    controller-runtime.metrics      Metrics server is starting to listen    {&quot;addr&quot;: &quot;:8080&quot;}2023-07-23T13:28:13-07:00       INFO    setup   starting manager2023-07-23T13:28:13-07:00       INFO    Starting server {&quot;kind&quot;: &quot;health probe&quot;, &quot;addr&quot;: &quot;[::]:8081&quot;}2023-07-23T13:28:13-07:00       INFO    starting server {&quot;path&quot;: &quot;/metrics&quot;, &quot;kind&quot;: &quot;metrics&quot;, &quot;addr&quot;: &quot;[::]:8080&quot;}2023-07-23T13:28:13-07:00       INFO    Starting EventSource    {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;, &quot;source&quot;: &quot;kind source: *v1alpha1.Greet&quot;}2023-07-23T13:28:13-07:00       INFO    Starting Controller     {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;}2023-07-23T13:28:13-07:00       INFO    Starting workers        {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;, &quot;worker count&quot;: 1}2023-07-23T13:28:28-07:00       INFO    Reconciler invoked..2023-07-23T13:28:28-07:00       INFO    app Name for CRD is - first-app2023-07-23T13:28:28-07:00       INFO    appName for CRD is - first-app2023-07-23T13:28:28-07:00       INFO    GET invoked reconcile for resource name - greet-sample&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-once-operator-deployed&quot;&gt;Output once operator deployed&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/782d4fab-7529-4584-9371-d69b0237e3cd&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;kubectl describe&lt;/code&gt; to describe the CRD and looks like below, note there are no event info we can add it later in next section to controller code.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/c898b5fe-1cc4-48f3-b5b2-329694e2b1e4&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-tracking-event-in-the-controller&quot;&gt;Tracking Event in the Controller&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To record the events, first we need to add recorder to the &lt;code&gt;GreetReconciler&lt;/code&gt; struct in the &lt;code&gt;controllers/greet_controller.go&lt;/code&gt; file and import the library for record.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt;(  ....    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/client-go/tools/record&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Import the library for record&lt;/span&gt;  ....)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetReconciler &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    client.Client    Scheme *runtime.Scheme    Recorder record.EventRecorder      &lt;span class=&quot;hljs-comment&quot;&gt;// New Recorder event&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We will use the Recorder event object to record events and the code looks like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)        instance := &amp;amp;greetv1alpha1.Greet{}    err := r.Get(ctx, req.NamespacedName, instance)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        &lt;span class=&quot;hljs-comment&quot;&gt;// If there are errors we record an event.&lt;/span&gt;        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }       appName := instance.Spec.Name       &lt;span class=&quot;hljs-comment&quot;&gt;// Recorder event added&lt;/span&gt;       r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))       &lt;span class=&quot;hljs-comment&quot;&gt;//..... other code&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Since the &lt;code&gt;GreetReconciler&lt;/code&gt; struct is updated to include a recorder object, the &lt;code&gt;main.go&lt;/code&gt; needs to fetch the recorder object from the manager and set to the struct.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;   &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err = (&amp;amp;controllers.GreetReconciler{               Client: mgr.GetClient(),               Scheme: mgr.GetScheme(),               Recorder: mgr.GetEventRecorderFor(&lt;span class=&quot;hljs-string&quot;&gt;&quot;greet-controller&quot;&lt;/span&gt;), &lt;span class=&quot;hljs-comment&quot;&gt;//Obtain the recorder&lt;/span&gt;   }).SetupWithManager(mgr); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {       setupLog.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;unable to create controller&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;controller&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;)       os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)   }&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-events-are-displayed-when-we-describe-the-crd&quot;&gt;Output events are displayed when we describe the CRD&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;If the operator is running in local cluster stop it. &lt;code&gt;make generate install run&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Delete the CR if it already deployed using &lt;code&gt;kubectl delete&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Once deployed the operator will display the log message.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4ac8148b-9ca4-472a-8fd5-e63bfc317c42&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In Recorder.Event the &quot;Object&quot; is the displayed as reason of the event.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt; r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-where-the-recorderevent-is-updated-with-different-value&quot;&gt;Output where the &lt;code&gt;Recorder.Event&lt;/code&gt; is updated with different value&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/11cb3ad3-3f50-439d-be7a-9d2c6f407511&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-update-the-status-when-the-custom-resource-deployed&quot;&gt;Update the status when the Custom Resource deployed&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Once the Controller and Custom resources are deployed, we can track the status with &lt;code&gt;kubectl get greet/greet-sample -w&lt;/code&gt;, in this section we will see the code changes required to include the &lt;code&gt;APPNAME&lt;/code&gt; and &lt;code&gt;STATUS&lt;/code&gt; so when using &lt;code&gt;kubectl get &amp;lt;crd-resource-name&amp;gt;&lt;/code&gt; will provide the info which like in the snapshot.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4c1df07f-add4-48b4-a8e3-f63e22563705&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In the &lt;code&gt;api/v1alpha1/greet_type.go&lt;/code&gt; file we need to add the marker like below over the corresponding &lt;code&gt;Greet&lt;/code&gt; struct in this case.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In the code snippet of the &lt;code&gt;greet_type.go&lt;/code&gt; file, the &lt;code&gt;GreetStatus&lt;/code&gt; struct includes new property &lt;code&gt;Status&lt;/code&gt; which is of type string.&lt;/li&gt;&lt;li&gt;In the &lt;code&gt;controllers/greet_controller.go&lt;/code&gt; reconciler function we check the status and updated it dynamically based on resource status.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {        Status &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;// ----------&amp;gt; newly added status property&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//Don&apos;t leave any new line space between the marker // below marker used to display APPNAME and STATUS&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.displayName=&quot;Greet App&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.resources=&quot;Deployment,v1,\&quot;A Kubernetes Deployment of greet app\&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-the-reconciler-logic-to-validate-set-and-update-the-status&quot;&gt;The reconciler logic to validate, set and update the status&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)    instance := &amp;amp;greetv1alpha1.Greet{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, req.NamespacedName, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {             r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)             log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)             &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{},client.IgnoreNotFound(err)    }       appName := instance.Spec.Name       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {      log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;,instance.Spec.Name))          r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))       } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {          log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)       }      &lt;span class=&quot;hljs-comment&quot;&gt;// update the ok when it is blank&lt;/span&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Status.Status == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {          instance.Status.Status = &lt;span class=&quot;hljs-string&quot;&gt;&quot;OK&quot;&lt;/span&gt;          log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - is set to OK&quot;&lt;/span&gt;)      }      &lt;span class=&quot;hljs-comment&quot;&gt;// update the status with client ------------&amp;gt; Only status will be updated&lt;/span&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Status().Update(ctx, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {             log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)             &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{},client.IgnoreNotFound(err)      }      &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-for-status-change&quot;&gt;Output for status change&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Stop the operator if it was deployed in local cluster.&lt;/li&gt;&lt;li&gt;Delete the Custom Resource if it was deployed to local cluster&lt;/li&gt;&lt;li&gt;Deploy the operator to local cluster using &lt;code&gt;make generate install run&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Deploy the custom resource yaml manifest to the local cluster using &lt;code&gt;kubectl apply -f config/samples/&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;With&lt;code&gt;kubectl get greet/greet-sample -w&lt;/code&gt; command we can monitor the resource status.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/fbb3b88b-fd7a-4d2b-9bb4-36d4f3976e7d&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-points-that-where-not-covered&quot;&gt;Points that where not covered&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Deploying the operator in actual cluster by creating an image.&lt;/li&gt;&lt;li&gt;We can package the CRDs to helm and deploy it via helm CLI&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;p&gt;This article gives a brief overview of how to use Operator SDK (Go) to create Custom Resource Definition and Controller to extend Kubernetes API and manage Custom Resources.&lt;/p&gt;&lt;p&gt;This is a hands-on article and requires a good understanding in Kubernetes and how operators work. The operator code can be downloaded from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/tree/main/go-operator/app-op&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-extending-kubernetes-api-with-operator-sdk&quot;&gt;Extending Kubernetes API with Operator-SDK&lt;/h2&gt;&lt;p&gt;In this blog, have explained how to use operator-sdk to create additional resource in Kubernetes cluster. To start with you we first scaffold the project and create api using the operator-sdk cli, this gives us a starting point to develop the CRD&apos;s and Controllers. Note, not all points are explained in detail, only focus on necessary aspect required in developing operators.&lt;/p&gt;&lt;p&gt;I used Windows machine for development. The &lt;em&gt;operator-sdk&lt;/em&gt; CLI was installed in WSL2. The scaffolded operator-sdk project can be opened in Visual Studio code for development to update code.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes and Operators&lt;/li&gt;&lt;li&gt;Docker Desktop&lt;/li&gt;&lt;li&gt;KIND CLI (we will use KinD cluster, install in Windows)&lt;/li&gt;&lt;li&gt;kubectl Installed in WSL2 and Windows&lt;/li&gt;&lt;li&gt;Go installed in WSL2&lt;/li&gt;&lt;li&gt;GNU make installed and updated in WSL2&lt;/li&gt;&lt;li&gt;Operator-SDK CLI installed in WSL2&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-about-operator-framework&quot;&gt;About Operator framework&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Operator framework provides tools to extend the Kubernetes API, &lt;code&gt;kubectl api-resource&lt;/code&gt; will list the existing resources from the cluster API with operator framework we can create a new resource and deploy it to the cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Operator-SDK CLI provides option to scaffold the project and updates the project with the resource coordinates like Kind, Version and Group used to identify once the new resource is deployed to cluster. Few of the files will be edited, &lt;code&gt;api/&amp;lt;version&amp;gt;/&amp;lt;kind-name&amp;gt;_type.go&lt;/code&gt; file contains the go struct where we can define the properties this will be used to generate CRD. The reconciler logic goes into &lt;code&gt;controllers/&amp;lt;kind-name&amp;gt;_controller.go&lt;/code&gt;, the entry point will be the &lt;code&gt;main.go&lt;/code&gt; file. The operator-sdk project utilizes &lt;em&gt;kubebuilder&lt;/em&gt; underneath. The details are explained later. The operator-sdk already has the code to create new manager in &lt;code&gt;main.go&lt;/code&gt; and provides the basic code structure for reconciler logic under &lt;code&gt;controllers/&lt;/code&gt; folder.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once the CRD is deployed to the cluster, we need a controller logic which will monitor for any changes to the resources. For example, when the resource is created the controller will know of this event and in operator will invoke the defined function.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-install-golang-in-wsl2&quot;&gt;Install GoLang in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install GoLang, refer this &lt;a target=&quot;_blank&quot; href=&quot;https://go.dev/doc/install&quot;&gt;Go documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;wget https://dl.google.com/go/go1.20.4.linux-amd64.tar.gzsudo tar -xvf go1.20.4.linux-amd64.tar.gzsudo mv go /usr/local&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Open the &lt;code&gt;~/.bashrc&lt;/code&gt; file and add the below variables so it will update as environment variables&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;export GOROOT=/usr/local/goexport GOPATH=$HOME/goexport PATH=$GOPATH/bin:$GOROOT/bin:$PATH&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To find the Go version, issuing &lt;code&gt;go version&lt;/code&gt; command we should see the response like below.    &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ go versiongo version go1.20.4 linux/amd64&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-kind-cli-in-windows&quot;&gt;Install KinD CLI in Windows&lt;/h3&gt;&lt;p&gt;Download and install KinD CLI, this can be installed via Chocolatey, refer the &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kind&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The KinD cluster Kubernetes cluster configuration details.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;~$ kubectl version -o yamlclientVersion:  buildDate: &quot;2023-05-17T14:20:07Z&quot;  compiler: gc  gitCommit: 7f6f68fdabc4df88cfea2dcf9a19b2b830f1e647  gitTreeState: clean  gitVersion: v1.27.2  goVersion: go1.20.4  major: &quot;1&quot;  minor: &quot;27&quot;  platform: linux/amd64kustomizeVersion: v5.0.1serverVersion:  buildDate: &quot;2023-06-15T00:36:28Z&quot;  compiler: gc  gitCommit: 25b4e43193bcda6c7328a6d147b1fb73a33f1598  gitTreeState: clean  gitVersion: v1.27.3  goVersion: go1.20.5  major: &quot;1&quot;  minor: &quot;27&quot;  platform: linux/amd64&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-gnu-make-in-wsl2&quot;&gt;Install GNU make in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install GNU make version, simply use &lt;code&gt;sudo apt install make&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ make -versionGNU Make 4.3Built for x86_64-pc-linux-gnuCopyright (C) 1988-2020 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-operator-sdk-cli-in-wsl2&quot;&gt;Install Operator-SDK CLI in WSL2&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To install operator-sdk refer the Operator SDK &lt;a target=&quot;_blank&quot; href=&quot;https://sdk.operatorframework.io/docs/installation/&quot;&gt;documentation&lt;/a&gt;, it is self explainotary.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once installed, we can view the version refer below snippet for command and output response.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ operator-sdk versionoperator-sdk version: &quot;v1.30.0&quot;, commit: &quot;b794fe909abc1affa1f28cfb75ceaf3bf79187e6&quot;, kubernetes version: &quot;1.26.0&quot;, go version: &quot;go1.19.10&quot;, GOOS: &quot;linux&quot;, GOARCH: &quot;amd64&quot;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-creating-new-operator-sdk-project-for-development&quot;&gt;Creating new Operator-SDK project for development&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Create a new folder, using the operator-sdk CLI we can initalize the project. The &lt;code&gt;operator-sdk init&lt;/code&gt; command will scaffold the necessary files. The command looks like below, the switch options explained below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;operator-sdk init --domain greetapp.com --repo github.com/thirumurthis/app-operator&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-of-operator-sdk-init-command&quot;&gt;Output of operator-sdk init command&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;Writing kustomize manifests for you to edit...Writing scaffold for you to edit...Get controller runtime:$ go get sigs.k8s.io/controller-runtime@v0.14.1Update dependencies:$ go mod tidyNext: define a resource with:$ operator-sdk create api&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The switch option in the operator-sdk command above used to scaffold a project.&lt;ul&gt;&lt;li&gt;&lt;code&gt;--domain&lt;/code&gt; in the command is required which will identify the resource when using &lt;code&gt;kubectl api-resource&lt;/code&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ kubectl api-resources | grep -e greet -e NAMENAME        SHORTNAMES   APIVERSION                             NAMESPACED   KINDgreets                   greet.greetapp.com/v1alpha1            true         Greet&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;--repo&lt;/code&gt; is used to specify that this project is outside go path.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h2 id=&quot;heading-update-the-scaffolded-project-with-the-api-with-operator-sdk-cli&quot;&gt;Update the scaffolded project with the API with operator-sdk CLI&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;As mentioned above the API is identified by Kubernetes cluster using Kind, Version and Group, we are using operator-sdk with these coordinates as switch options to update the already created operator-sdk project.&lt;/li&gt;&lt;li&gt;This will update the project structure by updating generated &lt;code&gt;_type.go&lt;/code&gt; file and other files.&lt;/li&gt;&lt;li&gt;The output of &lt;code&gt;operator-sdk init&lt;/code&gt; command also directs this step to be next.&lt;/li&gt;&lt;li&gt;The kind and version will be used in the CRD manifest.&lt;/li&gt;&lt;li&gt;Command to use operator-sdk CLI to create API on the scaffolded project.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ operator-sdk create api --group greet --version v1alpha1 --kind Greet --resource --controller&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;--resource&lt;/code&gt; and &lt;code&gt;--controller&lt;/code&gt; switch will update the resources and creates the controller. If not provided in the command, the CLI will prompt from user whether resources and controller required to be created for the project.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-output-of-operator-sdk-create-api-command&quot;&gt;Output of operator-sdk create api command&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;Writing kustomize manifests for you to edit...Writing scaffold for you to edit...api/v1alpha1/deploymentscaler_types.gocontrollers/deploymentscaler_controller.goUpdate dependencies:$ go mod tidyRunning make:$ make generatemkdir -p /mnt/c/goOperator/deploymentscaler/bintest -s /mnt/c/goOperator/deploymentscaler/bin/controller-gen &amp;amp;&amp;amp; /mnt/c/goOperator/deploymentscaler/bin/controller-gen --version | grep -q v0.11.1 || \GOBIN=/mnt/c/goOperator/deploymentscaler/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.11.1/mnt/c/goOperator/deploymentscaler/bin/controller-gen object:headerFile=&quot;hack/boilerplate.go.txt&quot; paths=&quot;./...&quot;Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:$ make manifests&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The operator-sdk project includes a Makefile with bunch of useful commands that is useful during development.&lt;/li&gt;&lt;li&gt;In WSL2 terminal, if we are already navigated to the project folder issue &lt;code&gt;make manifests&lt;/code&gt; which will generate CRD file. This yaml file will be under &lt;code&gt;config/crd/bases/&lt;/code&gt;, in this case the file name will start with greet.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-update-the-go-mod-with-the-latest-library-version&quot;&gt;Update the go mod with the latest library version&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;This step is optional, the &lt;code&gt;go.mod&lt;/code&gt; file is updated in the project structure so the latest Kubernetes libraries will be used. These are the latest version at the time of writing this article.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;go.mod&lt;/code&gt; file with the updated version looks like below. Once the file is updated, issue &lt;code&gt;go mod tidy&lt;/code&gt; to download the latest libraries. &lt;code&gt;go.mod&lt;/code&gt; file is more like dependency manager for Go, like maven for Java or pacakge.json in node.js.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1.19&lt;/span&gt;require (        github.com/onsi/ginkgo/v2 v2&lt;span class=&quot;hljs-number&quot;&gt;.9&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.5&lt;/span&gt;        github.com/onsi/gomega v1&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.7&lt;/span&gt;        k8s.io/apimachinery v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;        k8s.io/client-&lt;span class=&quot;hljs-keyword&quot;&gt;go&lt;/span&gt; v0&lt;span class=&quot;hljs-number&quot;&gt;.27&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.4&lt;/span&gt;        sigs.k8s.io/controller-runtime v0&lt;span class=&quot;hljs-number&quot;&gt;.15&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-adding-new-property-to-the-crd&quot;&gt;Adding new property to the CRD&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Let&apos;s add new property to the CRD called &lt;code&gt;Name&lt;/code&gt;, latter we will see how we can read this value from the reconciler code and print this in log&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The &lt;code&gt;Name&lt;/code&gt; property should be updated in the api/v1alpha1/&lt;code&gt;*_types.go&lt;/code&gt;, where &lt;code&gt;v1alpha1&lt;/code&gt; is the version used in the &lt;code&gt;operator-sdk create api&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The new property is updated in the &lt;code&gt;GreetSpec&lt;/code&gt; struct.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;On top of the new property, we add two markers to perform length validation (comments marked as 1 and 2).&lt;/li&gt;&lt;li&gt;Other section of the &lt;code&gt;greet_type.go&lt;/code&gt; file remains unchanged&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Note:- &lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;The comment &lt;code&gt;//Name of the resource&lt;/code&gt; above new property will be displayed in the CRD as description. &lt;/li&gt;&lt;li&gt;To create a new CRD from the project use &lt;code&gt;make manifests&lt;/code&gt; command in WSL2 the file will be created under &apos;config/crd/bases/&apos;. Once deployed to the cluster the same can be viewed using &lt;code&gt;kubectl explain &amp;lt;crd-resource-name&amp;gt;&lt;/code&gt; command.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; v1alpha1&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    metav1 &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/apimachinery/pkg/apis/meta/v1&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetSpec &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    &lt;span class=&quot;hljs-comment&quot;&gt;//Name of the resource &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MaxLength=15   // ---&amp;gt;  1 maker for validation&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// +kubebuilder:validation:MinLength=1    // ---&amp;gt;  2 maker for validation&lt;/span&gt;    Name &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//------------------&amp;gt; 3 new property for the CRD&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetList contains a list of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetList &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ListMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Items           []Greet &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;items&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    SchemeBuilder.Register(&amp;amp;Greet{}, &amp;amp;GreetList{})}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the above code change, if we issue make manifests command, the CRD YAML file gets created under &lt;code&gt;config/crd/bases/&lt;/code&gt;. The newly added properties will look like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Name&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;resource&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;maxLength:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;minLength:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;                &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;string&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;required:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;name&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;object&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-update-the-controller-code-to-read-the-new-property&quot;&gt;Update the controller code to read the new property&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Whenever the &lt;code&gt;api/v1alpha1/greet_types1&lt;/code&gt;file is updated, we need to use &lt;code&gt;make generate&lt;/code&gt; command. This command will perform updates the project with the newly included properties.&lt;/li&gt;&lt;li&gt;Below is the reconciler Go code created by operator-sdk under &lt;code&gt;controllers&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;In the Reconcile function, the &lt;code&gt;log.Log&lt;/code&gt; is used to log simple message&lt;/li&gt;&lt;li&gt;We initialize an instance of the Greet CRD object which has Name property&lt;/li&gt;&lt;li&gt;The &lt;code&gt;r.Get()&lt;/code&gt; will fetch the CRD instance from the Cluster, in case of error when obtaining the object simply return.&lt;/li&gt;&lt;li&gt;If the CRD instance is available, we get the name and log it.&lt;/li&gt;&lt;li&gt;At this point there are NO changes to other files in the project.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;) &lt;span class=&quot;hljs-comment&quot;&gt;// -------------&amp;gt; Logs the message passed&lt;/span&gt;    instance := &amp;amp;greetv1alpha1.Greet{}   &lt;span class=&quot;hljs-comment&quot;&gt;//--------------&amp;gt; initalize an instance of the CRD &lt;/span&gt;    err := r.Get(ctx, req.NamespacedName, instance)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }    appName := instance.Spec.Name        &lt;span class=&quot;hljs-comment&quot;&gt;// Get the name from the CR deployed &lt;/span&gt;    log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;app Name for CRD is - %s &quot;&lt;/span&gt;,appName))    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {      log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;,instance.Spec.Name))    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {      log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)    }    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-create-the-custom-resource-for-the-greet-crd&quot;&gt;Create the Custom resource for the Greet CRD&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The skeleton of the Custom Resource file will be created when we issue &lt;code&gt;make manifests&lt;/code&gt;, where the newly added property is used here &lt;code&gt;name: first-app&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet.greetapp.com/v1alpha1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Greet&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/instance:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/part-of:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/managed-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app.kubernetes.io/created-by:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;app-op&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;greet-sample&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# TODO(user): Add fields here&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;first-app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-deploy-operator-to-local-kind-cluster&quot;&gt;Deploy operator to local KinD cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The operator-sdk includes additional make targets, to help in development. Issuing below command will deploy the controller changes to local kind cluster. The output looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;In below output first deployed operator changes using &lt;code&gt;make generate install run&lt;/code&gt;, then deployed the Custom Resource manifest. &lt;/li&gt;&lt;li&gt;Once the operator sees the CR deployment a create event is received by reconciler and the based on the logic to print the log the log info will be printed.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;em&gt;Info:&lt;/em&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;ul&gt;&lt;li&gt;If make generate install run from the WSL2 terminal was not able to find the Kubernetes cluster, you can copy the kube config from the windows .kube to WSL2 path.&lt;/li&gt;&lt;li&gt;Form WSL2 terminal, you can use below command to copy,&lt;pre&gt;&lt;code&gt;cp /mnt/c/Users/&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;username&lt;/span&gt;&amp;gt;&lt;/span&gt;/.kube/config ~/.kube/config&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ make generate install run....go run ./main.go2023-07-23T13:28:13-07:00       INFO    controller-runtime.metrics      Metrics server is starting to listen    {&quot;addr&quot;: &quot;:8080&quot;}2023-07-23T13:28:13-07:00       INFO    setup   starting manager2023-07-23T13:28:13-07:00       INFO    Starting server {&quot;kind&quot;: &quot;health probe&quot;, &quot;addr&quot;: &quot;[::]:8081&quot;}2023-07-23T13:28:13-07:00       INFO    starting server {&quot;path&quot;: &quot;/metrics&quot;, &quot;kind&quot;: &quot;metrics&quot;, &quot;addr&quot;: &quot;[::]:8080&quot;}2023-07-23T13:28:13-07:00       INFO    Starting EventSource    {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;, &quot;source&quot;: &quot;kind source: *v1alpha1.Greet&quot;}2023-07-23T13:28:13-07:00       INFO    Starting Controller     {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;}2023-07-23T13:28:13-07:00       INFO    Starting workers        {&quot;controller&quot;: &quot;greet&quot;, &quot;controllerGroup&quot;: &quot;greet.greetapp.com&quot;, &quot;controllerKind&quot;: &quot;Greet&quot;, &quot;worker count&quot;: 1}2023-07-23T13:28:28-07:00       INFO    Reconciler invoked..2023-07-23T13:28:28-07:00       INFO    app Name for CRD is - first-app2023-07-23T13:28:28-07:00       INFO    appName for CRD is - first-app2023-07-23T13:28:28-07:00       INFO    GET invoked reconcile for resource name - greet-sample&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-once-operator-deployed&quot;&gt;Output once operator deployed&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/782d4fab-7529-4584-9371-d69b0237e3cd&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;kubectl describe&lt;/code&gt; to describe the CRD and looks like below, note there are no event info we can add it later in next section to controller code.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/c898b5fe-1cc4-48f3-b5b2-329694e2b1e4&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-tracking-event-in-the-controller&quot;&gt;Tracking Event in the Controller&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To record the events, first we need to add recorder to the &lt;code&gt;GreetReconciler&lt;/code&gt; struct in the &lt;code&gt;controllers/greet_controller.go&lt;/code&gt; file and import the library for record.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt;(  ....    &lt;span class=&quot;hljs-string&quot;&gt;&quot;k8s.io/client-go/tools/record&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// Import the library for record&lt;/span&gt;  ....)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetReconciler &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    client.Client    Scheme *runtime.Scheme    Recorder record.EventRecorder      &lt;span class=&quot;hljs-comment&quot;&gt;// New Recorder event&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We will use the Recorder event object to record events and the code looks like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)        instance := &amp;amp;greetv1alpha1.Greet{}    err := r.Get(ctx, req.NamespacedName, instance)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        &lt;span class=&quot;hljs-comment&quot;&gt;// If there are errors we record an event.&lt;/span&gt;        r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }       appName := instance.Spec.Name       &lt;span class=&quot;hljs-comment&quot;&gt;// Recorder event added&lt;/span&gt;       r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))       &lt;span class=&quot;hljs-comment&quot;&gt;//..... other code&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Since the &lt;code&gt;GreetReconciler&lt;/code&gt; struct is updated to include a recorder object, the &lt;code&gt;main.go&lt;/code&gt; needs to fetch the recorder object from the manager and set to the struct.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;   &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err = (&amp;amp;controllers.GreetReconciler{               Client: mgr.GetClient(),               Scheme: mgr.GetScheme(),               Recorder: mgr.GetEventRecorderFor(&lt;span class=&quot;hljs-string&quot;&gt;&quot;greet-controller&quot;&lt;/span&gt;), &lt;span class=&quot;hljs-comment&quot;&gt;//Obtain the recorder&lt;/span&gt;   }).SetupWithManager(mgr); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {       setupLog.Error(err, &lt;span class=&quot;hljs-string&quot;&gt;&quot;unable to create controller&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;controller&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;)       os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)   }&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-events-are-displayed-when-we-describe-the-crd&quot;&gt;Output events are displayed when we describe the CRD&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;If the operator is running in local cluster stop it. &lt;code&gt;make generate install run&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Delete the CR if it already deployed using &lt;code&gt;kubectl delete&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;Once deployed the operator will display the log message.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4ac8148b-9ca4-472a-8fd5-e63bfc317c42&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In Recorder.Event the &quot;Object&quot; is the displayed as reason of the event.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt; r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-where-the-recorderevent-is-updated-with-different-value&quot;&gt;Output where the &lt;code&gt;Recorder.Event&lt;/code&gt; is updated with different value&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/11cb3ad3-3f50-439d-be7a-9d2c6f407511&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-update-the-status-when-the-custom-resource-deployed&quot;&gt;Update the status when the Custom Resource deployed&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Once the Controller and Custom resources are deployed, we can track the status with &lt;code&gt;kubectl get greet/greet-sample -w&lt;/code&gt;, in this section we will see the code changes required to include the &lt;code&gt;APPNAME&lt;/code&gt; and &lt;code&gt;STATUS&lt;/code&gt; so when using &lt;code&gt;kubectl get &amp;lt;crd-resource-name&amp;gt;&lt;/code&gt; will provide the info which like in the snapshot.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4c1df07f-add4-48b4-a8e3-f63e22563705&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In the &lt;code&gt;api/v1alpha1/greet_type.go&lt;/code&gt; file we need to add the marker like below over the corresponding &lt;code&gt;Greet&lt;/code&gt; struct in this case.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In the code snippet of the &lt;code&gt;greet_type.go&lt;/code&gt; file, the &lt;code&gt;GreetStatus&lt;/code&gt; struct includes new property &lt;code&gt;Status&lt;/code&gt; which is of type string.&lt;/li&gt;&lt;li&gt;In the &lt;code&gt;controllers/greet_controller.go&lt;/code&gt; reconciler function we check the status and updated it dynamically based on resource status.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// GreetStatus defines the observed state of Greet&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; GreetStatus &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {        Status &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;// ----------&amp;gt; newly added status property&lt;/span&gt;}&lt;span class=&quot;hljs-comment&quot;&gt;//Don&apos;t leave any new line space between the marker // below marker used to display APPNAME and STATUS&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:object:root=true&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;APPNAME&quot;,type=&quot;string&quot;,JSONPath=&quot;.spec.name&quot;,description=&quot;Name of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:printcolumn:name=&quot;STATUS&quot;,type=&quot;string&quot;,JSONPath=&quot;.status.status&quot;,description=&quot;Status of the app&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//+kubebuilder:subresource:status&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.displayName=&quot;Greet App&quot;&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// +operator-sdk:gen-csv:customresourcedefinitions.resources=&quot;Deployment,v1,\&quot;A Kubernetes Deployment of greet app\&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; Greet &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    metav1.TypeMeta   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;,inline&quot;`&lt;/span&gt;    metav1.ObjectMeta &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;metadata,omitempty&quot;`&lt;/span&gt;    Spec   GreetSpec   &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;spec,omitempty&quot;`&lt;/span&gt;    Status GreetStatus &lt;span class=&quot;hljs-string&quot;&gt;`json:&quot;status,omitempty&quot;`&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-the-reconciler-logic-to-validate-set-and-update-the-status&quot;&gt;The reconciler logic to validate, set and update the status&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(r *GreetReconciler)&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Reconcile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ctx context.Context, req ctrl.Request)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;(ctrl.Result, error)&lt;/span&gt;&lt;/span&gt; {    _ = log.FromContext(ctx)    log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Reconciler invoked..&quot;&lt;/span&gt;)    instance := &amp;amp;greetv1alpha1.Greet{}    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Get(ctx, req.NamespacedName, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {             r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Object&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Failed to read Object&quot;&lt;/span&gt;)             log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)             &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{},client.IgnoreNotFound(err)    }       appName := instance.Spec.Name       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Spec.Name != &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {      log.Log.Info(fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;appName for CRD is - %s &quot;&lt;/span&gt;,instance.Spec.Name))          r.Recorder.Event(instance, corev1.EventTypeWarning, &lt;span class=&quot;hljs-string&quot;&gt;&quot;Greet&quot;&lt;/span&gt;, fmt.Sprintf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Created - %s &quot;&lt;/span&gt;,appName))       } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {          log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - NOT FOUND&quot;&lt;/span&gt;)       }      &lt;span class=&quot;hljs-comment&quot;&gt;// update the ok when it is blank&lt;/span&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; instance.Status.Status == &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; {          instance.Status.Status = &lt;span class=&quot;hljs-string&quot;&gt;&quot;OK&quot;&lt;/span&gt;          log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;instance.Spec.Name - is set to OK&quot;&lt;/span&gt;)      }      &lt;span class=&quot;hljs-comment&quot;&gt;// update the status with client ------------&amp;gt; Only status will be updated&lt;/span&gt;      &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := r.Status().Update(ctx, instance); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {             log.Log.Info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Error while reading the object&quot;&lt;/span&gt;)             &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{},client.IgnoreNotFound(err)      }      &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ctrl.Result{}, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-for-status-change&quot;&gt;Output for status change&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Stop the operator if it was deployed in local cluster.&lt;/li&gt;&lt;li&gt;Delete the Custom Resource if it was deployed to local cluster&lt;/li&gt;&lt;li&gt;Deploy the operator to local cluster using &lt;code&gt;make generate install run&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Deploy the custom resource yaml manifest to the local cluster using &lt;code&gt;kubectl apply -f config/samples/&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;With&lt;code&gt;kubectl get greet/greet-sample -w&lt;/code&gt; command we can monitor the resource status.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/fbb3b88b-fd7a-4d2b-9bb4-36d4f3976e7d&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-points-that-where-not-covered&quot;&gt;Points that where not covered&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Deploying the operator in actual cluster by creating an image.&lt;/li&gt;&lt;li&gt;We can package the CRDs to helm and deploy it via helm CLI&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Automate repetitive tasks using Shell script in Git Bash]]></title><description><![CDATA[mvn and kubectl command in script, which is configured in git bash alias.]]></description><link>https://thirumurthi.hashnode.dev/automate-repetitive-tasks-using-shell-script-in-git-bash</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/automate-repetitive-tasks-using-shell-script-in-git-bash</guid><category><![CDATA[shell]]></category><category><![CDATA[shell script]]></category><category><![CDATA[gitbash]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 10 Jun 2023 22:42:02 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h1 id=&quot;heading-automate-repetitive-tasks-using-shell-scripts&quot;&gt;Automate repetitive tasks using shell scripts&lt;/h1&gt;&lt;p&gt;In day to day application development especially building Microservice architecture based application using Spring Boot and  Kubernetes, during development we tend to build artifacts and images multiple times for validating the changes.&lt;/p&gt;&lt;p&gt;In this blog have detail how to automate day to day development tasks like using &lt;code&gt;mvn&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; commands, both the commands configured in the Git Bash as alias in the &lt;code&gt;.bashrc&lt;/code&gt; file. Demonstrated how to run the commands in bash terminal by passing arguments.&lt;/p&gt;&lt;h2 id=&quot;heading-prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Shell scripting&lt;/li&gt;&lt;li&gt;Kind CLI installed (Docker Desktop)&lt;/li&gt;&lt;li&gt;Git Bash Installed&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-automate-mvn-command-as-a-alias-in-git-bash&quot;&gt;Automate mvn command as a alias in Git Bash&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To set an alias command for maven command &lt;ul&gt;&lt;li&gt;Add below command in &lt;code&gt;$HOME/.bashrc&lt;/code&gt; file in windows.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;alias runMvn=&lt;span class=&quot;hljs-string&quot;&gt;&apos;mvnFunc(){ POMFILE=&quot;pom.xml&quot;; if [ -f &quot;$POMFILE&quot; ]; then mvn &quot;$@&quot; clean install; else echo &quot;$POMFILE not found&quot;; fi; unset -f mvnFunc; }; mvnFunc&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;If the Git Bash is already opened, to apply the changes to reflect on the open shell issue &lt;code&gt;$ source ~/.bashrc&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;About the above code,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Defines a simple shell function, which checks is the pom.xml file exist in the current directory.&lt;/li&gt;&lt;li&gt;The usage of &quot;$@&quot; is to use the argument in the mvn command passed as argment.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-command-usage-in-git-bash&quot;&gt;Command usage in Git Bash&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Executing the alias command (without any argument) like below will run &lt;code&gt;mvn clean install&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ runMvn&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Executing alias command (with argument -DskipTest) like below will execute &lt;code&gt;mvn -DskipTests clean install&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ runMvn -DskipTests&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-automate-kubectl-create-and-delete-resource-from-yaml-file&quot;&gt;Automate kubectl create and delete resource from yaml file&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To automate the kubectl apply and delete resources we create a simple shell script.&lt;/li&gt;&lt;li&gt;The shell script will be configured in the &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;alias runK8SScript=&lt;span class=&quot;hljs-string&quot;&gt;&apos;kubeFunc(){ TMPPWD=$(pwd); cd /c/shellScript/; sh runK8SScript.sh &quot;$@&quot; ; cd $TMPPWD; unset -f kubeFunc; }; kubeFunc&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create a Script (.sh) file named &lt;code&gt;runK8SScript.sh&lt;/code&gt; with the below content.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below script can be extended say if we have mulitple yaml file we can utilize it.&lt;/li&gt;&lt;li&gt;Likewise we can use helm to deploy charts as well.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Logic in below script is self explanatory, script uses &lt;code&gt;getopts&lt;/code&gt;, to get user option based on which the &lt;code&gt;kubectl apply&lt;/code&gt; and &lt;code&gt;kubectl delete&lt;/code&gt; command will be executed.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;#!&lt;span class=&quot;hljs-regexp&quot;&gt;/usr/&lt;/span&gt;bin/env bashACTION=handleResource(){  INPUT_ACTION=$&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  CONTEXT=$&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;  MANIFEST_PATH=$&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  MANIFEST_FILE=$&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;  echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;[DEBUG] Executing .. kubectl --context $CONTEXT $INPUT_ACTION -f $MANIFEST_PATH$MANIFEST_FILE&quot;&lt;/span&gt;  # &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; namespace not provied within the manifest   # pass it to &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;variable&lt;/span&gt;  &lt;span class=&quot;hljs-title&quot;&gt;kubectl&lt;/span&gt; --&lt;span class=&quot;hljs-title&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$CONTEXT&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$INPUT_ACTION&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$MANIFEST_PATH$MANIFEST_FILE&lt;/span&gt;}&lt;span class=&quot;hljs-title&quot;&gt;info&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) &lt;/span&gt;{ echo -e &lt;span class=&quot;hljs-string&quot;&gt;&quot;$0 -&amp;lt;option&amp;gt; &amp;lt;action&amp;gt; \nusage:&quot;&lt;/span&gt; &amp;amp;&amp;amp; grep &lt;span class=&quot;hljs-string&quot;&gt;&quot; .)\ #&quot;&lt;/span&gt; $&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; | sed &lt;span class=&quot;hljs-string&quot;&gt;&apos;s/)\ ##//g&apos;&lt;/span&gt; | sed &lt;span class=&quot;hljs-string&quot;&gt;&apos;s/\([cd] \)/-\1/g&apos;&lt;/span&gt;;}&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; getopts &lt;span class=&quot;hljs-string&quot;&gt;&quot;:c:d:&quot;&lt;/span&gt; option; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; $option &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;    c) ## create      echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;option provided $OPTARG&quot;&lt;/span&gt;      ACTION=&lt;span class=&quot;hljs-string&quot;&gt;&quot;C&quot;&lt;/span&gt;      ;;    d) ## &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;      echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;option provided $OPTARG&quot;&lt;/span&gt;      ACTION=&lt;span class=&quot;hljs-string&quot;&gt;&quot;D&quot;&lt;/span&gt;      ;;    *)        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;not correct usage, use &quot;&lt;/span&gt;       info;       exit &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;  esacdone&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then   echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;other available options&quot;&lt;/span&gt;  infofi# using kind and the cluster context is definedCONTEXT_TO_DEPLOY=&lt;span class=&quot;hljs-string&quot;&gt;&quot;kind-demo1&quot;&lt;/span&gt;# use / at the endMANIFEST_FOLDER=&lt;span class=&quot;hljs-string&quot;&gt;&quot;/c/shellScript/manifest/&quot;&lt;/span&gt;#yaml fileMANIFEST_FILE_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;nginxDeploy.yaml&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;C&quot;&lt;/span&gt; || -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then    SKIP=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;    read -p &lt;span class=&quot;hljs-string&quot;&gt;&quot;Do you want to create resource (y/n)? - &quot;&lt;/span&gt; input    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; &amp;amp;&amp;amp; !( &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;yes&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;YES&quot;&lt;/span&gt; ) ]]; then        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Resource creation ignored&quot;&lt;/span&gt;       SKIP=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    fi    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (( $SKIP == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; )); then       echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating resources&quot;&lt;/span&gt;      handleResource &lt;span class=&quot;hljs-string&quot;&gt;&quot;apply&quot;&lt;/span&gt; $CONTEXT_TO_DEPLOY $MANIFEST_FOLDER $MANIFEST_FILE_NAME    fifi&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;D&quot;&lt;/span&gt; || -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then     SKIP=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;    read -p &lt;span class=&quot;hljs-string&quot;&gt;&quot;Do you want to delete resource (y/n)? - &quot;&lt;/span&gt; input    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; &amp;amp;&amp;amp; !( &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;yes&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;YES&quot;&lt;/span&gt; ) ]]; then        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Resource deletion ignored&quot;&lt;/span&gt;       SKIP=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    fi    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (( $SKIP == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; )); then         echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deleting resource&quot;&lt;/span&gt;        handleResource &lt;span class=&quot;hljs-string&quot;&gt;&quot;delete&quot;&lt;/span&gt; $CONTEXT_TO_DEPLOY $MANIFEST_FOLDER $MANIFEST_FILE_NAME    fifi&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-usage-of-the-alias-command&quot;&gt;Usage of the alias command&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-no-argument&quot;&gt;Output with no argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/9068927b-fe43-47c0-8e43-17f33a769a73&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript -c create&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-create-argument&quot;&gt;Output with create argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/34ccaee5-e5f3-4d79-91ab-8facd62799eb&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript -d &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-delete-argument&quot;&gt;Output with delete argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4cedf531-d884-4b65-afb7-1c354468dab2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h1 id=&quot;heading-automate-repetitive-tasks-using-shell-scripts&quot;&gt;Automate repetitive tasks using shell scripts&lt;/h1&gt;&lt;p&gt;In day to day application development especially building Microservice architecture based application using Spring Boot and  Kubernetes, during development we tend to build artifacts and images multiple times for validating the changes.&lt;/p&gt;&lt;p&gt;In this blog have detail how to automate day to day development tasks like using &lt;code&gt;mvn&lt;/code&gt; and &lt;code&gt;kubectl&lt;/code&gt; commands, both the commands configured in the Git Bash as alias in the &lt;code&gt;.bashrc&lt;/code&gt; file. Demonstrated how to run the commands in bash terminal by passing arguments.&lt;/p&gt;&lt;h2 id=&quot;heading-prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Shell scripting&lt;/li&gt;&lt;li&gt;Kind CLI installed (Docker Desktop)&lt;/li&gt;&lt;li&gt;Git Bash Installed&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-automate-mvn-command-as-a-alias-in-git-bash&quot;&gt;Automate mvn command as a alias in Git Bash&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To set an alias command for maven command &lt;ul&gt;&lt;li&gt;Add below command in &lt;code&gt;$HOME/.bashrc&lt;/code&gt; file in windows.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;alias runMvn=&lt;span class=&quot;hljs-string&quot;&gt;&apos;mvnFunc(){ POMFILE=&quot;pom.xml&quot;; if [ -f &quot;$POMFILE&quot; ]; then mvn &quot;$@&quot; clean install; else echo &quot;$POMFILE not found&quot;; fi; unset -f mvnFunc; }; mvnFunc&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;If the Git Bash is already opened, to apply the changes to reflect on the open shell issue &lt;code&gt;$ source ~/.bashrc&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;About the above code,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Defines a simple shell function, which checks is the pom.xml file exist in the current directory.&lt;/li&gt;&lt;li&gt;The usage of &quot;$@&quot; is to use the argument in the mvn command passed as argment.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-command-usage-in-git-bash&quot;&gt;Command usage in Git Bash&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Executing the alias command (without any argument) like below will run &lt;code&gt;mvn clean install&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ runMvn&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;Executing alias command (with argument -DskipTest) like below will execute &lt;code&gt;mvn -DskipTests clean install&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ runMvn -DskipTests&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-automate-kubectl-create-and-delete-resource-from-yaml-file&quot;&gt;Automate kubectl create and delete resource from yaml file&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;To automate the kubectl apply and delete resources we create a simple shell script.&lt;/li&gt;&lt;li&gt;The shell script will be configured in the &lt;code&gt;~/.bashrc&lt;/code&gt;, &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;alias runK8SScript=&lt;span class=&quot;hljs-string&quot;&gt;&apos;kubeFunc(){ TMPPWD=$(pwd); cd /c/shellScript/; sh runK8SScript.sh &quot;$@&quot; ; cd $TMPPWD; unset -f kubeFunc; }; kubeFunc&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Create a Script (.sh) file named &lt;code&gt;runK8SScript.sh&lt;/code&gt; with the below content.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below script can be extended say if we have mulitple yaml file we can utilize it.&lt;/li&gt;&lt;li&gt;Likewise we can use helm to deploy charts as well.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Logic in below script is self explanatory, script uses &lt;code&gt;getopts&lt;/code&gt;, to get user option based on which the &lt;code&gt;kubectl apply&lt;/code&gt; and &lt;code&gt;kubectl delete&lt;/code&gt; command will be executed.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;#!&lt;span class=&quot;hljs-regexp&quot;&gt;/usr/&lt;/span&gt;bin/env bashACTION=handleResource(){  INPUT_ACTION=$&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  CONTEXT=$&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;  MANIFEST_PATH=$&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  MANIFEST_FILE=$&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;  echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;[DEBUG] Executing .. kubectl --context $CONTEXT $INPUT_ACTION -f $MANIFEST_PATH$MANIFEST_FILE&quot;&lt;/span&gt;  # &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; namespace not provied within the manifest   # pass it to &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;variable&lt;/span&gt;  &lt;span class=&quot;hljs-title&quot;&gt;kubectl&lt;/span&gt; --&lt;span class=&quot;hljs-title&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$CONTEXT&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$INPUT_ACTION&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;$MANIFEST_PATH$MANIFEST_FILE&lt;/span&gt;}&lt;span class=&quot;hljs-title&quot;&gt;info&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) &lt;/span&gt;{ echo -e &lt;span class=&quot;hljs-string&quot;&gt;&quot;$0 -&amp;lt;option&amp;gt; &amp;lt;action&amp;gt; \nusage:&quot;&lt;/span&gt; &amp;amp;&amp;amp; grep &lt;span class=&quot;hljs-string&quot;&gt;&quot; .)\ #&quot;&lt;/span&gt; $&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; | sed &lt;span class=&quot;hljs-string&quot;&gt;&apos;s/)\ ##//g&apos;&lt;/span&gt; | sed &lt;span class=&quot;hljs-string&quot;&gt;&apos;s/\([cd] \)/-\1/g&apos;&lt;/span&gt;;}&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; getopts &lt;span class=&quot;hljs-string&quot;&gt;&quot;:c:d:&quot;&lt;/span&gt; option; &lt;span class=&quot;hljs-keyword&quot;&gt;do&lt;/span&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; $option &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;    c) ## create      echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;option provided $OPTARG&quot;&lt;/span&gt;      ACTION=&lt;span class=&quot;hljs-string&quot;&gt;&quot;C&quot;&lt;/span&gt;      ;;    d) ## &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;      echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;option provided $OPTARG&quot;&lt;/span&gt;      ACTION=&lt;span class=&quot;hljs-string&quot;&gt;&quot;D&quot;&lt;/span&gt;      ;;    *)        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;not correct usage, use &quot;&lt;/span&gt;       info;       exit &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;  esacdone&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then   echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;other available options&quot;&lt;/span&gt;  infofi# using kind and the cluster context is definedCONTEXT_TO_DEPLOY=&lt;span class=&quot;hljs-string&quot;&gt;&quot;kind-demo1&quot;&lt;/span&gt;# use / at the endMANIFEST_FOLDER=&lt;span class=&quot;hljs-string&quot;&gt;&quot;/c/shellScript/manifest/&quot;&lt;/span&gt;#yaml fileMANIFEST_FILE_NAME=&lt;span class=&quot;hljs-string&quot;&gt;&quot;nginxDeploy.yaml&quot;&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;C&quot;&lt;/span&gt; || -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then    SKIP=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;    read -p &lt;span class=&quot;hljs-string&quot;&gt;&quot;Do you want to create resource (y/n)? - &quot;&lt;/span&gt; input    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; &amp;amp;&amp;amp; !( &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;yes&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;YES&quot;&lt;/span&gt; ) ]]; then        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Resource creation ignored&quot;&lt;/span&gt;       SKIP=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    fi    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (( $SKIP == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; )); then       echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Creating resources&quot;&lt;/span&gt;      handleResource &lt;span class=&quot;hljs-string&quot;&gt;&quot;apply&quot;&lt;/span&gt; $CONTEXT_TO_DEPLOY $MANIFEST_FOLDER $MANIFEST_FILE_NAME    fifi&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;D&quot;&lt;/span&gt; || -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$ACTION&quot;&lt;/span&gt; ]]; then     SKIP=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;    read -p &lt;span class=&quot;hljs-string&quot;&gt;&quot;Do you want to delete resource (y/n)? - &quot;&lt;/span&gt; input    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; [[ ! -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; &amp;amp;&amp;amp; !( &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;Y&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;yes&quot;&lt;/span&gt; || &lt;span class=&quot;hljs-string&quot;&gt;&quot;$input&quot;&lt;/span&gt; == &lt;span class=&quot;hljs-string&quot;&gt;&quot;YES&quot;&lt;/span&gt; ) ]]; then        echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Resource deletion ignored&quot;&lt;/span&gt;       SKIP=&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    fi    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (( $SKIP == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; )); then         echo &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deleting resource&quot;&lt;/span&gt;        handleResource &lt;span class=&quot;hljs-string&quot;&gt;&quot;delete&quot;&lt;/span&gt; $CONTEXT_TO_DEPLOY $MANIFEST_FOLDER $MANIFEST_FILE_NAME    fifi&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-usage-of-the-alias-command&quot;&gt;Usage of the alias command&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-no-argument&quot;&gt;Output with no argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/9068927b-fe43-47c0-8e43-17f33a769a73&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript -c create&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-create-argument&quot;&gt;Output with create argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/34ccaee5-e5f3-4d79-91ab-8facd62799eb&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ runK8SScript -d &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-with-delete-argument&quot;&gt;Output with delete argument&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/4cedf531-d884-4b65-afb7-1c354468dab2&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Develop REST API with Javalin and running app using JBang]]></title><description><![CDATA[Build RestAPI with Javalin framework and running it using JBang]]></description><link>https://thirumurthi.hashnode.dev/develop-rest-api-with-javalin-and-running-app-using-jbang</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/develop-rest-api-with-javalin-and-running-app-using-jbang</guid><category><![CDATA[jbang]]></category><category><![CDATA[REST API]]></category><category><![CDATA[javalin]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 27 May 2023 05:34:46 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-rest-api-with-javalin-and-jbang&quot;&gt;REST API with Javalin and JBang&lt;/h2&gt;&lt;p&gt;In this blog we will create a REST API using Javalin and running it using JBang.&lt;/p&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;JBang CLI installed&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-javalin&quot;&gt;What is Javalin?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Javalin is a very lightweight web framework for Java&lt;/li&gt;&lt;li&gt;Javalin comes with a Jetty embedded server&lt;/li&gt;&lt;li&gt;Very easy to build REST API&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For more details refer the &lt;a target=&quot;_blank&quot; href=&quot;https://javalin.io/documentation&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-jbang&quot;&gt;JBang&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;With JBang we can run Java class as a script.&lt;/li&gt;&lt;li&gt;With the JBang here there is no specific Java project structure created by Maven or Gradle.&lt;/li&gt;&lt;li&gt;Like Shell script she bang, we do have specify JBang in the Java file.&lt;/li&gt;&lt;li&gt;The dependency are provided at the top of the file within the java comment style.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-possible-usage&quot;&gt;Possible usage&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Since we are not using the Maven or Gradle style project structure, this can be used for spinning up the REST API as a backend with mocked JSON payload and used for building consumer application.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-java-code&quot;&gt;Java code&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;With the Javalin library we initally configure the app&lt;/li&gt;&lt;li&gt;In this class the example of GET and POST request is demonstrated&lt;/li&gt;&lt;li&gt;Also we read a json file and serve the data in JSON format&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$0&quot; : exit $?&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS io.javalin:javalin:5.5.0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.projectlombok:lombok:1.18.26&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-simple:2.0.7&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS commons-io:commons-io:2.11.0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS com.fasterxml.jackson.core:jackson-databind:2.15.1&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.javalin.Javalin;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.File;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.FileInputStream;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.InputStream;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.IOException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.commons.io.IOExceptionList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.commons.io.IOUtils;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.nio.charset.StandardCharsets;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.nio.file.Paths;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.ArrayList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.HashMap;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.type.TypeReference;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RESTApi&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String fileName =&lt;span class=&quot;hljs-string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; items = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt;&lt;/span&gt;{        loadItems();        &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; app = Javalin.create(config -&amp;gt; {            config.plugins            .enableCors(cors -&amp;gt; cors.add(host -&amp;gt; host.allowHost(&lt;span class=&quot;hljs-string&quot;&gt;&quot;localhost&quot;&lt;/span&gt;)));        })        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/data&quot;&lt;/span&gt;,ctx -&amp;gt; ctx.json(readDataFromFile(fileName)))        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/hello/{name}&quot;&lt;/span&gt;,ctx -&amp;gt; ctx.result(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Welcome &quot;&lt;/span&gt;+ctx.pathParam(&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;)))        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/items&quot;&lt;/span&gt;,ctx-&amp;gt; ctx.json(getItems()))        .post(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/item&quot;&lt;/span&gt;, ctx -&amp;gt; {                    ctx.status(&lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt;);                    addItem(ctx.bodyAsClass(Items.class));})        .start(&lt;span class=&quot;hljs-number&quot;&gt;7070&lt;/span&gt;);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; Items &lt;span class=&quot;hljs-title&quot;&gt;addItem&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Items item)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;input data {}&quot;&lt;/span&gt;,item);        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(item != &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;){            items.add(item);        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; item;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getItems&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;loadItems&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        Items computer = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;);        Items keyBoard = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;);        Items mouse = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;);        items.add(computer);        items.add(keyBoard);        items.add(mouse);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items;            }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;readDataFromFile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String fileName)&lt;/span&gt;&lt;/span&gt;{        Map&amp;lt;String, Object&amp;gt; valueMap = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; HashMap&amp;lt;&amp;gt;();        String data = &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;{            ObjectMapper mapper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();            valueMap = mapper.readValue(Paths.get(fileName).toFile(),                                 &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; TypeReference&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt;(){});            data = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper().writeValueAsString(valueMap);        }&lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt;(Exception ex){            ex.printStackTrace();        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; data;    }}&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Items&lt;/span&gt;&lt;/span&gt;{    String product = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; quantity =&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-sample-data-json-file&quot;&gt;Sample data json file&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;companyName&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;xyzABC&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;address&quot;&lt;/span&gt; : {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;addressLine1&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Street&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;addressLine2&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Apt Number&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;city&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;City&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;zipCode&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;123456&quot;&lt;/span&gt;    },    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;departments&quot;&lt;/span&gt;: [        {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Accounts&quot;&lt;/span&gt;,         &lt;span class=&quot;hljs-attr&quot;&gt;&quot;employees&quot;&lt;/span&gt;:[            {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;employee1&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt;},            {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;employee2&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;2&quot;&lt;/span&gt;}         ]        }    ] }&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/hello/Javalin&lt;/span&gt;Welcome Javalin&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;List the loaded items&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/items&lt;/span&gt;[{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;}]&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;List of added item above&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/items&lt;/span&gt;[{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Phone&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;}]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Add item&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl -X POST -d &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;product&quot;:&quot;Phone&quot;,&quot;quantity&quot;:&quot;2&quot;}&apos;&lt;/span&gt; http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/item&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Javalin startup logs&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/8e486b66-50cf-4c0d-b437-725c9e798212&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-rest-api-with-javalin-and-jbang&quot;&gt;REST API with Javalin and JBang&lt;/h2&gt;&lt;p&gt;In this blog we will create a REST API using Javalin and running it using JBang.&lt;/p&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;JBang CLI installed&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-javalin&quot;&gt;What is Javalin?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Javalin is a very lightweight web framework for Java&lt;/li&gt;&lt;li&gt;Javalin comes with a Jetty embedded server&lt;/li&gt;&lt;li&gt;Very easy to build REST API&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For more details refer the &lt;a target=&quot;_blank&quot; href=&quot;https://javalin.io/documentation&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-jbang&quot;&gt;JBang&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;With JBang we can run Java class as a script.&lt;/li&gt;&lt;li&gt;With the JBang here there is no specific Java project structure created by Maven or Gradle.&lt;/li&gt;&lt;li&gt;Like Shell script she bang, we do have specify JBang in the Java file.&lt;/li&gt;&lt;li&gt;The dependency are provided at the top of the file within the java comment style.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-possible-usage&quot;&gt;Possible usage&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Since we are not using the Maven or Gradle style project structure, this can be used for spinning up the REST API as a backend with mocked JSON payload and used for building consumer application.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-java-code&quot;&gt;Java code&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;With the Javalin library we initally configure the app&lt;/li&gt;&lt;li&gt;In this class the example of GET and POST request is demonstrated&lt;/li&gt;&lt;li&gt;Also we read a json file and serve the data in JSON format&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$0&quot; : exit $?&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS io.javalin:javalin:5.5.0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.projectlombok:lombok:1.18.26&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-simple:2.0.7&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS commons-io:commons-io:2.11.0&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS com.fasterxml.jackson.core:jackson-databind:2.15.1&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.javalin.Javalin;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.File;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.FileInputStream;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.InputStream;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.IOException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.commons.io.IOExceptionList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.commons.io.IOUtils;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.nio.charset.StandardCharsets;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.nio.file.Paths;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.ArrayList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.HashMap;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.type.TypeReference;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RESTApi&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String fileName =&lt;span class=&quot;hljs-string&quot;&gt;&quot;data.json&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; items = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt;&lt;/span&gt;{        loadItems();        &lt;span class=&quot;hljs-keyword&quot;&gt;var&lt;/span&gt; app = Javalin.create(config -&amp;gt; {            config.plugins            .enableCors(cors -&amp;gt; cors.add(host -&amp;gt; host.allowHost(&lt;span class=&quot;hljs-string&quot;&gt;&quot;localhost&quot;&lt;/span&gt;)));        })        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/data&quot;&lt;/span&gt;,ctx -&amp;gt; ctx.json(readDataFromFile(fileName)))        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/hello/{name}&quot;&lt;/span&gt;,ctx -&amp;gt; ctx.result(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Welcome &quot;&lt;/span&gt;+ctx.pathParam(&lt;span class=&quot;hljs-string&quot;&gt;&quot;name&quot;&lt;/span&gt;)))        .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/items&quot;&lt;/span&gt;,ctx-&amp;gt; ctx.json(getItems()))        .post(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/item&quot;&lt;/span&gt;, ctx -&amp;gt; {                    ctx.status(&lt;span class=&quot;hljs-number&quot;&gt;200&lt;/span&gt;);                    addItem(ctx.bodyAsClass(Items.class));})        .start(&lt;span class=&quot;hljs-number&quot;&gt;7070&lt;/span&gt;);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; Items &lt;span class=&quot;hljs-title&quot;&gt;addItem&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Items item)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;input data {}&quot;&lt;/span&gt;,item);        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(item != &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;){            items.add(item);        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; item;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getItems&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Items&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;loadItems&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        Items computer = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;);        Items keyBoard = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;);        Items mouse = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Items(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;);        items.add(computer);        items.add(keyBoard);        items.add(mouse);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items;            }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;readDataFromFile&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String fileName)&lt;/span&gt;&lt;/span&gt;{        Map&amp;lt;String, Object&amp;gt; valueMap = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; HashMap&amp;lt;&amp;gt;();        String data = &lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;{            ObjectMapper mapper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();            valueMap = mapper.readValue(Paths.get(fileName).toFile(),                                 &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; TypeReference&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt;(){});            data = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper().writeValueAsString(valueMap);        }&lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt;(Exception ex){            ex.printStackTrace();        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; data;    }}&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Items&lt;/span&gt;&lt;/span&gt;{    String product = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;    &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; quantity =&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-sample-data-json-file&quot;&gt;Sample data json file&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;companyName&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;xyzABC&quot;&lt;/span&gt;,    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;address&quot;&lt;/span&gt; : {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;addressLine1&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Street&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;addressLine2&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Apt Number&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;city&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;City&quot;&lt;/span&gt;,        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;zipCode&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;123456&quot;&lt;/span&gt;    },    &lt;span class=&quot;hljs-attr&quot;&gt;&quot;departments&quot;&lt;/span&gt;: [        {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Accounts&quot;&lt;/span&gt;,         &lt;span class=&quot;hljs-attr&quot;&gt;&quot;employees&quot;&lt;/span&gt;:[            {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;employee1&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt;},            {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;employee2&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-attr&quot;&gt;&quot;id&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;2&quot;&lt;/span&gt;}         ]        }    ] }&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/hello/Javalin&lt;/span&gt;Welcome Javalin&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;List the loaded items&lt;/p&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/items&lt;/span&gt;[{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;}]&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;List of added item above&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/items&lt;/span&gt;[{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Computer&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;KeyBoard&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Mouse&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;},{&lt;span class=&quot;hljs-string&quot;&gt;&quot;product&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Phone&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;quantity&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;}]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Add item&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ curl -X POST -d &lt;span class=&quot;hljs-string&quot;&gt;&apos;{&quot;product&quot;:&quot;Phone&quot;,&quot;quantity&quot;:&quot;2&quot;}&apos;&lt;/span&gt; http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:7070/item&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Javalin startup logs&lt;img src=&quot;https://github.com/thirumurthis/Learnings/assets/6425536/8e486b66-50cf-4c0d-b437-725c9e798212&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Spring Boot NullKeySerializer - Handle Kafka payload with null keys]]></title><description><![CDATA[This article explains how to extend Spring Boot default JSON serializer to implement NullKeySerializer to serialize payload with Maps that has null keys.]]></description><link>https://thirumurthi.hashnode.dev/spring-boot-nullkeyserializer-handle-kafka-payload-with-null-keys</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/spring-boot-nullkeyserializer-handle-kafka-payload-with-null-keys</guid><category><![CDATA[Springboot]]></category><category><![CDATA[kafka]]></category><category><![CDATA[serialization]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Mon, 27 Mar 2023 02:56:45 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-spring-boot-nullkeyserializer-handle-kafka-payload-with-null-keys&quot;&gt;Spring Boot NullKeySerializer - Handle Kafka payload with null keys&lt;/h2&gt;&lt;p&gt;In this article detailed how the default Spring Boot Kafka JSON Serializer can be extended with NullKeySerializer implementation to handle payload when message with map contains null keys. The default JSON Serializer throws exception when payload message to Kafka topic with null keys.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kafka cluster running in 9092 port&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In Message Oriented Middleware (MOM) based distributed application, the payload messages communicate between system over network. There are scenarios where the payload may contain maps with null key. As mentioned above default Spring Boot JSON serializer will throw exception and exception message looks like below.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Servlet.service() &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; servlet [dispatcherServlet] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; context &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; path [] threw exception [Request processing failed: org.apache.kafka.common.errors.SerializationException: Can&lt;span class=&quot;hljs-string&quot;&gt;&apos;t serialize data [MapInputData(messageInfo={null=the key is null explicitly, 1=the key is one non-null}, date=Sun Mar 26 14:40:29 PDT 2023)] for topic [input-topic]] with root cause&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-brief-steps-on-how-to-handle-null-key-in-the-payload&quot;&gt;Brief steps on how to handle null key in the payload:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;First  the extend the default spring JSON serializer class &lt;code&gt;org.springframework.kafka.support.serializer.JsonSerializer&lt;/code&gt; and implement the NullKeySerializer.&lt;ul&gt;&lt;li&gt;Next, the extended custom serializer class should be configured in the spring kafka producer &lt;code&gt;spring.kafka.producer.value-serializer&lt;/code&gt; property.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-implementation&quot;&gt;Code implementation&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The complete spring custom serialzier code that implements NullKeySeralizer:&lt;ul&gt;&lt;li&gt;In this class the Jackson ObjectMapper is created and configured the implemented NullKeySerializer. The ObjectMapper is also configured to load additional modules, to handle the Date in the payload.&lt;ul&gt;&lt;li&gt;The ObjectMapper is passed to the Spring Boot default JsonSerializer.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonGenerator;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.SerializationFeature;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.SerializerProvider;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ser.std.StdSerializer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.util.StdDateFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.support.serializer.JsonSerializer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.IOException;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomKafkaJsonSerializer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JsonSerializer&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Object&lt;/span&gt;&amp;gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomKafkaJsonSerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(customizedObjectMapper());    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; ObjectMapper &lt;span class=&quot;hljs-title&quot;&gt;customizedObjectMapper&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        ObjectMapper objMapper= &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();        &lt;span class=&quot;hljs-comment&quot;&gt;//if the pay load include timestamps we need to use modules&lt;/span&gt;        objMapper.findAndRegisterModules();        objMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);        objMapper.setDateFormat(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; StdDateFormat().withColonInTimeZone(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;));        objMapper.getSerializerProvider().setNullKeySerializer(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; NullKeySerializer());        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; objMapper;    }    &lt;span class=&quot;hljs-comment&quot;&gt;// Null key serializer&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;StdSerializer&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Object&lt;/span&gt;&amp;gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{            &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;);        }        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Class&amp;lt;Object&amp;gt; t)&lt;/span&gt; &lt;/span&gt;{            &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(t);        }        &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Object nullKey, JsonGenerator generator, SerializerProvider unused)&lt;/span&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException &lt;/span&gt;{            generator.writeFieldName(&lt;span class=&quot;hljs-string&quot;&gt;&quot;null&quot;&lt;/span&gt;);        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Spring Boot application entry point&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;KafkaApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(KafkaApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Controller code, which creates the payload message mocking Map with null key.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.model.MapInputData;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.service.ProducerService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Date;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.HashMap;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SimpleController&lt;/span&gt; &lt;/span&gt;{    ProducerService producerService;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SimpleController&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ProducerService producerService)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.producerService=producerService;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/send&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        MapInputData mapInputData = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; MapInputData();        Map&amp;lt;String,Object&amp;gt; input = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; HashMap&amp;lt;&amp;gt;();        input.put(&lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;the key is null explicitly&quot;&lt;/span&gt;);        input.put(&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;the key is one non-null&quot;&lt;/span&gt;);        mapInputData.setDate(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Date());        mapInputData.setMessageInfo(input);        producerService.sendMessage(mapInputData);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Payload POJO definition&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka.model;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.annotation.JsonTypeInfo;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Date;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@JsonTypeInfo(         use = JsonTypeInfo.Id.NAME,        property = &quot;type&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;MapInputData&lt;/span&gt; &lt;/span&gt;{    Map&amp;lt;String, Object&amp;gt; messageInfo;    Date date;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Producer service, that sends the message to Kafka cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka.service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.text.MessageFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.model.MapInputData;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.core.KafkaTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.support.KafkaHeaders;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.messaging.Message;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.messaging.support.MessageBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${spring.kafka.topic:demo-topic}&quot;)&lt;/span&gt;    String topicName;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; KafkaTemplate&amp;lt;String,Object&amp;gt; kafkaTemplate;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(KafkaTemplate&amp;lt;String,Object&amp;gt; kafkaTemplate)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.kafkaTemplate = kafkaTemplate;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(MapInputData messageModel)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sending message from producer - {}&quot;&lt;/span&gt;,messageModel);        Message message = constructMessage(messageModel);        kafkaTemplate.send(message);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageFormat.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Message Sent from Producer - {0}&quot;&lt;/span&gt;,message);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Message &lt;span class=&quot;hljs-title&quot;&gt;constructMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(MapInputData messageModel)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageBuilder.withPayload(messageModel)                .setHeader(KafkaHeaders.TOPIC,topicName)                .setHeader(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reason&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;for-Local-validation&quot;&lt;/span&gt;)                .build();    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Application configuration &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;application:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;service-1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;topic:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;input-topic&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;consumer:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap-servers:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost:9092&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;group-id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;input-group-id&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;auto-offset-reset:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;earliest&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key-deserializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;value-deserializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;producer:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap-servers:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost:9092&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key-serializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringSerializer&lt;/span&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;# The custom null serializer added to configuration&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;value-serializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;com.example.kafka.CustomKafkaJsonSerial&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With the above spring configuration the producer can serialize the payload with null key and send message over wire to Kafka broker.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;pom.xml with dependencies&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.example&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-spring-boot-nullkeyserializer-handle-kafka-payload-with-null-keys&quot;&gt;Spring Boot NullKeySerializer - Handle Kafka payload with null keys&lt;/h2&gt;&lt;p&gt;In this article detailed how the default Spring Boot Kafka JSON Serializer can be extended with NullKeySerializer implementation to handle payload when message with map contains null keys. The default JSON Serializer throws exception when payload message to Kafka topic with null keys.&lt;/p&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kafka cluster running in 9092 port&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In Message Oriented Middleware (MOM) based distributed application, the payload messages communicate between system over network. There are scenarios where the payload may contain maps with null key. As mentioned above default Spring Boot JSON serializer will throw exception and exception message looks like below.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;Servlet.service() &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; servlet [dispatcherServlet] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; context &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; path [] threw exception [Request processing failed: org.apache.kafka.common.errors.SerializationException: Can&lt;span class=&quot;hljs-string&quot;&gt;&apos;t serialize data [MapInputData(messageInfo={null=the key is null explicitly, 1=the key is one non-null}, date=Sun Mar 26 14:40:29 PDT 2023)] for topic [input-topic]] with root cause&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-brief-steps-on-how-to-handle-null-key-in-the-payload&quot;&gt;Brief steps on how to handle null key in the payload:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;First  the extend the default spring JSON serializer class &lt;code&gt;org.springframework.kafka.support.serializer.JsonSerializer&lt;/code&gt; and implement the NullKeySerializer.&lt;ul&gt;&lt;li&gt;Next, the extended custom serializer class should be configured in the spring kafka producer &lt;code&gt;spring.kafka.producer.value-serializer&lt;/code&gt; property.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-implementation&quot;&gt;Code implementation&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The complete spring custom serialzier code that implements NullKeySeralizer:&lt;ul&gt;&lt;li&gt;In this class the Jackson ObjectMapper is created and configured the implemented NullKeySerializer. The ObjectMapper is also configured to load additional modules, to handle the Date in the payload.&lt;ul&gt;&lt;li&gt;The ObjectMapper is passed to the Spring Boot default JsonSerializer.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonGenerator;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.SerializationFeature;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.SerializerProvider;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ser.std.StdSerializer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.util.StdDateFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.support.serializer.JsonSerializer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.IOException;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomKafkaJsonSerializer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JsonSerializer&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Object&lt;/span&gt;&amp;gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomKafkaJsonSerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(customizedObjectMapper());    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; ObjectMapper &lt;span class=&quot;hljs-title&quot;&gt;customizedObjectMapper&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        ObjectMapper objMapper= &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();        &lt;span class=&quot;hljs-comment&quot;&gt;//if the pay load include timestamps we need to use modules&lt;/span&gt;        objMapper.findAndRegisterModules();        objMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);        objMapper.setDateFormat(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; StdDateFormat().withColonInTimeZone(&lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;));        objMapper.getSerializerProvider().setNullKeySerializer(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; NullKeySerializer());        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; objMapper;    }    &lt;span class=&quot;hljs-comment&quot;&gt;// Null key serializer&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;StdSerializer&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;Object&lt;/span&gt;&amp;gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{            &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;);        }        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;NullKeySerializer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Class&amp;lt;Object&amp;gt; t)&lt;/span&gt; &lt;/span&gt;{            &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(t);        }        &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;        &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Object nullKey, JsonGenerator generator, SerializerProvider unused)&lt;/span&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException &lt;/span&gt;{            generator.writeFieldName(&lt;span class=&quot;hljs-string&quot;&gt;&quot;null&quot;&lt;/span&gt;);        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Spring Boot application entry point&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;KafkaApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(KafkaApplication.class, args);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Controller code, which creates the payload message mocking Map with null key.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.model.MapInputData;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.service.ProducerService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Date;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.HashMap;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SimpleController&lt;/span&gt; &lt;/span&gt;{    ProducerService producerService;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;SimpleController&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ProducerService producerService)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.producerService=producerService;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/send&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        MapInputData mapInputData = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; MapInputData();        Map&amp;lt;String,Object&amp;gt; input = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; HashMap&amp;lt;&amp;gt;();        input.put(&lt;span class=&quot;hljs-keyword&quot;&gt;null&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;the key is null explicitly&quot;&lt;/span&gt;);        input.put(&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;the key is one non-null&quot;&lt;/span&gt;);        mapInputData.setDate(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Date());        mapInputData.setMessageInfo(input);        producerService.sendMessage(mapInputData);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Payload POJO definition&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka.model;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.annotation.JsonTypeInfo;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Date;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@JsonTypeInfo(         use = JsonTypeInfo.Id.NAME,        property = &quot;type&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;MapInputData&lt;/span&gt; &lt;/span&gt;{    Map&amp;lt;String, Object&amp;gt; messageInfo;    Date date;}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Producer service, that sends the message to Kafka cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka.service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.text.MessageFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.kafka.model.MapInputData;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.core.KafkaTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.support.KafkaHeaders;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.messaging.Message;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.messaging.support.MessageBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${spring.kafka.topic:demo-topic}&quot;)&lt;/span&gt;    String topicName;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; KafkaTemplate&amp;lt;String,Object&amp;gt; kafkaTemplate;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(KafkaTemplate&amp;lt;String,Object&amp;gt; kafkaTemplate)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.kafkaTemplate = kafkaTemplate;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(MapInputData messageModel)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sending message from producer - {}&quot;&lt;/span&gt;,messageModel);        Message message = constructMessage(messageModel);        kafkaTemplate.send(message);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageFormat.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Message Sent from Producer - {0}&quot;&lt;/span&gt;,message);    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Message &lt;span class=&quot;hljs-title&quot;&gt;constructMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(MapInputData messageModel)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageBuilder.withPayload(messageModel)                .setHeader(KafkaHeaders.TOPIC,topicName)                .setHeader(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reason&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;for-Local-validation&quot;&lt;/span&gt;)                .build();    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Application configuration &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;application:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;service-1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;topic:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;input-topic&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;consumer:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap-servers:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost:9092&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;group-id:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;input-group-id&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;auto-offset-reset:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;earliest&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key-deserializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;value-deserializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringDeserializer&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;producer:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap-servers:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;localhost:9092&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key-serializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;org.apache.kafka.common.serialization.StringSerializer&lt;/span&gt;      &lt;span class=&quot;hljs-comment&quot;&gt;# The custom null serializer added to configuration&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;value-serializer:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;com.example.kafka.CustomKafkaJsonSerial&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;With the above spring configuration the producer can serialize the payload with null key and send message over wire to Kafka broker.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;pom.xml with dependencies&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.example&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Run Integration in Apache Camel-K]]></title><description><![CDATA[This blog explains the running integrations using Apache Camel-K, by installing Camel-k operator in KIND cluster using Kamel CLI and running an integration]]></description><link>https://thirumurthi.hashnode.dev/run-integration-in-apache-camel-k</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/run-integration-in-apache-camel-k</guid><category><![CDATA[kind]]></category><category><![CDATA[apache-camel]]></category><category><![CDATA[kamel]]></category><category><![CDATA[camel-k]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Thu, 09 Feb 2023 05:46:59 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-camel-k&quot;&gt;Camel-K&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Apache Camel K is a lightweight cloud-integration platform that runs natively on Kubernetes.&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this blog will show how to install Camel-K operator in Kubernetes (KIND) cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Have created a simple integration code (Java integration).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The integration code expose a REST endpoint using Camel component.&lt;/li&gt;&lt;li&gt;The message is passed as URL path variable.&lt;/li&gt;&lt;li&gt;The message is routed to &lt;code&gt;direct&lt;/code&gt; endpoint and transform with a constant string.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker Desktop (Docker daemon running).&lt;/li&gt;&lt;li&gt;Dockerhub account.&lt;/li&gt;&lt;li&gt;Kamel CLI installed.&lt;/li&gt;&lt;li&gt;KIND CLI installed.&lt;/li&gt;&lt;li&gt;Basic understanding on Kubernetes and Operator pattern.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-options-to-install-camel-k-operator&quot;&gt;Options to install Camel-K operator&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;There are different option to install Camel-K. Options are listed below, &lt;ul&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://artifacthub.io/packages/helm/camel-k/camel-k&quot;&gt;Helm charts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://operatorhub.io/operator/camel-k&quot;&gt;OperatorHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/installation.html&quot;&gt;Kamel CLI&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;In this blog the Camel-K operator is installed with &lt;strong&gt;Kamel CLI&lt;/strong&gt; in KIND cluster.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;During Camel-K installation we need to configure the docker registry (docker.io).In this blog have used Dockerhub, we can use private registry as well.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-install-kind-cluster-and-deploy-nginx-ingress-controller&quot;&gt;Install KIND cluster and deploy Nginx Ingress controller&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The ingress controller is used to access the REST endpoint from the host machine.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the KIND cluster configuration file which includes patch configuration for ingress controller, save this as &lt;code&gt;kamel-kind-cluster.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kubeadmConfigPatches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    kind: InitConfiguration    nodeRegistration:      kubeletExtraArgs:        node-labels: &quot;ingress-ready=true&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We need to use the above configuration in Kind CLI to create the cluster, the command usage is listed below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind create cluster --config kamel-kind-cluster.yaml --name kamel-ingress&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In order to apply the ingress controller configuration below command. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/docs/user/ingress/#ingress-nginx_&quot;&gt;kind documentation&lt;/a&gt; for more info.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-camel-k-operator-in-kind-cluster&quot;&gt;Install Camel-K operator in KIND cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install the Camel-K operator with Kamel CLI, we need to configure the docker registry (docker.io). For this first we need to create a secret in the cluster with the Docker credentials.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Creating a secret with the $HOME/.docker/config.json file directly didn&apos;t work for me. When running the integration, the logs indicated unauthorized access.&lt;/li&gt;&lt;li&gt;Below is the command to create secret from docker config file.&lt;pre&gt;&lt;code&gt;kubectl create secret generic regcred \ --&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-file=.dockerconfigjson=$HOME/.docker/config.json \ --type=kubernetes.io/dockerconfigjson&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-install-olm-in-the-cluster&quot;&gt;Install OLM in the cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;This is optional step. By installing the OLM (Operator Lifecycle Management)  we are not required to use the option &lt;code&gt;--olm=false&lt;/code&gt; in Kamel CLI during installation.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To install the OLM, run below command from Gitbash.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;curl -sL https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.23.1/install.sh | bash -s v0.23.1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To create the secret with the Docker credentials use below commands&lt;ul&gt;&lt;li&gt;Storing the Dockerhub credentials in the environment variable will help in case we need to automate the installation process.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; powershell use below command, to accessing environment variable we use $env:&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;env-key&lt;/span&gt;&amp;gt;&lt;/span&gt;kubectl -n default create secret docker-registry external-registry-secret --docker-username $env:DOCKER_USER --docker-password $env:DOCKER_PASS# from shell (like git bash) use below commandkubectl -n default create secret docker-registry external-registry-secret --docker-username $DOCKER_USER --docker-password $DOCKER_PASS&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below command will install the Camel-K operator in default namespace.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# the secret created above is passed &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; --registry-secret &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; commandkamel install -n &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; --registry docker.io --organization &amp;lt;organization-name&amp;gt; --registry-secret external-registry-secret --wait&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If OLM is not installed in the cluster (as mentioned above), in this case then we need to use &lt;code&gt;--olm=false&lt;/code&gt; in the command shown below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel install -n &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; --olm=&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; --registry docker.io --organization &amp;lt;organization-name&amp;gt; --registry-secret external-registry-secret --wait&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Camel-K operator installation takes sometime to install.Camel-K operator deploys as a pod, so to check the status of the pod in the default namespace use &lt;code&gt;kubectl get pods&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217720112-da2a90e5-600a-46e4-afff-423a57bf409b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-running-a-simple-integration&quot;&gt;Running a simple integration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;We can use Kamel CLI to run integration code developed in Java, groovy, etc. &lt;/li&gt;&lt;li&gt;&lt;p&gt;The Camel-K operator gets deployed to cluster as a pod, we can simply check the status of the pod and make sure it is in running state before creating an integration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is a simple Java integration code, which uses Camel RouteBuilder and REST component to expose REST endpoint and routes the message.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.RouteBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;WelcomeRoute&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RouteBuilder&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{      restConfiguration().bindingMode(&lt;span class=&quot;hljs-string&quot;&gt;&quot;auto&quot;&lt;/span&gt;);        rest(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api&quot;&lt;/span&gt;)            .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/demo/{info}&quot;&lt;/span&gt;)            .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;log:info&quot;&lt;/span&gt;)            .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:msg&quot;&lt;/span&gt;);        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:msg&quot;&lt;/span&gt;)                .transform().simple(&lt;span class=&quot;hljs-string&quot;&gt;&quot;msg received - ${header.info}&quot;&lt;/span&gt;);   }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;During development we can run the integration using &lt;code&gt;--dev&lt;/code&gt; option, the command to create and run the integration looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run WelcomeRoute.java --dev&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Using &lt;code&gt;--dev&lt;/code&gt; will print the logs in console.&lt;/li&gt;&lt;li&gt;&lt;p&gt;With this flag any changes to the Java file will reflect immediately in the integration real time.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the console log output of successfully deployed integration.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;Condition &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ready&quot;&lt;/span&gt; is &lt;span class=&quot;hljs-string&quot;&gt;&quot;True&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; Integration welcome-route: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;/&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ready replicas[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;267&lt;/span&gt; INFO  [org.apa.cam.k.Runtime] (main) Apache Camel K Runtime &lt;span class=&quot;hljs-number&quot;&gt;1.16&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;325&lt;/span&gt; INFO  [org.apa.cam.qua.cor.CamelBootstrapRecorder] (main) Bootstrap runtime: org.apache.camel.quarkus.main.CamelMainRuntime[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;334&lt;/span&gt; INFO  [org.apa.cam.mai.MainSupport] (main) Apache Camel (Main) &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; is starting[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;517&lt;/span&gt; INFO  [org.apa.cam.k.lis.SourcesConfigurer] (main) Loading routes &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;: SourceDefinition{language=&lt;span class=&quot;hljs-string&quot;&gt;&apos;java&apos;&lt;/span&gt;, type=&lt;span class=&quot;hljs-string&quot;&gt;&apos;source&apos;&lt;/span&gt;, location=&lt;span class=&quot;hljs-string&quot;&gt;&apos;file:/etc/camel/sources/.\WelcomeRoute.java&apos;&lt;/span&gt;, }[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;022&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) is starting[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;161&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Routes startup (started:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;162&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main)     Started route1 (direct:&lt;span class=&quot;hljs-comment&quot;&gt;//msg)&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;162&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main)     Started route2 (rest:&lt;span class=&quot;hljs-comment&quot;&gt;//get:/api:/demo/%7Binfo%7D)&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;163&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) started &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;732&lt;/span&gt;ms (build:&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;ms init:&lt;span class=&quot;hljs-number&quot;&gt;605&lt;/span&gt;ms start:&lt;span class=&quot;hljs-number&quot;&gt;127&lt;/span&gt;ms)[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;874&lt;/span&gt; INFO  [io.quarkus] (main) camel-k-integration &lt;span class=&quot;hljs-number&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt; on JVM (powered by Quarkus &lt;span class=&quot;hljs-number&quot;&gt;2.14&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;.Final) started &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;18.400&lt;/span&gt;s. Listening on: http:&lt;span class=&quot;hljs-comment&quot;&gt;//0.0.0.0:8080&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;879&lt;/span&gt; INFO  [io.quarkus] (main) Profile prod activated.[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;889&lt;/span&gt; INFO  [io.quarkus] (main) Installed features: [camel-attachments, camel-bean, camel-core, camel-direct, camel-java-joor-dsl, camel-k-core, camel-k-runtime, camel-kubernetes, camel-log, camel-platform-http, camel-rest, cdi, kubernetes-client, security, smallrye-context-propagation, vertx]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Kamel CLI can be used to check the status of integration, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel get&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If the integration is running on a specific namespace we can use &lt;code&gt;kame get -n &amp;lt;namespace-name&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706482-39ecead7-d7cf-493c-a764-98215c4a148d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;By default Camel-K creates a &lt;code&gt;ClusterIP&lt;/code&gt; service for this integration.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217711853-fbe6d5ad-9a14-473d-9c89-1b79f1aaac53.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The endpoints exposed can be checked using the command &lt;code&gt;kubectl get endpoint&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706735-3abd5379-130e-4af1-859c-0e5fe313c097.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;By default the Camel-K operator creates service as &lt;code&gt;ClusterIP&lt;/code&gt;. In case if we want to expose the service as &lt;code&gt;NodePort&lt;/code&gt; or &lt;code&gt;LoadBalancer&lt;/code&gt;, we can use &lt;code&gt;Service Traits&lt;/code&gt; to configure. The command looks like below.&lt;ul&gt;&lt;li&gt;There are different traits supported by Camel-K, refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/traits/traits.html&quot;&gt;Camel-K traits documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run --trait service.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; --trait service.node-port=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; --trait service.type=NodePort -n &amp;lt;namespace&amp;gt; &lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;file.java&lt;/span&gt;&amp;gt;&lt;/span&gt; --dev&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-apply-ingress-rule-to-access-the-endpoint&quot;&gt;Apply ingress rule to access the endpoint&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To access the REST endpoint from the host machine, we use Nginx Ingress control already deployed in cluster.&lt;/li&gt;&lt;li&gt;&lt;p&gt;We need a ingress rule configuration to route traffic to access the service.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The ingress rule configuration manifest content is listed below save this in a file named &lt;code&gt;ingress-rule.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1&lt;span class=&quot;hljs-attr&quot;&gt;kind&lt;/span&gt;: Ingress&lt;span class=&quot;hljs-attr&quot;&gt;metadata&lt;/span&gt;:  name: kamel-welcome-route  &lt;span class=&quot;hljs-attr&quot;&gt;annotations&lt;/span&gt;:    nginx.ingress.kubernetes.io/rewrite-target: /$&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec&lt;/span&gt;:  rules:  - http:      paths:      - pathType: Prefix        &lt;span class=&quot;hljs-attr&quot;&gt;path&lt;/span&gt;: &lt;span class=&quot;hljs-regexp&quot;&gt;/(/&lt;/span&gt;|$)(.*)        &lt;span class=&quot;hljs-attr&quot;&gt;backend&lt;/span&gt;:          service:            name: welcome-route            &lt;span class=&quot;hljs-attr&quot;&gt;port&lt;/span&gt;:              number: &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To apply the ingress rule use &lt;code&gt;kubectl apply -f ingress-rule.yaml&lt;/code&gt; command.&lt;/li&gt;&lt;li&gt;To check the ingress status use &lt;code&gt;kubectl get ingress&lt;/code&gt; command.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-access-the-rest-endpoint-and-output&quot;&gt;Access the REST endpoint and output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once the integration is deployed successfully and in running state, we can use &lt;code&gt;wget&lt;/code&gt; to get access the endpoint. Below is the complete command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;wget -q -O - localhost/api/demo/hello&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217705778-00d05132-06bd-4943-8b55-163885fa3220.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below is the operator and integration pod running in cluster, have used Lens to connect to the kind cluster.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706212-b66f9421-fc5c-41f5-9caa-e00ab55dc9f6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-passing-properties-to-the-integration-code&quot;&gt;Passing properties to the integration code&lt;/h3&gt;&lt;p&gt;For a simple groovy script, where the &lt;code&gt;my.message&lt;/code&gt; is fetched from the properties. Save the below content to a file &lt;code&gt;Message.groovy&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;from(&lt;span class=&quot;hljs-string&quot;&gt;&apos;timer:props?period=1000&apos;&lt;/span&gt;)    .log(&lt;span class=&quot;hljs-string&quot;&gt;&apos;{{my.message}}&apos;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To pass the property values, since we are not using &lt;code&gt;--dev&lt;/code&gt;, the integration will be created&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run --property my.message=&lt;span class=&quot;hljs-string&quot;&gt;&quot;Example-From-Property&quot;&lt;/span&gt; Message.groovy&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217715614-4865e91d-9cdc-4dea-9b04-1e5ec639e1f5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output looks like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;46&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;116&lt;/span&gt; INFO  [route1] (Camel (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) thread #&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - timer:&lt;span class=&quot;hljs-comment&quot;&gt;//props) Example-From-Property&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;46&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;31&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;090&lt;/span&gt; INFO  [route1] (Camel (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) thread #&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - timer:&lt;span class=&quot;hljs-comment&quot;&gt;//props) Example-From-Property&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217715505-5e351772-6175-47ed-b349-1a9ca96fbfae.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-delete-an-integration-using-kamel-cli&quot;&gt;Delete an integration using Kamel CLI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kamel CLI command &lt;code&gt;kamel get&lt;/code&gt; can be used to list the integration status.&lt;/li&gt;&lt;li&gt;To delete the integration, we need to use below command &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt; &amp;lt;name-&lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt;-integration&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-additional-information&quot;&gt;Additional information&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;We can use ConfigMap with the configuration or properties file and pass it in runtime using Kamel CLI to the integration code. Refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/configuration/runtime-properties.html&quot;&gt;Camel-K runtime configuration documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Promoting the integration to different environment, we can do it as well refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/running/promoting.html&quot;&gt;Camel-K promoting documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-camel-k&quot;&gt;Camel-K&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Apache Camel K is a lightweight cloud-integration platform that runs natively on Kubernetes.&lt;/li&gt;&lt;li&gt;&lt;p&gt;In this blog will show how to install Camel-K operator in Kubernetes (KIND) cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Have created a simple integration code (Java integration).&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The integration code expose a REST endpoint using Camel component.&lt;/li&gt;&lt;li&gt;The message is passed as URL path variable.&lt;/li&gt;&lt;li&gt;The message is routed to &lt;code&gt;direct&lt;/code&gt; endpoint and transform with a constant string.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Docker Desktop (Docker daemon running).&lt;/li&gt;&lt;li&gt;Dockerhub account.&lt;/li&gt;&lt;li&gt;Kamel CLI installed.&lt;/li&gt;&lt;li&gt;KIND CLI installed.&lt;/li&gt;&lt;li&gt;Basic understanding on Kubernetes and Operator pattern.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-options-to-install-camel-k-operator&quot;&gt;Options to install Camel-K operator&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;There are different option to install Camel-K. Options are listed below, &lt;ul&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://artifacthub.io/packages/helm/camel-k/camel-k&quot;&gt;Helm charts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://operatorhub.io/operator/camel-k&quot;&gt;OperatorHub&lt;/a&gt;&lt;/li&gt;&lt;li&gt;using &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/installation.html&quot;&gt;Kamel CLI&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;In this blog the Camel-K operator is installed with &lt;strong&gt;Kamel CLI&lt;/strong&gt; in KIND cluster.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;During Camel-K installation we need to configure the docker registry (docker.io).In this blog have used Dockerhub, we can use private registry as well.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-install-kind-cluster-and-deploy-nginx-ingress-controller&quot;&gt;Install KIND cluster and deploy Nginx Ingress controller&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The ingress controller is used to access the REST endpoint from the host machine.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the KIND cluster configuration file which includes patch configuration for ingress controller, save this as &lt;code&gt;kamel-kind-cluster.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kubeadmConfigPatches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|    kind: InitConfiguration    nodeRegistration:      kubeletExtraArgs:        node-labels: &quot;ingress-ready=true&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;We need to use the above configuration in Kind CLI to create the cluster, the command usage is listed below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kind create cluster --config kamel-kind-cluster.yaml --name kamel-ingress&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;In order to apply the ingress controller configuration below command. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/docs/user/ingress/#ingress-nginx_&quot;&gt;kind documentation&lt;/a&gt; for more info.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kubectl apply -f https:&lt;span class=&quot;hljs-comment&quot;&gt;//raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-install-camel-k-operator-in-kind-cluster&quot;&gt;Install Camel-K operator in KIND cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To install the Camel-K operator with Kamel CLI, we need to configure the docker registry (docker.io). For this first we need to create a secret in the cluster with the Docker credentials.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Creating a secret with the $HOME/.docker/config.json file directly didn&apos;t work for me. When running the integration, the logs indicated unauthorized access.&lt;/li&gt;&lt;li&gt;Below is the command to create secret from docker config file.&lt;pre&gt;&lt;code&gt;kubectl create secret generic regcred \ --&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;-file=.dockerconfigjson=$HOME/.docker/config.json \ --type=kubernetes.io/dockerconfigjson&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-install-olm-in-the-cluster&quot;&gt;Install OLM in the cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;This is optional step. By installing the OLM (Operator Lifecycle Management)  we are not required to use the option &lt;code&gt;--olm=false&lt;/code&gt; in Kamel CLI during installation.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To install the OLM, run below command from Gitbash.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;curl -sL https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.23.1/install.sh | bash -s v0.23.1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To create the secret with the Docker credentials use below commands&lt;ul&gt;&lt;li&gt;Storing the Dockerhub credentials in the environment variable will help in case we need to automate the installation process.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; powershell use below command, to accessing environment variable we use $env:&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;env-key&lt;/span&gt;&amp;gt;&lt;/span&gt;kubectl -n default create secret docker-registry external-registry-secret --docker-username $env:DOCKER_USER --docker-password $env:DOCKER_PASS# from shell (like git bash) use below commandkubectl -n default create secret docker-registry external-registry-secret --docker-username $DOCKER_USER --docker-password $DOCKER_PASS&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below command will install the Camel-K operator in default namespace.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# the secret created above is passed &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; --registry-secret &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; commandkamel install -n &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; --registry docker.io --organization &amp;lt;organization-name&amp;gt; --registry-secret external-registry-secret --wait&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If OLM is not installed in the cluster (as mentioned above), in this case then we need to use &lt;code&gt;--olm=false&lt;/code&gt; in the command shown below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel install -n &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; --olm=&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; --registry docker.io --organization &amp;lt;organization-name&amp;gt; --registry-secret external-registry-secret --wait&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Camel-K operator installation takes sometime to install.Camel-K operator deploys as a pod, so to check the status of the pod in the default namespace use &lt;code&gt;kubectl get pods&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217720112-da2a90e5-600a-46e4-afff-423a57bf409b.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-running-a-simple-integration&quot;&gt;Running a simple integration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;We can use Kamel CLI to run integration code developed in Java, groovy, etc. &lt;/li&gt;&lt;li&gt;&lt;p&gt;The Camel-K operator gets deployed to cluster as a pod, we can simply check the status of the pod and make sure it is in running state before creating an integration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is a simple Java integration code, which uses Camel RouteBuilder and REST component to expose REST endpoint and routes the message.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.RouteBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;WelcomeRoute&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RouteBuilder&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{      restConfiguration().bindingMode(&lt;span class=&quot;hljs-string&quot;&gt;&quot;auto&quot;&lt;/span&gt;);        rest(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api&quot;&lt;/span&gt;)            .get(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/demo/{info}&quot;&lt;/span&gt;)            .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;log:info&quot;&lt;/span&gt;)            .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:msg&quot;&lt;/span&gt;);        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:msg&quot;&lt;/span&gt;)                .transform().simple(&lt;span class=&quot;hljs-string&quot;&gt;&quot;msg received - ${header.info}&quot;&lt;/span&gt;);   }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;During development we can run the integration using &lt;code&gt;--dev&lt;/code&gt; option, the command to create and run the integration looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run WelcomeRoute.java --dev&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Using &lt;code&gt;--dev&lt;/code&gt; will print the logs in console.&lt;/li&gt;&lt;li&gt;&lt;p&gt;With this flag any changes to the Java file will reflect immediately in the integration real time.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the console log output of successfully deployed integration.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;Condition &lt;span class=&quot;hljs-string&quot;&gt;&quot;Ready&quot;&lt;/span&gt; is &lt;span class=&quot;hljs-string&quot;&gt;&quot;True&quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; Integration welcome-route: &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;/&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; ready replicas[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;267&lt;/span&gt; INFO  [org.apa.cam.k.Runtime] (main) Apache Camel K Runtime &lt;span class=&quot;hljs-number&quot;&gt;1.16&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;325&lt;/span&gt; INFO  [org.apa.cam.qua.cor.CamelBootstrapRecorder] (main) Bootstrap runtime: org.apache.camel.quarkus.main.CamelMainRuntime[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;334&lt;/span&gt; INFO  [org.apa.cam.mai.MainSupport] (main) Apache Camel (Main) &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; is starting[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;48&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;517&lt;/span&gt; INFO  [org.apa.cam.k.lis.SourcesConfigurer] (main) Loading routes &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt;: SourceDefinition{language=&lt;span class=&quot;hljs-string&quot;&gt;&apos;java&apos;&lt;/span&gt;, type=&lt;span class=&quot;hljs-string&quot;&gt;&apos;source&apos;&lt;/span&gt;, location=&lt;span class=&quot;hljs-string&quot;&gt;&apos;file:/etc/camel/sources/.\WelcomeRoute.java&apos;&lt;/span&gt;, }[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;022&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) is starting[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;161&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Routes startup (started:&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;162&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main)     Started route1 (direct:&lt;span class=&quot;hljs-comment&quot;&gt;//msg)&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;162&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main)     Started route2 (rest:&lt;span class=&quot;hljs-comment&quot;&gt;//get:/api:/demo/%7Binfo%7D)&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;163&lt;/span&gt; INFO  [org.apa.cam.imp.eng.AbstractCamelContext] (main) Apache Camel &lt;span class=&quot;hljs-number&quot;&gt;3.19&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) started &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;732&lt;/span&gt;ms (build:&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;ms init:&lt;span class=&quot;hljs-number&quot;&gt;605&lt;/span&gt;ms start:&lt;span class=&quot;hljs-number&quot;&gt;127&lt;/span&gt;ms)[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;874&lt;/span&gt; INFO  [io.quarkus] (main) camel-k-integration &lt;span class=&quot;hljs-number&quot;&gt;1.11&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt; on JVM (powered by Quarkus &lt;span class=&quot;hljs-number&quot;&gt;2.14&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;.Final) started &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;18.400&lt;/span&gt;s. Listening on: http:&lt;span class=&quot;hljs-comment&quot;&gt;//0.0.0.0:8080&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;879&lt;/span&gt; INFO  [io.quarkus] (main) Profile prod activated.[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;02&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;36&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;55&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;889&lt;/span&gt; INFO  [io.quarkus] (main) Installed features: [camel-attachments, camel-bean, camel-core, camel-direct, camel-java-joor-dsl, camel-k-core, camel-k-runtime, camel-kubernetes, camel-log, camel-platform-http, camel-rest, cdi, kubernetes-client, security, smallrye-context-propagation, vertx]&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Kamel CLI can be used to check the status of integration, use below command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel get&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If the integration is running on a specific namespace we can use &lt;code&gt;kame get -n &amp;lt;namespace-name&amp;gt;&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706482-39ecead7-d7cf-493c-a764-98215c4a148d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;By default Camel-K creates a &lt;code&gt;ClusterIP&lt;/code&gt; service for this integration.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217711853-fbe6d5ad-9a14-473d-9c89-1b79f1aaac53.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The endpoints exposed can be checked using the command &lt;code&gt;kubectl get endpoint&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706735-3abd5379-130e-4af1-859c-0e5fe313c097.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;By default the Camel-K operator creates service as &lt;code&gt;ClusterIP&lt;/code&gt;. In case if we want to expose the service as &lt;code&gt;NodePort&lt;/code&gt; or &lt;code&gt;LoadBalancer&lt;/code&gt;, we can use &lt;code&gt;Service Traits&lt;/code&gt; to configure. The command looks like below.&lt;ul&gt;&lt;li&gt;There are different traits supported by Camel-K, refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/traits/traits.html&quot;&gt;Camel-K traits documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run --trait service.enabled=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; --trait service.node-port=&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; --trait service.type=NodePort -n &amp;lt;namespace&amp;gt; &lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;file.java&lt;/span&gt;&amp;gt;&lt;/span&gt; --dev&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-apply-ingress-rule-to-access-the-endpoint&quot;&gt;Apply ingress rule to access the endpoint&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To access the REST endpoint from the host machine, we use Nginx Ingress control already deployed in cluster.&lt;/li&gt;&lt;li&gt;&lt;p&gt;We need a ingress rule configuration to route traffic to access the service.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The ingress rule configuration manifest content is listed below save this in a file named &lt;code&gt;ingress-rule.yaml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;apiVersion: networking.k8s.io/v1&lt;span class=&quot;hljs-attr&quot;&gt;kind&lt;/span&gt;: Ingress&lt;span class=&quot;hljs-attr&quot;&gt;metadata&lt;/span&gt;:  name: kamel-welcome-route  &lt;span class=&quot;hljs-attr&quot;&gt;annotations&lt;/span&gt;:    nginx.ingress.kubernetes.io/rewrite-target: /$&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec&lt;/span&gt;:  rules:  - http:      paths:      - pathType: Prefix        &lt;span class=&quot;hljs-attr&quot;&gt;path&lt;/span&gt;: &lt;span class=&quot;hljs-regexp&quot;&gt;/(/&lt;/span&gt;|$)(.*)        &lt;span class=&quot;hljs-attr&quot;&gt;backend&lt;/span&gt;:          service:            name: welcome-route            &lt;span class=&quot;hljs-attr&quot;&gt;port&lt;/span&gt;:              number: &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To apply the ingress rule use &lt;code&gt;kubectl apply -f ingress-rule.yaml&lt;/code&gt; command.&lt;/li&gt;&lt;li&gt;To check the ingress status use &lt;code&gt;kubectl get ingress&lt;/code&gt; command.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-access-the-rest-endpoint-and-output&quot;&gt;Access the REST endpoint and output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Once the integration is deployed successfully and in running state, we can use &lt;code&gt;wget&lt;/code&gt; to get access the endpoint. Below is the complete command.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;wget -q -O - localhost/api/demo/hello&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217705778-00d05132-06bd-4943-8b55-163885fa3220.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below is the operator and integration pod running in cluster, have used Lens to connect to the kind cluster.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217706212-b66f9421-fc5c-41f5-9caa-e00ab55dc9f6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-passing-properties-to-the-integration-code&quot;&gt;Passing properties to the integration code&lt;/h3&gt;&lt;p&gt;For a simple groovy script, where the &lt;code&gt;my.message&lt;/code&gt; is fetched from the properties. Save the below content to a file &lt;code&gt;Message.groovy&lt;/code&gt;.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;from(&lt;span class=&quot;hljs-string&quot;&gt;&apos;timer:props?period=1000&apos;&lt;/span&gt;)    .log(&lt;span class=&quot;hljs-string&quot;&gt;&apos;{{my.message}}&apos;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To pass the property values, since we are not using &lt;code&gt;--dev&lt;/code&gt;, the integration will be created&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel run --property my.message=&lt;span class=&quot;hljs-string&quot;&gt;&quot;Example-From-Property&quot;&lt;/span&gt; Message.groovy&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217715614-4865e91d-9cdc-4dea-9b04-1e5ec639e1f5.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output looks like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;46&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;116&lt;/span&gt; INFO  [route1] (Camel (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) thread #&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - timer:&lt;span class=&quot;hljs-comment&quot;&gt;//props) Example-From-Property&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hljs-number&quot;&gt;2023&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-02&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-09&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;03&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;46&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;31&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;090&lt;/span&gt; INFO  [route1] (Camel (camel&lt;span class=&quot;hljs-number&quot;&gt;-1&lt;/span&gt;) thread #&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - timer:&lt;span class=&quot;hljs-comment&quot;&gt;//props) Example-From-Property&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/217715505-5e351772-6175-47ed-b349-1a9ca96fbfae.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-delete-an-integration-using-kamel-cli&quot;&gt;Delete an integration using Kamel CLI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kamel CLI command &lt;code&gt;kamel get&lt;/code&gt; can be used to list the integration status.&lt;/li&gt;&lt;li&gt;To delete the integration, we need to use below command &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;kamel &lt;span class=&quot;hljs-keyword&quot;&gt;delete&lt;/span&gt; &amp;lt;name-&lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt;-integration&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-additional-information&quot;&gt;Additional information&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;We can use ConfigMap with the configuration or properties file and pass it in runtime using Kamel CLI to the integration code. Refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/configuration/runtime-properties.html&quot;&gt;Camel-K runtime configuration documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Promoting the integration to different environment, we can do it as well refer the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/camel-k/1.11.x/running/promoting.html&quot;&gt;Camel-K promoting documentation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Execute Java code like a script using JBang]]></title><description><![CDATA[Simple example code to explain JBang CLI usage.]]></description><link>https://thirumurthi.hashnode.dev/execute-java-code-like-a-script-using-jbang</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/execute-java-code-like-a-script-using-jbang</guid><category><![CDATA[Java]]></category><category><![CDATA[camel]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 29 Jan 2023 07:46:29 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-jbang&quot;&gt;JBang&lt;/h2&gt;&lt;p&gt;In this blog have explained the basic usage of JBang CLI command. With additional specification we will be able to run Java code without using any source code structure.&lt;/p&gt;&lt;h3 id=&quot;heading-what-is-jbang&quot;&gt;What is JBang?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/index.html&quot;&gt;JBang&lt;/a&gt; is a CLI tool which can run java code directly from a file.&lt;/li&gt;&lt;li&gt;With JBang CLI we can execute java code from file by passing it as a argument. &lt;ul&gt;&lt;li&gt;In order to execute the Java file by JBang CLI, the file shouls include special defintions within java comments, which is explained in the example.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;JBang can also execute .jsh (java shell) file. The .jsh file is similar to .java file, but it doesn&apos;t require class definition or main method.&lt;ul&gt;&lt;li&gt;Any code that executes in JShell REPL editor, can be places in .jsh file.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;JBang can also be used to install JDK&apos;s and list installed JDK&apos;s, using command &lt;code&gt;jbang jdk list&lt;/code&gt;. &lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-install-jbang&quot;&gt;Install JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI can be installed in different ways refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/installation.html&quot;&gt;installation&lt;/a&gt; docs.&lt;/li&gt;&lt;li&gt;In my Windows machine I used chocolatey manager. &lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-execute-first-java-code-in-jbang&quot;&gt;Execute first Java code in JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI requires the environment to be defined in very first line of the java file, like below.&lt;/li&gt;&lt;li&gt;This is similar to shell shebang, where we use &lt;code&gt;#!&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$@&quot; ; exit $?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save below code snippet as &lt;code&gt;addTwoNumbers.java&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$@&quot; ; exit $?&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;addTwoNumbers&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(args.length==&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {            System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;No arguments passed!!&quot;&lt;/span&gt;);        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;{              &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; num1 = Integer.parseInt(args[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]);              &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; num2 = Integer.parseInt(args[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]);              System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sum of &quot;&lt;/span&gt;+num1+&lt;span class=&quot;hljs-string&quot;&gt;&quot; + &quot;&lt;/span&gt;+num2+&lt;span class=&quot;hljs-string&quot;&gt;&quot; = &quot;&lt;/span&gt;+(num1+num2));             } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (NumberFormatException ex){                 System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;ERROR:- only whole number is supported&quot;&lt;/span&gt;);             }        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-jbang-command-to-run-java-file&quot;&gt;JBang command to run Java file&lt;/h5&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang addTwoNumbers.java &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;Sum &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-jbang-can-resolve-maven-dependencies&quot;&gt;JBang can resolve Maven dependencies&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI can resolve Maven or Gradle dependencies from the Java file.&lt;/li&gt;&lt;li&gt;JBang requires the dependencies to be specified in a specific format which should start with &lt;code&gt;//DEPS&lt;/code&gt; and looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS groupId:artifactId:version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Defining Maven &lt;code&gt;BOM&lt;/code&gt; dependencies in the Java file. Note, the suffix &lt;code&gt;@pom&lt;/code&gt;, is required when defining the bom dependencies.&lt;ul&gt;&lt;li&gt;Points to note when using  &lt;code&gt;bom&lt;/code&gt; dependencies,&lt;ul&gt;&lt;li&gt;The bom definition should be specified before using the related dependencies.&lt;/li&gt;&lt;li&gt;Single Java file that is executed by JBang can only contain one &lt;code&gt;bom&lt;/code&gt; definition.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS groupId:artifactId:version@pom&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Example for using &lt;a target=&quot;_blank&quot; href=&quot;https://mvnrepository.com/artifact/org.apache.camel/camel-bom/3.20.1&quot;&gt;camel bom&lt;/a&gt; dependencies, not nee to specify the versions for the realted dependencies.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-bom:3.20.1@pom&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-core&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-main&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-sample-code-defining-maven-dependencies-for-jbang&quot;&gt;Sample code defining maven dependencies for JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The java code below uses camel dependencies. It simply generates random number every 2.5 seconds.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save below code snippet in &lt;code&gt;CamelDemo.java&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$0&quot; : exit $?&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-bom:3.20.1@pom&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-core&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-main&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-stream&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-nop:2.0.6&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-api:2.0.6&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.main.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.spi.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; org.apache.camel.builder.PredicateBuilder.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; java.lang.System.*;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CamelDemo&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{        out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Starting camel route...&quot;&lt;/span&gt;);        setProperty(&lt;span class=&quot;hljs-string&quot;&gt;&quot;org.slf4j.simpleLogger.logFile&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;System.out&quot;&lt;/span&gt;);        Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();        Main main = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Main();        main.configure().addRoutesBuilder(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RouteBuilder(){            &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{                from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer:hello?period=2500&quot;&lt;/span&gt;)               .process(exchange -&amp;gt; exchange.getIn().setBody(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;)))               .setBody(simple(&lt;span class=&quot;hljs-string&quot;&gt;&quot;rNum: = ${body}&quot;&lt;/span&gt;))               .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;stream:out&quot;&lt;/span&gt;);            }         });        main.run();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-output-of-jbang-cli-execution&quot;&gt;Output of JBang CLI execution&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;To execute the java file using jbang use the command &lt;code&gt;jbang CamelDemo.java&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Initial run will download the defined jar dependencies and output will look like below,&lt;/li&gt;&lt;li&gt;We can use the &lt;code&gt;-verbose&lt;/code&gt; switch to print additional logs of &lt;code&gt;jbang&lt;/code&gt;like, &lt;code&gt;jbang --verbose CamelDemo.java&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang CamelDemo.java[jbang] Resolving dependencies...[jbang]    org.apache.camel:camel-bom:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;@pom[jbang]    org.apache.camel:camel-core:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.apache.camel:camel-main:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.apache.camel:camel-stream:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.slf4j:slf4j-nop:&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.6&lt;/span&gt;[jbang]    org.slf4j:slf4j-api:&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.6&lt;/span&gt;[jbang] Dependencies resolved[jbang] Building jar...Starting camel route...rNum: = &lt;span class=&quot;hljs-number&quot;&gt;482&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;rNum&lt;/span&gt;: = &lt;span class=&quot;hljs-number&quot;&gt;289&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/215309948-953a1b90-7f88-4496-8258-7684ac98019d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-use-jbang-in-docker-to-run-java-file&quot;&gt;Use JBang in Docker to run Java file&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; windows when attaching the volume better to use the complete path &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the folder where CamelDemo.java existsdocker run -v C:\\simple-camel\\:&lt;span class=&quot;hljs-regexp&quot;&gt;/ws -w/&lt;/span&gt;ws -ti jbangdev/jbang-action --verbose CamelDemo.java&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;Based on the JBang documentation, the command might looke like below, but note &lt;code&gt;pwd&lt;/code&gt; in volume didn&apos;t work in windows&lt;/p&gt;&lt;pre&gt;&lt;code&gt;docker run -v &lt;span class=&quot;hljs-string&quot;&gt;`pwd`&lt;/span&gt;:&lt;span class=&quot;hljs-regexp&quot;&gt;/ws -w/&lt;/span&gt;ws -ti jbangdev/jbang-action --verbose CamelDemo.java&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-use-jbang-to-execute-java-code-directly-using-url&quot;&gt;Use JBang to execute Java code directly using URL&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We can use JBang CLI to execute the java code directly from the internet as well &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/jbangdev/jbang-examples/blob/main/examples/helloworld.java&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/215311206-26a7b8b0-fb35-4203-9ce5-06326aa4edfe.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-consideration&quot;&gt;Consideration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;There are certain limitation in using JBang CLI, like it can&apos;t be used for complex Java programs. &lt;/li&gt;&lt;li&gt;It can refer mulitple java file under pacakges, refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/organizing.html&quot;&gt;documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;To use JBang in production totally depends on the usage, it can be used for small automation process but not for any complex code still this community is growing.&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-jbang&quot;&gt;JBang&lt;/h2&gt;&lt;p&gt;In this blog have explained the basic usage of JBang CLI command. With additional specification we will be able to run Java code without using any source code structure.&lt;/p&gt;&lt;h3 id=&quot;heading-what-is-jbang&quot;&gt;What is JBang?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/index.html&quot;&gt;JBang&lt;/a&gt; is a CLI tool which can run java code directly from a file.&lt;/li&gt;&lt;li&gt;With JBang CLI we can execute java code from file by passing it as a argument. &lt;ul&gt;&lt;li&gt;In order to execute the Java file by JBang CLI, the file shouls include special defintions within java comments, which is explained in the example.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;JBang can also execute .jsh (java shell) file. The .jsh file is similar to .java file, but it doesn&apos;t require class definition or main method.&lt;ul&gt;&lt;li&gt;Any code that executes in JShell REPL editor, can be places in .jsh file.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;JBang can also be used to install JDK&apos;s and list installed JDK&apos;s, using command &lt;code&gt;jbang jdk list&lt;/code&gt;. &lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-install-jbang&quot;&gt;Install JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI can be installed in different ways refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/installation.html&quot;&gt;installation&lt;/a&gt; docs.&lt;/li&gt;&lt;li&gt;In my Windows machine I used chocolatey manager. &lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-execute-first-java-code-in-jbang&quot;&gt;Execute first Java code in JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI requires the environment to be defined in very first line of the java file, like below.&lt;/li&gt;&lt;li&gt;This is similar to shell shebang, where we use &lt;code&gt;#!&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$@&quot; ; exit $?&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Save below code snippet as &lt;code&gt;addTwoNumbers.java&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$@&quot; ; exit $?&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;addTwoNumbers&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;(args.length==&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {            System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;No arguments passed!!&quot;&lt;/span&gt;);        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt;{              &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; num1 = Integer.parseInt(args[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]);              &lt;span class=&quot;hljs-keyword&quot;&gt;int&lt;/span&gt; num2 = Integer.parseInt(args[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]);              System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sum of &quot;&lt;/span&gt;+num1+&lt;span class=&quot;hljs-string&quot;&gt;&quot; + &quot;&lt;/span&gt;+num2+&lt;span class=&quot;hljs-string&quot;&gt;&quot; = &quot;&lt;/span&gt;+(num1+num2));             } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (NumberFormatException ex){                 System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;ERROR:- only whole number is supported&quot;&lt;/span&gt;);             }        }    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-jbang-command-to-run-java-file&quot;&gt;JBang command to run Java file&lt;/h5&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang addTwoNumbers.java &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;Sum &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-jbang-can-resolve-maven-dependencies&quot;&gt;JBang can resolve Maven dependencies&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;JBang CLI can resolve Maven or Gradle dependencies from the Java file.&lt;/li&gt;&lt;li&gt;JBang requires the dependencies to be specified in a specific format which should start with &lt;code&gt;//DEPS&lt;/code&gt; and looks like below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS groupId:artifactId:version&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Defining Maven &lt;code&gt;BOM&lt;/code&gt; dependencies in the Java file. Note, the suffix &lt;code&gt;@pom&lt;/code&gt;, is required when defining the bom dependencies.&lt;ul&gt;&lt;li&gt;Points to note when using  &lt;code&gt;bom&lt;/code&gt; dependencies,&lt;ul&gt;&lt;li&gt;The bom definition should be specified before using the related dependencies.&lt;/li&gt;&lt;li&gt;Single Java file that is executed by JBang can only contain one &lt;code&gt;bom&lt;/code&gt; definition.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS groupId:artifactId:version@pom&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Example for using &lt;a target=&quot;_blank&quot; href=&quot;https://mvnrepository.com/artifact/org.apache.camel/camel-bom/3.20.1&quot;&gt;camel bom&lt;/a&gt; dependencies, not nee to specify the versions for the realted dependencies.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-bom:3.20.1@pom&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-core&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-main&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-sample-code-defining-maven-dependencies-for-jbang&quot;&gt;Sample code defining maven dependencies for JBang&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The java code below uses camel dependencies. It simply generates random number every 2.5 seconds.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save below code snippet in &lt;code&gt;CamelDemo.java&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;///usr/bin/env jbang &quot;$0&quot; &quot;$0&quot; : exit $?&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-bom:3.20.1@pom&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-core&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-main&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.apache.camel:camel-stream&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-nop:2.0.6&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//DEPS org.slf4j:slf4j-api:2.0.6&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.main.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.spi.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; org.apache.camel.builder.PredicateBuilder.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; java.lang.System.*;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CamelDemo&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{        out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Starting camel route...&quot;&lt;/span&gt;);        setProperty(&lt;span class=&quot;hljs-string&quot;&gt;&quot;org.slf4j.simpleLogger.logFile&quot;&lt;/span&gt;, &lt;span class=&quot;hljs-string&quot;&gt;&quot;System.out&quot;&lt;/span&gt;);        Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();        Main main = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Main();        main.configure().addRoutesBuilder(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RouteBuilder(){            &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception&lt;/span&gt;{                from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer:hello?period=2500&quot;&lt;/span&gt;)               .process(exchange -&amp;gt; exchange.getIn().setBody(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;)))               .setBody(simple(&lt;span class=&quot;hljs-string&quot;&gt;&quot;rNum: = ${body}&quot;&lt;/span&gt;))               .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;stream:out&quot;&lt;/span&gt;);            }         });        main.run();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-output-of-jbang-cli-execution&quot;&gt;Output of JBang CLI execution&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;To execute the java file using jbang use the command &lt;code&gt;jbang CamelDemo.java&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Initial run will download the defined jar dependencies and output will look like below,&lt;/li&gt;&lt;li&gt;We can use the &lt;code&gt;-verbose&lt;/code&gt; switch to print additional logs of &lt;code&gt;jbang&lt;/code&gt;like, &lt;code&gt;jbang --verbose CamelDemo.java&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang CamelDemo.java[jbang] Resolving dependencies...[jbang]    org.apache.camel:camel-bom:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;@pom[jbang]    org.apache.camel:camel-core:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.apache.camel:camel-main:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.apache.camel:camel-stream:&lt;span class=&quot;hljs-number&quot;&gt;3.20&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;[jbang]    org.slf4j:slf4j-nop:&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.6&lt;/span&gt;[jbang]    org.slf4j:slf4j-api:&lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.6&lt;/span&gt;[jbang] Dependencies resolved[jbang] Building jar...Starting camel route...rNum: = &lt;span class=&quot;hljs-number&quot;&gt;482&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;rNum&lt;/span&gt;: = &lt;span class=&quot;hljs-number&quot;&gt;289&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/215309948-953a1b90-7f88-4496-8258-7684ac98019d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-use-jbang-in-docker-to-run-java-file&quot;&gt;Use JBang in Docker to run Java file&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; windows when attaching the volume better to use the complete path &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the folder where CamelDemo.java existsdocker run -v C:\\simple-camel\\:&lt;span class=&quot;hljs-regexp&quot;&gt;/ws -w/&lt;/span&gt;ws -ti jbangdev/jbang-action --verbose CamelDemo.java&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;Based on the JBang documentation, the command might looke like below, but note &lt;code&gt;pwd&lt;/code&gt; in volume didn&apos;t work in windows&lt;/p&gt;&lt;pre&gt;&lt;code&gt;docker run -v &lt;span class=&quot;hljs-string&quot;&gt;`pwd`&lt;/span&gt;:&lt;span class=&quot;hljs-regexp&quot;&gt;/ws -w/&lt;/span&gt;ws -ti jbangdev/jbang-action --verbose CamelDemo.java&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-use-jbang-to-execute-java-code-directly-using-url&quot;&gt;Use JBang to execute Java code directly using URL&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We can use JBang CLI to execute the java code directly from the internet as well &lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; jbang https:&lt;span class=&quot;hljs-comment&quot;&gt;//github.com/jbangdev/jbang-examples/blob/main/examples/helloworld.java&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/215311206-26a7b8b0-fb35-4203-9ce5-06326aa4edfe.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-consideration&quot;&gt;Consideration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;There are certain limitation in using JBang CLI, like it can&apos;t be used for complex Java programs. &lt;/li&gt;&lt;li&gt;It can refer mulitple java file under pacakges, refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.jbang.dev/documentation/guide/latest/organizing.html&quot;&gt;documentation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;To use JBang in production totally depends on the usage, it can be used for small automation process but not for any complex code still this community is growing.&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Deploy Jaeger instance in KIND cluster using Jaeger operator]]></title><description><![CDATA[Jaeger instance installation in Docker Desktop using KIND cluster, demonstrate with a simple SpringBoot application to trace spans.]]></description><link>https://thirumurthi.hashnode.dev/deploy-jaeger-instance-in-kind-cluster-using-jaeger-operator</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/deploy-jaeger-instance-in-kind-cluster-using-jaeger-operator</guid><category><![CDATA[kind cluster]]></category><category><![CDATA[jaeger]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Wed, 11 Jan 2023 06:06:20 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;p&gt;This blog will explain how to deploy the Jaeger all-in-one image in KIND cluster using the Jaeger operator.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Jaeger architecture&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Docker Desktop installed and running&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;KIND CLI configured&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-about-this-article&quot;&gt;About this article&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First, we will see instructions on how to deploy Jaeger instance in the Docker Desktop KIND cluster&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Next, we will run the SpringBoot application locally to send traces with OpenTracing.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-jaeger&quot;&gt;what is Jaeger?&lt;/h3&gt;&lt;p&gt;Jaeger is an open-source project used for distributed tracing. Jaeger project was developed by Uber and is now a CNCF project.&lt;/p&gt;&lt;p&gt;Say, when a request is being processed by multiple microservice the request flow between services can be traced in the Jaeger. The span tracing can be used to analyze the performance since the Jaeger UI provides details of how much time is spent on each service.&lt;/p&gt;&lt;h3 id=&quot;heading-jaeger-installation-steps&quot;&gt;Jaeger installation steps&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Install KIND cluster with necessary ports exposed&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Install cert-manager, using cert-manager yaml&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Based on the Jaeger Installation document it requires &lt;code&gt;cert-manager&lt;/code&gt; to be installed in the Kubernetes cluster before installing the Jaeger operator.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create Namespace and Install Jaeger operator yaml&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create Jaeger instance using CRD manifest&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In this case, have used &lt;code&gt;all-in-one&lt;/code&gt; mode Jaeger instance&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;NOTE:&lt;/p&gt;&lt;p&gt;There are different modes the Jaeger can be deployed, the default mode is &lt;code&gt;all-in-one&lt;/code&gt; mode where the trace data will not be persisted.&lt;/p&gt;&lt;p&gt;&lt;code&gt;all-in-one&lt;/code&gt; mode is mostly used for local development and data is held in memory.&lt;/p&gt;&lt;p&gt;For production, it is better to use &lt;code&gt;production&lt;/code&gt; mode. Refer Jaeger documentation for more details.&lt;/p&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-kind-configuration&quot;&gt;KIND configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;KIND cluster configuration below exposes multiple ports export, it is not necessary to expose all the ports, latter only ports 16686 and 14268 are forwarded.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the YAML content as &lt;code&gt;jaeger_kind_cluster.yaml&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;networking:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ipFamily:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ipv4&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerAddress:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6831&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6831&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;UDP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6832&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6832&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;UDP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16685&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16685&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5778&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5778&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14268&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14268&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-cert-manager-and-jaeger-operator-yaml-file-reference&quot;&gt;cert-manager and jaeger-operator yaml file reference&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the content from the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/cert-manager/cert-manager/releases/download/v1.6.3/cert-manager.yaml&quot;&gt;Cert-Manager/GitHub&lt;/a&gt; file to &lt;code&gt;cert-manager.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the content from the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/jaegertracing/jaeger-operator/releases/download/v1.41.0/jaeger-operator.yaml&quot;&gt;Jaegertracing/GitHub&lt;/a&gt; file to &lt;code&gt;jaeger-opertor.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the Jaeger CRD manifest YAML, which deploys Jaeger instance in KIND cluster.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;simplest&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-shell-script-to-install-jaeger-in-kind-cluster&quot;&gt;Shell script to install Jaeger in KIND cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Once the yaml files are stored under a directory, run below script in Git Bash to install the Jaeger Instance.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#! /bin/sh&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Create kind cluster in Docker desktop&lt;/span&gt;kind create cluster --name jaeger-cluster --config jaeger_kind_cluster.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# install the cert manager &lt;/span&gt;kubectl apply -f cert-manager.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# create namespace trace&lt;/span&gt;kubectl create ns trace&lt;span class=&quot;hljs-comment&quot;&gt;# sleep for 10 sec&lt;/span&gt;sleep 10&lt;span class=&quot;hljs-comment&quot;&gt;# install the jaeger operator&lt;/span&gt;kubectl -n trace apply -f jaeger-operator.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# pause for 100 seconds&lt;/span&gt;sleep 100&lt;span class=&quot;hljs-comment&quot;&gt;# install the simple cluster&lt;/span&gt;kubectl -n trace apply -f simple-jaeger.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;After execution of the shell script, with the below command status and strategy of deployed Jaeger instance can be verified.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ kubectl -n trace get jaegersNAME       STATUS    VERSION   STRATEGY   STORAGE   AGEsimplest   Running   1.40.0    allinone   memory    10d&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below is the output of status of the deployed Jaeger resources in the KIND cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# get the pods name of the jaeger$ kubectl -n trace get pods# output NAME                               READY   STATUS    RESTARTS       AGEjaeger-operator-6787f4df85-ww7mx   2/2     Running   7 (147m ago)   10dsimplest-6b8dbb67c5-kpz5j          1/1     Running   0              146m&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# ge the service status$ kubectl -n trace get svc# output sampleNAME                            TYPE        CLUSTER-IP   PORT(S)                                                 jaeger-operator-metrics         ClusterIP   10.96.230.32 8443/TCP                                                jaeger-operator-webhook-service ClusterIP   10.96.137.93 443/TCP                                                 simplest-agent                  ClusterIP   None         5775/UDP,5778/TCP,6831/UDP,6832/UDP                     simplest-collector              ClusterIP   10.96.135.45 9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCPsimplest-collector-headless     ClusterIP   None         9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCPsimplest-query                  ClusterIP   10.96.212.68 16686/TCP,16685/TCP&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-port-forward-the-ui-and-the-jaeger-collector-service-port&quot;&gt;Port forward the UI and the Jaeger collector service port&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In the spring application, we will send the traces to the 14268 port, which is the Jaeger collector service running in the cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Based on the Jaeger architecture, the collector service will collect the traces.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# port forward the jaeger pod (the pod name can be fetched from above command)kubectl -n trace port-forward pod/simplest-6b8dbb67c5-kpz5j 16686:16686# port forward the jaeger service kubectl -n trace port-forward svc/simplest-collector 14268:14268&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;SpringBoot application is developed using 2.7.7 version with OpenTracing dependencies.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;SpringBoot 3.0.0 doesn&apos;t support OpenTracing, it is deprecated in favor of OpenTelementry.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-springboot-application-to-send-traces&quot;&gt;SpringBoot Application to send traces&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The pom.xml file with &lt;code&gt;OpenTracing&lt;/code&gt; dependencies.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.7&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.example&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;application&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.opentracing.contrib&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;opentracing-spring-jaeger-cloud-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.3.1&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The entry point of SpringBoot application.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JaegerApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(KafkaApplication.class, args);    }    // Used by the Jeager dependencies to intercept http header    &lt;span class=&quot;hljs-meta&quot;&gt;@Bean&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; RestTemplate &lt;span class=&quot;hljs-title&quot;&gt;restTemplate&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(RestTemplateBuilder builder)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; builder.build();    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Spring controller below exposes two endpoint &lt;code&gt;/api/generate&lt;/code&gt; and &lt;code&gt;api/fetch&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;We will execute the same SpringBoot application in different ports (&lt;code&gt;8080&lt;/code&gt; and &lt;code&gt;8090&lt;/code&gt;) on the same host machine.&lt;/p&gt;&lt;p&gt;The endpoint &lt;code&gt;http://localhost:8080/api/fetch&lt;/code&gt; will invoke the application running on &lt;code&gt;http:/localhost:8090/api/generate&lt;/code&gt;. The traces will be sent to the Jaeger instance by the application.&lt;/p&gt;&lt;p&gt;We can update the Jaeger configuration to send traces in the sample rather than sending all the traces for each request which is not shown here.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.Configuration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.internal.samplers.ConstSampler;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.internal.samplers.ProbabilisticSampler;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.ResponseEntity;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; RestTemplate restTemplate;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(RestTemplate restTemplate)&lt;/span&gt;&lt;/span&gt;{       &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.restTemplate = restTemplate;   }    Random rand = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/generate&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;calculate&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; number = rand.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;);        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;api /generate invoked {}&quot;&lt;/span&gt;,number);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; number;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${app2.port:8090}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String appPort;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${app2.host:localhost}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String hostName;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/fetch&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity &lt;span class=&quot;hljs-title&quot;&gt;getNum&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String url = &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://&quot;&lt;/span&gt;+hostName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;:&quot;&lt;/span&gt;+appPort+&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api/generate&quot;&lt;/span&gt;;        String resp = restTemplate.getForObject(url, String.class);        log.info(&quot;api/fetch invoked - {} = {}&quot;,url,resp);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(&lt;span class=&quot;hljs-string&quot;&gt;&quot;random num : &quot;&lt;/span&gt;+resp);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;application.yml&lt;/code&gt; file defining the &lt;code&gt;OpenTracing&lt;/code&gt; Jaeger URL configuration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The spring application name is not passed during runtime with &lt;code&gt;Java&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;  opentracing:    jaeger:      http-sender:        url: http://localhost:14268/api/traces&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-execute-the-spring-boot-application-services&quot;&gt;Execute the spring boot application services&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use &lt;code&gt;mvn clean install&lt;/code&gt; command to create the jar file.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once jar file is generated, execute two instances of application with the below commands.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;java -jar .\target\app-0.0.1-SNAPSHOT.jar --spring.application.name=service-1 --server.port=8080 --debugjava -jar .\target\app-0.0.1-SNAPSHOT.jar --spring.application.name=service-2 --server.port=8090 --debug&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;After the application is up and running, use &lt;code&gt;curl&lt;/code&gt; command to access the REST end-point like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;curl -i http://localhost:8080/api/fetchHTTP/1.1 200 Content-Type: text/plain;charset=UTF-8Content-Length: 16Date: Wed, 11 Jan 2023 02:09:58 GMTrandom num : 771&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Once the &lt;code&gt;curl&lt;/code&gt; command access the endpoint the traces are sent to Jaeger and we can view the spans from &lt;a target=&quot;_blank&quot; href=&quot;http://localhost:16686&quot;&gt;Jaeger UI&lt;/a&gt; at &lt;code&gt;http://localhost:16686&lt;/code&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In Jaeger UI the service name &lt;code&gt;jaeger-query&lt;/code&gt; is the default.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;After accessing the REST endpoint and traces are collected the Jaeger UI spans can be viewed under service. This service is the SpringBoot application name. In this case, &lt;code&gt;service-1&lt;/code&gt; and &lt;code&gt;service-2&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-snapshot-of-the-jaeger-ui-after-shipping-the-traces&quot;&gt;Snapshot of the Jaeger UI after shipping the traces&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/211721720-4cc25cc7-4817-42b4-9ebc-26d1e2cffe17.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/211721864-0fd6b612-f36e-4e17-9f91-a9063e1caf0e.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;p&gt;This blog will explain how to deploy the Jaeger all-in-one image in KIND cluster using the Jaeger operator.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Jaeger architecture&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Docker Desktop installed and running&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;KIND CLI configured&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-about-this-article&quot;&gt;About this article&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;First, we will see instructions on how to deploy Jaeger instance in the Docker Desktop KIND cluster&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Next, we will run the SpringBoot application locally to send traces with OpenTracing.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-jaeger&quot;&gt;what is Jaeger?&lt;/h3&gt;&lt;p&gt;Jaeger is an open-source project used for distributed tracing. Jaeger project was developed by Uber and is now a CNCF project.&lt;/p&gt;&lt;p&gt;Say, when a request is being processed by multiple microservice the request flow between services can be traced in the Jaeger. The span tracing can be used to analyze the performance since the Jaeger UI provides details of how much time is spent on each service.&lt;/p&gt;&lt;h3 id=&quot;heading-jaeger-installation-steps&quot;&gt;Jaeger installation steps&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Install KIND cluster with necessary ports exposed&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Install cert-manager, using cert-manager yaml&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Based on the Jaeger Installation document it requires &lt;code&gt;cert-manager&lt;/code&gt; to be installed in the Kubernetes cluster before installing the Jaeger operator.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create Namespace and Install Jaeger operator yaml&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create Jaeger instance using CRD manifest&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In this case, have used &lt;code&gt;all-in-one&lt;/code&gt; mode Jaeger instance&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;NOTE:&lt;/p&gt;&lt;p&gt;There are different modes the Jaeger can be deployed, the default mode is &lt;code&gt;all-in-one&lt;/code&gt; mode where the trace data will not be persisted.&lt;/p&gt;&lt;p&gt;&lt;code&gt;all-in-one&lt;/code&gt; mode is mostly used for local development and data is held in memory.&lt;/p&gt;&lt;p&gt;For production, it is better to use &lt;code&gt;production&lt;/code&gt; mode. Refer Jaeger documentation for more details.&lt;/p&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-kind-configuration&quot;&gt;KIND configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;KIND cluster configuration below exposes multiple ports export, it is not necessary to expose all the ports, latter only ports 16686 and 14268 are forwarded.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the YAML content as &lt;code&gt;jaeger_kind_cluster.yaml&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;networking:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ipFamily:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ipv4&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerAddress:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6831&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6831&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;UDP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6832&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6832&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;UDP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16686&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16685&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;16685&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9411&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4317&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;4318&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5778&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5778&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14250&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14268&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14268&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;14269&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-cert-manager-and-jaeger-operator-yaml-file-reference&quot;&gt;cert-manager and jaeger-operator yaml file reference&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save the content from the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/cert-manager/cert-manager/releases/download/v1.6.3/cert-manager.yaml&quot;&gt;Cert-Manager/GitHub&lt;/a&gt; file to &lt;code&gt;cert-manager.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Save the content from the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/jaegertracing/jaeger-operator/releases/download/v1.41.0/jaeger-operator.yaml&quot;&gt;Jaegertracing/GitHub&lt;/a&gt; file to &lt;code&gt;jaeger-opertor.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Below is the Jaeger CRD manifest YAML, which deploys Jaeger instance in KIND cluster.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jaegertracing.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Jaeger&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;simplest&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-shell-script-to-install-jaeger-in-kind-cluster&quot;&gt;Shell script to install Jaeger in KIND cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Once the yaml files are stored under a directory, run below script in Git Bash to install the Jaeger Instance.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-sh&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#! /bin/sh&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Create kind cluster in Docker desktop&lt;/span&gt;kind create cluster --name jaeger-cluster --config jaeger_kind_cluster.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# install the cert manager &lt;/span&gt;kubectl apply -f cert-manager.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# create namespace trace&lt;/span&gt;kubectl create ns trace&lt;span class=&quot;hljs-comment&quot;&gt;# sleep for 10 sec&lt;/span&gt;sleep 10&lt;span class=&quot;hljs-comment&quot;&gt;# install the jaeger operator&lt;/span&gt;kubectl -n trace apply -f jaeger-operator.yaml&lt;span class=&quot;hljs-comment&quot;&gt;# pause for 100 seconds&lt;/span&gt;sleep 100&lt;span class=&quot;hljs-comment&quot;&gt;# install the simple cluster&lt;/span&gt;kubectl -n trace apply -f simple-jaeger.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;After execution of the shell script, with the below command status and strategy of deployed Jaeger instance can be verified.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;$ kubectl -n trace get jaegersNAME       STATUS    VERSION   STRATEGY   STORAGE   AGEsimplest   Running   1.40.0    allinone   memory    10d&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below is the output of status of the deployed Jaeger resources in the KIND cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# get the pods name of the jaeger$ kubectl -n trace get pods# output NAME                               READY   STATUS    RESTARTS       AGEjaeger-operator-6787f4df85-ww7mx   2/2     Running   7 (147m ago)   10dsimplest-6b8dbb67c5-kpz5j          1/1     Running   0              146m&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# ge the service status$ kubectl -n trace get svc# output sampleNAME                            TYPE        CLUSTER-IP   PORT(S)                                                 jaeger-operator-metrics         ClusterIP   10.96.230.32 8443/TCP                                                jaeger-operator-webhook-service ClusterIP   10.96.137.93 443/TCP                                                 simplest-agent                  ClusterIP   None         5775/UDP,5778/TCP,6831/UDP,6832/UDP                     simplest-collector              ClusterIP   10.96.135.45 9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCPsimplest-collector-headless     ClusterIP   None         9411/TCP,14250/TCP,14267/TCP,14268/TCP,4317/TCP,4318/TCPsimplest-query                  ClusterIP   10.96.212.68 16686/TCP,16685/TCP&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-port-forward-the-ui-and-the-jaeger-collector-service-port&quot;&gt;Port forward the UI and the Jaeger collector service port&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In the spring application, we will send the traces to the 14268 port, which is the Jaeger collector service running in the cluster.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Based on the Jaeger architecture, the collector service will collect the traces.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# port forward the jaeger pod (the pod name can be fetched from above command)kubectl -n trace port-forward pod/simplest-6b8dbb67c5-kpz5j 16686:16686# port forward the jaeger service kubectl -n trace port-forward svc/simplest-collector 14268:14268&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;SpringBoot application is developed using 2.7.7 version with OpenTracing dependencies.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;SpringBoot 3.0.0 doesn&apos;t support OpenTracing, it is deprecated in favor of OpenTelementry.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-springboot-application-to-send-traces&quot;&gt;SpringBoot Application to send traces&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The pom.xml file with &lt;code&gt;OpenTracing&lt;/code&gt; dependencies.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.7&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.example&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;application&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.opentracing.contrib&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;opentracing-spring-jaeger-cloud-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.3.1&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;The entry point of SpringBoot application.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JaegerApplication&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{        SpringApplication.run(KafkaApplication.class, args);    }    // Used by the Jeager dependencies to intercept http header    &lt;span class=&quot;hljs-meta&quot;&gt;@Bean&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; RestTemplate &lt;span class=&quot;hljs-title&quot;&gt;restTemplate&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(RestTemplateBuilder builder)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; builder.build();    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Spring controller below exposes two endpoint &lt;code&gt;/api/generate&lt;/code&gt; and &lt;code&gt;api/fetch&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;We will execute the same SpringBoot application in different ports (&lt;code&gt;8080&lt;/code&gt; and &lt;code&gt;8090&lt;/code&gt;) on the same host machine.&lt;/p&gt;&lt;p&gt;The endpoint &lt;code&gt;http://localhost:8080/api/fetch&lt;/code&gt; will invoke the application running on &lt;code&gt;http:/localhost:8090/api/generate&lt;/code&gt;. The traces will be sent to the Jaeger instance by the application.&lt;/p&gt;&lt;p&gt;We can update the Jaeger configuration to send traces in the sample rather than sending all the traces for each request which is not shown here.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.kafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.Configuration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.internal.samplers.ConstSampler;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; io.jaegertracing.internal.samplers.ProbabilisticSampler;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.web.client.RestTemplateBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.Bean;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.ResponseEntity;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.client.RestTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; RestTemplate restTemplate;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(RestTemplate restTemplate)&lt;/span&gt;&lt;/span&gt;{       &lt;span class=&quot;hljs-keyword&quot;&gt;this&lt;/span&gt;.restTemplate = restTemplate;   }    Random rand = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/generate&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;calculate&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; number = rand.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;);        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;api /generate invoked {}&quot;&lt;/span&gt;,number);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; number;    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${app2.port:8090}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String appPort;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${app2.host:localhost}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String hostName;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/fetch&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity &lt;span class=&quot;hljs-title&quot;&gt;getNum&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String url = &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://&quot;&lt;/span&gt;+hostName+&lt;span class=&quot;hljs-string&quot;&gt;&quot;:&quot;&lt;/span&gt;+appPort+&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api/generate&quot;&lt;/span&gt;;        String resp = restTemplate.getForObject(url, String.class);        log.info(&quot;api/fetch invoked - {} = {}&quot;,url,resp);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(&lt;span class=&quot;hljs-string&quot;&gt;&quot;random num : &quot;&lt;/span&gt;+resp);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;application.yml&lt;/code&gt; file defining the &lt;code&gt;OpenTracing&lt;/code&gt; Jaeger URL configuration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The spring application name is not passed during runtime with &lt;code&gt;Java&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;  opentracing:    jaeger:      http-sender:        url: http://localhost:14268/api/traces&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-execute-the-spring-boot-application-services&quot;&gt;Execute the spring boot application services&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use &lt;code&gt;mvn clean install&lt;/code&gt; command to create the jar file.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Once jar file is generated, execute two instances of application with the below commands.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;java -jar .\target\app-0.0.1-SNAPSHOT.jar --spring.application.name=service-1 --server.port=8080 --debugjava -jar .\target\app-0.0.1-SNAPSHOT.jar --spring.application.name=service-2 --server.port=8090 --debug&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;After the application is up and running, use &lt;code&gt;curl&lt;/code&gt; command to access the REST end-point like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;curl -i http://localhost:8080/api/fetchHTTP/1.1 200 Content-Type: text/plain;charset=UTF-8Content-Length: 16Date: Wed, 11 Jan 2023 02:09:58 GMTrandom num : 771&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Once the &lt;code&gt;curl&lt;/code&gt; command access the endpoint the traces are sent to Jaeger and we can view the spans from &lt;a target=&quot;_blank&quot; href=&quot;http://localhost:16686&quot;&gt;Jaeger UI&lt;/a&gt; at &lt;code&gt;http://localhost:16686&lt;/code&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In Jaeger UI the service name &lt;code&gt;jaeger-query&lt;/code&gt; is the default.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;After accessing the REST endpoint and traces are collected the Jaeger UI spans can be viewed under service. This service is the SpringBoot application name. In this case, &lt;code&gt;service-1&lt;/code&gt; and &lt;code&gt;service-2&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-snapshot-of-the-jaeger-ui-after-shipping-the-traces&quot;&gt;Snapshot of the Jaeger UI after shipping the traces&lt;/h4&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/211721720-4cc25cc7-4817-42b4-9ebc-26d1e2cffe17.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/211721864-0fd6b612-f36e-4e17-9f91-a9063e1caf0e.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Deploy Strimzi Apache Kafka Operator in KIND cluster with KRaft mode]]></title><description><![CDATA[Demonstration of deploying Strimzi Apache kafka operator enabling the KRaft mode (experimental feature) in KIND cluster.]]></description><link>https://thirumurthi.hashnode.dev/deploy-strimzi-apache-kafka-operator-in-kind-cluster-with-kraft-mode</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/deploy-strimzi-apache-kafka-operator-in-kind-cluster-with-kraft-mode</guid><category><![CDATA[Kraft]]></category><category><![CDATA[Apache Kafka]]></category><category><![CDATA[Strimzi]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 03 Dec 2022 08:15:34 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-deploy-kafka-cluster-in-kind-cluster&quot;&gt;Deploy Kafka cluster in KIND cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this article, I will explain to show how we can deploy Strimzi Kafka enabling KRaft mode in KIND cluster within the Docker desktop.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configuration defined in this article also shows how we can access Kafka broker from the host machine.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Prerequisites :&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Kubernetes and Operator patterns&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Apache Kafka&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Docker Desktop installed and running&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;KIND CLI installed&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;GNU Make 4.0 installed (for automation)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Apache Kafka Zookeeper Vs KRaft:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kafka community currently recommends using &lt;code&gt;Zookeeper&lt;/code&gt; for leader election in the production environment. Due to lots of limitations Kafka community is moving out of &lt;code&gt;Zookeeper&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;KRaft&lt;/code&gt; is new way by which Kafka manages quoram between multiple clusters.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Kraft&lt;/code&gt; is still an experimental feature and &lt;strong&gt;NOT&lt;/strong&gt; to be used in production yet.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Deploying Kafka in Kubernetes?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy Kafka in Kubernetes the easiest option is Strimzi Apache Kafka Operator.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Strimzi&lt;/code&gt; Operators can be configured to deploy Kafka brokers in production.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Strimzi&lt;/code&gt; is CNCF supported project.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Persistent datastore in &lt;code&gt;Strimzi&lt;/code&gt; has different options like,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ephemeral&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;JBOD &lt;a target=&quot;_blank&quot; href=&quot;https://strimzi.io/blog/2019/07/08/persistent-storage-improvements/&quot;&gt;Just a Bunch Of Disks&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Persistent Volumes provided by any Cloud providers&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://strimzi.io/quickstarts/&quot;&gt;strimzi.io&lt;/a&gt; details the steps to deploy a persistent Kafka cluster in KIND.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-does-this-article-include&quot;&gt;What does this article include?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;We will deploy &lt;code&gt;Strimzi&lt;/code&gt; Kafka cluster with 3 brokers and Ephemeral type datastore. With ephemeral configuration, if the broker is destroyed the data will be lost.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;How to enables the experimental &lt;code&gt;KRaft&lt;/code&gt; mode in &lt;code&gt;Strimzi&lt;/code&gt; Operator.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;How we can access the Kafka brokers running in &lt;code&gt;KIND&lt;/code&gt; cluster from the host machine.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In Windows machine to access the containers running &lt;code&gt;KIND&lt;/code&gt; cluster we need to forward the port, by updating the Strimzi cluster configuration.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; **INFO**&amp;gt; &amp;gt; *   Accessing &lt;span class=&quot;hljs-string&quot;&gt;`Strimzi Apache Kafka`&lt;/span&gt; brokers &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the outside &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; kubernetes cluster it requires bootstrap service to be exposed &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; NodePort. [Refer to &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; article that explains accessing Strimzi Kafka cluster &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; an external client](https:&lt;span class=&quot;hljs-comment&quot;&gt;//strimzi.io/blog/2019/04/23/accessing-kafka-part-2/)&lt;/span&gt;&amp;gt;     &lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-why-kraft-mode&quot;&gt;Why KRaft mode?&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The reason to use Kraft mode is on my laptop, deploying the Strimzi Kafka with &lt;code&gt;Zookeeper&lt;/code&gt; keeps on restarting the &lt;code&gt;Zookeeper&lt;/code&gt; and &lt;code&gt;Kafka Broker&lt;/code&gt; pods very often most of the time not accessible. I think this is because of memory limitations my laptop only had 8GB of memory.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;KRaft&lt;/code&gt; feature does create &lt;code&gt;Zookeeper&lt;/code&gt; pods.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Deploying Kafka in &lt;code&gt;KRaft&lt;/code&gt; mode with 3 brokers in &lt;code&gt;KIND&lt;/code&gt; cluster was always running successfully.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Noticed that when sending messages to the cluster with the console producer bat script there are retry error messages printed in console.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Since it is easy to spin up in a local machine we can use this to develop Kafka based applications locally.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;NOTE:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The same Strimzi Cluster configuration will work for &lt;code&gt;non- kRaft&lt;/code&gt; mode where &lt;code&gt;Zookeeper&lt;/code&gt; is used, the configuration requires including the &lt;code&gt;Entity operator&lt;/code&gt; and &lt;code&gt;Topic operator&lt;/code&gt; which can have empty values.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-steps-to-install-strimzi-apache-kafka-in-kind-cluster&quot;&gt;Steps to install Strimzi Apache Kafka in KIND cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;1. Spin up the KIND cluster with the required port forward configuration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;2. Create a namespace called &lt;code&gt;kafka&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;3. Install the &lt;code&gt;Strimzi&lt;/code&gt; Operator (This can be done using Helm chart as well)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4. Enable &lt;code&gt;KRaft&lt;/code&gt; feature&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;5. Install the Strimzi cluster using the CRD configuration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;6. Create Topic using Strimzi CRD in the Kafka broker&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;7. Connect to Strimzi Kafka broker using Apache Kafka binary bat script&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Later in this article, we will see how to automate the process using GNU &lt;code&gt;make&lt;/code&gt; .&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-step-1-create-kind-cluster-with-port-forward-configuration&quot;&gt;Step 1: Create KIND cluster with port forward configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create &lt;code&gt;Kind&lt;/code&gt; cluster we can use the below configuration which includes a list of port that forwards the network traffic to the cluster. Since we use GNU &lt;code&gt;make&lt;/code&gt;save this in a file named &lt;code&gt;kafka_kind_cluster.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;networking:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ipFamily:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ipv4&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerAddress:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If Docker Desktop is running, execute the below command to create &lt;code&gt;KIND&lt;/code&gt; cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kind create cluster --name=kafka --config=kafka_kind_cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt; will display the ports that forwards the traffic like below&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e5c4d36547af kindest/node:v1.25.2 &quot;/usr/local/bin/entr&quot; About an hour ago Up About an hour 127.0.0.1:6443-&amp;gt;6443/tcp, 127.0.0.1:31234-31236-&amp;gt;31234-31236/tcp, 127.0.0.1:9092-&amp;gt;31092/tcp kafka-control-plane&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-step-2-create-a-namespace&quot;&gt;Step 2: Create a namespace&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We can create the namespace in the cluster Imperatively using &lt;code&gt;kubectl&lt;/code&gt; command or Declaratively using YAML manifest.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl create ns kafka&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-3-install-strimzi-operator&quot;&gt;Step 3: Install Strimzi operator&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Strimzi&lt;/code&gt; can also be installed using Helm chart as well, the steps are available in Strimzi documentation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# namespace used is kafkakubectl create -f &apos;https://strimzi.io/install/latest?namespace=kafka&apos; -n kafka&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-4-enable-kraft-feature&quot;&gt;Step 4: Enable KRaft feature&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kraft mode requires the feature &lt;code&gt;UseStimziPodSets&lt;/code&gt; also to be enabled, since this feature is already enabled in &lt;code&gt;Strimzi Version 0.32.0&lt;/code&gt; no action is required.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The enable &lt;code&gt;Kraft&lt;/code&gt; mode we need to set the environment variable in Strimzi Operator. Before enabling the &lt;code&gt;KRaft&lt;/code&gt; feature we ned to make sure the Operator is in &lt;code&gt;Running&lt;/code&gt; status using &lt;code&gt;kubectl -n kafka get pods,svc,deployment&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Executing the command below will enable the &lt;code&gt;KRaft&lt;/code&gt; feature in the operator eventually restarts it.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl -n kafka set env deployment/strimzi-cluster-operator STRIMZI_FEATURE_GATES=+UseKRaft&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-5-install-kafka-cluster-using-strimzi-crd-definition&quot;&gt;Step 5: Install Kafka cluster using Strimzi CRD definition&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;This section will detail the &lt;code&gt;Strimzi&lt;/code&gt; CRD to define Kafka cluster configuration that will spin up &lt;code&gt;3 brokers&lt;/code&gt; with &lt;code&gt;Ephemeral&lt;/code&gt; type storage.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The listener configuration exposes the service as NodePort with the specified port.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;name: externaltype: NodePortport: 9094&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;When the Kafka client connects to the broker the bootstrap server sends the list of brokers with the leader info, by using &lt;code&gt;advertisedHost: 127.0.0.1&lt;/code&gt; the host machine can connect to the broker.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Additionally, these broker ports are used in the KIND cluster configuration to forward the traffic to Kafka broker.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configuration below still specifies the Zookeeper details since KRaft is an experimental feature. We don&apos;t need to specify the &lt;code&gt;Entity Operator&lt;/code&gt; and &lt;code&gt;Topic Operator&lt;/code&gt; for KRaft mode.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;The configuration below defines 3 brokers, expose service as Nodeport and Storage type as Ephemeral. Save the content to file &lt;code&gt;kraftmode.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.2&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;internal&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;external&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nodeport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;configuration:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;brokers:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;offsets.topic.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.min.isr:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;default.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;min.insync.replication:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;inter.broker.protocol.version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;3.2&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zookeeper:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once &lt;code&gt;Kraft&lt;/code&gt; feature is enabled and the &lt;code&gt;Strimzi&lt;/code&gt; operator is in &lt;code&gt;Running&lt;/code&gt; state, execute the command below to deploy the Kafka cluster.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl -n kafka apply -f kraftMode.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To track the status of the resource execute the command below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kafka -n kafka get pods,deploy,svc&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-6-create-topic-using-strimzi-crd&quot;&gt;Step 6: Create Topic using Strimzi CRD&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The configuration to create a Topic using the CRD is listed below, save the content to a file named topic.yaml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;KafkaTopic&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-demo&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;strimzi.io/cluster:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;topicName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;partitions:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To create the topic and view the details of the created topic use the commands below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# to create the topickubectl -n kafka apply -f topic.yaml# to view the created topickubectl -n kafka get kafkatopics&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-7-access-the-kafka-cluster&quot;&gt;Step 7: Access the Kafka cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;We can access the kafka broker using any Kafka client, the bootstrap server now is accessible via &lt;code&gt;localhost:9092&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the binaries from &lt;code&gt;Apache kafka&lt;/code&gt; website, and use the &lt;code&gt;kafka-console-producer.bat&lt;/code&gt;, &lt;code&gt;kafka-topic.bat&lt;/code&gt;, etc. to connect the brokers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The command below uses the producer script to send messages.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kafka-console-producer.bat --bootstrap-server localhost:9092 --topic example-demo aks=all&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# once messages are sent we can list the topic with below commandkafka-topic.bat --bootstrap-server localhost:9092 --list&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-using-the-makefile&quot;&gt;Using the Makefile&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;Makefile&lt;/code&gt; below automates part of the process of &lt;code&gt;deploying the operator&lt;/code&gt;, &lt;code&gt;creating the cluster&lt;/code&gt; and &lt;code&gt;deleting the kind cluster&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save below content in a file called &lt;code&gt;Makefile&lt;/code&gt;, make sure the recipe under the target starts with a &lt;code&gt;tab space&lt;/code&gt; else make command will error out.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This &lt;code&gt;Makefile&lt;/code&gt; contains additional targets like &lt;code&gt;installing kind cli&lt;/code&gt; and &lt;code&gt;install kubectl&lt;/code&gt;, etc. but this only works on Linux machines.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;SHELL :=/bin/bashNAMESPACE ?= kafkaCLUSTERNAME ?= kafkaSLEEPSEC ?= 5000#KAFKAEPHEMERALCONFIG := kafka-ephemeral-single.yamlKAFKAEPHEMERALCONFIG := kraftmode.yamlKAFKACLUSTER := kafka_kind_cluster.yaml.DEFAULT_GOAL :=info.PHONY: install-kind-linuxinstall-kind-linux:     @curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.17.0/kind-linux-amd64     @chmod +x ./kind     @mv ./kind /usr/local/bin/kind     @chmod +x /usr/local/bin/kind  .PHONY: install-kubectlinstall-kubectl:     @curl -LO &quot;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl&quot;    @chmod +x kubectl     @mkdir -p ~/.local/bin     @mv ./kubectl /usr/local/bin/kubectl     @chmod +x /usr/local/bin/kubectl.PHONY: install-clusterinstall-cluster:    @kind create cluster --name=${CLUSTERNAME} --config=./${KAFKACLUSTER}.PHONY: create-namespacecreate-namespace:    @kubectl create ns ${NAMESPACE}.PHONY: install-operatorinstall-operator:    @kubectl create -f &apos;https://strimzi.io/install/latest?namespace=${NAMESPACE}&apos; -n ${NAMESPACE}.PHONY: list-resourcelist-resource:    @kubectl -n kafka get pods,svc.PHONY: wait-zzwait-zz: # sleep 5 second    @echo &quot;waiting....&quot; \    sleep ${SLEEPSEC}.PHONY: delete-kind-clusterdelete-kind-cluster: ; @kind delete cluster --name=${CLUSTERNAME}.PHONY: install-kafka-clusterinstall-kafka-cluster: enable-kraft-feature wait-zz    @kubectl -n ${NAMESPACE} apply -f ${KAFKAEPHEMERALCONFIG}    @sleep ${SLEEPSEC}.PHONY: enable-kraft-featureenable-kraft-feature:     kubectl -n ${NAMESPACE} set env deployment/strimzi-cluster-operator STRIMZI_FEATURE_GATES=+UseKRaft.PHONY: deploy-operatordeploy-operator: install-cluster create-namespace install-operator wait-zz list-resource    @echo &quot;installing kafka&quot;.PHONY: kafka-producerkafka-producer:     echo &quot;kafka producer starting up...&quot;    @kubectl -n kafka run kafka-producer -ti --image=quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 --rm=true --restart=Never -- bin/kafka-console-producer.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 --topic my-topic.PHONY: kafka-consumerkafka-consumer:     echo &quot;kafka consumer starting to listen...&quot;    @kubectl -n kafka run kafka-consumer -ti --image=quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 --rm=true --restart=Never -- bin/kafka-console-consumer.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 --topic my-topic --from-beginninginfo:    @awk &apos;/^[a-zA-Z_-]+: / { print $$0; print &quot;\n&quot;}&apos; $(MAKEFILE_LIST) | \    awk -F&quot;:&quot; &apos;BEGIN {print &quot;targets&quot; } /^[a-zA-Z_-]+/ {print &quot;    &quot;$$1}&apos;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-using-makefile-targets&quot;&gt;Using Makefile Targets&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Executing the command &lt;code&gt;make&lt;/code&gt; will list the target names.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Step 1: To deploy the operator use command, &lt;code&gt;make deploy-operator&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Step 2: Once the &lt;code&gt;Strimzi&lt;/code&gt; operator status is &lt;code&gt;Running&lt;/code&gt;. Execute &lt;code&gt;make install-kafka-cluster&lt;/code&gt; command to install the cluster. This will enable the &lt;code&gt;KRaft&lt;/code&gt; feature and install the cluster with the configuration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note: Make sure the file name matches and all files are in the same directory.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make deploy-operator&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426061-1df530e5-e25c-4545-b0d4-055b8e896071.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make install-kafka-cluster&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426118-81f29c6d-a30d-4408-9161-bb51e5b9b7d8.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Created topic details&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426204-bdfecea8-ebb1-4bf5-8a88-edf466106704.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;CODE:-&lt;/strong&gt; Code can be downloaded from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/tree/kafka_strimzi_kind_code&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-additional-info-on-using-zookeeper-configuraion&quot;&gt;Additional info on using Zookeeper configuraion&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;If the KRaft mode is disabled (environment variable &lt;code&gt;UseKraft&lt;/code&gt; is turned off), the configuration below can be used to deploy Kafka cluster that uses &lt;code&gt;Zookeeper&lt;/code&gt; to manage leader elections.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In that case &lt;code&gt;Makefile&lt;/code&gt; requires changes, remove the target that enables Kraft mode.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.2&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;internal&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;external&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nodeport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;configuration:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;brokers:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;offsets.topic.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.min.isr:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;default.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;min.insync.replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;inter.broker.protocol.version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;3.2&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zookeeper:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;entityOperator:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;topicOperator:&lt;/span&gt; {}    &lt;span class=&quot;hljs-attr&quot;&gt;userOperator:&lt;/span&gt; {}&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-deploy-kafka-cluster-in-kind-cluster&quot;&gt;Deploy Kafka cluster in KIND cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this article, I will explain to show how we can deploy Strimzi Kafka enabling KRaft mode in KIND cluster within the Docker desktop.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configuration defined in this article also shows how we can access Kafka broker from the host machine.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Prerequisites :&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Kubernetes and Operator patterns&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Apache Kafka&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Docker Desktop installed and running&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;KIND CLI installed&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;GNU Make 4.0 installed (for automation)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Apache Kafka Zookeeper Vs KRaft:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kafka community currently recommends using &lt;code&gt;Zookeeper&lt;/code&gt; for leader election in the production environment. Due to lots of limitations Kafka community is moving out of &lt;code&gt;Zookeeper&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;KRaft&lt;/code&gt; is new way by which Kafka manages quoram between multiple clusters.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Kraft&lt;/code&gt; is still an experimental feature and &lt;strong&gt;NOT&lt;/strong&gt; to be used in production yet.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Deploying Kafka in Kubernetes?&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;To deploy Kafka in Kubernetes the easiest option is Strimzi Apache Kafka Operator.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Strimzi&lt;/code&gt; Operators can be configured to deploy Kafka brokers in production.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;Strimzi&lt;/code&gt; is CNCF supported project.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Persistent datastore in &lt;code&gt;Strimzi&lt;/code&gt; has different options like,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Ephemeral&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;JBOD &lt;a target=&quot;_blank&quot; href=&quot;https://strimzi.io/blog/2019/07/08/persistent-storage-improvements/&quot;&gt;Just a Bunch Of Disks&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Persistent Volumes provided by any Cloud providers&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://strimzi.io/quickstarts/&quot;&gt;strimzi.io&lt;/a&gt; details the steps to deploy a persistent Kafka cluster in KIND.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-does-this-article-include&quot;&gt;What does this article include?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;We will deploy &lt;code&gt;Strimzi&lt;/code&gt; Kafka cluster with 3 brokers and Ephemeral type datastore. With ephemeral configuration, if the broker is destroyed the data will be lost.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;How to enables the experimental &lt;code&gt;KRaft&lt;/code&gt; mode in &lt;code&gt;Strimzi&lt;/code&gt; Operator.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;How we can access the Kafka brokers running in &lt;code&gt;KIND&lt;/code&gt; cluster from the host machine.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;In Windows machine to access the containers running &lt;code&gt;KIND&lt;/code&gt; cluster we need to forward the port, by updating the Strimzi cluster configuration.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; **INFO**&amp;gt; &amp;gt; *   Accessing &lt;span class=&quot;hljs-string&quot;&gt;`Strimzi Apache Kafka`&lt;/span&gt; brokers &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the outside &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; kubernetes cluster it requires bootstrap service to be exposed &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; NodePort. [Refer to &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; article that explains accessing Strimzi Kafka cluster &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; an external client](https:&lt;span class=&quot;hljs-comment&quot;&gt;//strimzi.io/blog/2019/04/23/accessing-kafka-part-2/)&lt;/span&gt;&amp;gt;     &lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-why-kraft-mode&quot;&gt;Why KRaft mode?&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The reason to use Kraft mode is on my laptop, deploying the Strimzi Kafka with &lt;code&gt;Zookeeper&lt;/code&gt; keeps on restarting the &lt;code&gt;Zookeeper&lt;/code&gt; and &lt;code&gt;Kafka Broker&lt;/code&gt; pods very often most of the time not accessible. I think this is because of memory limitations my laptop only had 8GB of memory.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;KRaft&lt;/code&gt; feature does create &lt;code&gt;Zookeeper&lt;/code&gt; pods.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Deploying Kafka in &lt;code&gt;KRaft&lt;/code&gt; mode with 3 brokers in &lt;code&gt;KIND&lt;/code&gt; cluster was always running successfully.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Noticed that when sending messages to the cluster with the console producer bat script there are retry error messages printed in console.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Since it is easy to spin up in a local machine we can use this to develop Kafka based applications locally.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;NOTE:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The same Strimzi Cluster configuration will work for &lt;code&gt;non- kRaft&lt;/code&gt; mode where &lt;code&gt;Zookeeper&lt;/code&gt; is used, the configuration requires including the &lt;code&gt;Entity operator&lt;/code&gt; and &lt;code&gt;Topic operator&lt;/code&gt; which can have empty values.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-steps-to-install-strimzi-apache-kafka-in-kind-cluster&quot;&gt;Steps to install Strimzi Apache Kafka in KIND cluster&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;1. Spin up the KIND cluster with the required port forward configuration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;2. Create a namespace called &lt;code&gt;kafka&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;3. Install the &lt;code&gt;Strimzi&lt;/code&gt; Operator (This can be done using Helm chart as well)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4. Enable &lt;code&gt;KRaft&lt;/code&gt; feature&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;5. Install the Strimzi cluster using the CRD configuration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;6. Create Topic using Strimzi CRD in the Kafka broker&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;7. Connect to Strimzi Kafka broker using Apache Kafka binary bat script&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Later in this article, we will see how to automate the process using GNU &lt;code&gt;make&lt;/code&gt; .&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-step-1-create-kind-cluster-with-port-forward-configuration&quot;&gt;Step 1: Create KIND cluster with port forward configuration&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;To create &lt;code&gt;Kind&lt;/code&gt; cluster we can use the below configuration which includes a list of port that forwards the network traffic to the cluster. Since we use GNU &lt;code&gt;make&lt;/code&gt;save this in a file named &lt;code&gt;kafka_kind_cluster.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;networking:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ipFamily:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ipv4&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerAddress:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;apiServerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;6443&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;If Docker Desktop is running, execute the below command to create &lt;code&gt;KIND&lt;/code&gt; cluster&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kind create cluster --name=kafka --config=kafka_kind_cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;docker ps&lt;/code&gt; will display the ports that forwards the traffic like below&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e5c4d36547af kindest/node:v1.25.2 &quot;/usr/local/bin/entr&quot; About an hour ago Up About an hour 127.0.0.1:6443-&amp;gt;6443/tcp, 127.0.0.1:31234-31236-&amp;gt;31234-31236/tcp, 127.0.0.1:9092-&amp;gt;31092/tcp kafka-control-plane&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-step-2-create-a-namespace&quot;&gt;Step 2: Create a namespace&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We can create the namespace in the cluster Imperatively using &lt;code&gt;kubectl&lt;/code&gt; command or Declaratively using YAML manifest.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl create ns kafka&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-3-install-strimzi-operator&quot;&gt;Step 3: Install Strimzi operator&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;Strimzi&lt;/code&gt; can also be installed using Helm chart as well, the steps are available in Strimzi documentation.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# namespace used is kafkakubectl create -f &apos;https://strimzi.io/install/latest?namespace=kafka&apos; -n kafka&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-4-enable-kraft-feature&quot;&gt;Step 4: Enable KRaft feature&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kraft mode requires the feature &lt;code&gt;UseStimziPodSets&lt;/code&gt; also to be enabled, since this feature is already enabled in &lt;code&gt;Strimzi Version 0.32.0&lt;/code&gt; no action is required.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The enable &lt;code&gt;Kraft&lt;/code&gt; mode we need to set the environment variable in Strimzi Operator. Before enabling the &lt;code&gt;KRaft&lt;/code&gt; feature we ned to make sure the Operator is in &lt;code&gt;Running&lt;/code&gt; status using &lt;code&gt;kubectl -n kafka get pods,svc,deployment&lt;/code&gt; command.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Executing the command below will enable the &lt;code&gt;KRaft&lt;/code&gt; feature in the operator eventually restarts it.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl -n kafka set env deployment/strimzi-cluster-operator STRIMZI_FEATURE_GATES=+UseKRaft&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-5-install-kafka-cluster-using-strimzi-crd-definition&quot;&gt;Step 5: Install Kafka cluster using Strimzi CRD definition&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;This section will detail the &lt;code&gt;Strimzi&lt;/code&gt; CRD to define Kafka cluster configuration that will spin up &lt;code&gt;3 brokers&lt;/code&gt; with &lt;code&gt;Ephemeral&lt;/code&gt; type storage.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;The listener configuration exposes the service as NodePort with the specified port.&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;name: externaltype: NodePortport: 9094&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;When the Kafka client connects to the broker the bootstrap server sends the list of brokers with the leader info, by using &lt;code&gt;advertisedHost: 127.0.0.1&lt;/code&gt; the host machine can connect to the broker.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Additionally, these broker ports are used in the KIND cluster configuration to forward the traffic to Kafka broker.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The configuration below still specifies the Zookeeper details since KRaft is an experimental feature. We don&apos;t need to specify the &lt;code&gt;Entity Operator&lt;/code&gt; and &lt;code&gt;Topic Operator&lt;/code&gt; for KRaft mode.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;The configuration below defines 3 brokers, expose service as Nodeport and Storage type as Ephemeral. Save the content to file &lt;code&gt;kraftmode.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.2&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;internal&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;external&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nodeport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;configuration:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;brokers:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31235&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31236&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;offsets.topic.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.min.isr:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;default.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;min.insync.replication:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;inter.broker.protocol.version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;3.2&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zookeeper:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Once &lt;code&gt;Kraft&lt;/code&gt; feature is enabled and the &lt;code&gt;Strimzi&lt;/code&gt; operator is in &lt;code&gt;Running&lt;/code&gt; state, execute the command below to deploy the Kafka cluster.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kubectl -n kafka apply -f kraftMode.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To track the status of the resource execute the command below.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kafka -n kafka get pods,deploy,svc&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-6-create-topic-using-strimzi-crd&quot;&gt;Step 6: Create Topic using Strimzi CRD&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The configuration to create a Topic using the CRD is listed below, save the content to a file named topic.yaml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;KafkaTopic&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-demo&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-app&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;strimzi.io/cluster:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;topicName:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;example-demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;partitions:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To create the topic and view the details of the created topic use the commands below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# to create the topickubectl -n kafka apply -f topic.yaml# to view the created topickubectl -n kafka get kafkatopics&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-step-7-access-the-kafka-cluster&quot;&gt;Step 7: Access the Kafka cluster&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;We can access the kafka broker using any Kafka client, the bootstrap server now is accessible via &lt;code&gt;localhost:9092&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Download the binaries from &lt;code&gt;Apache kafka&lt;/code&gt; website, and use the &lt;code&gt;kafka-console-producer.bat&lt;/code&gt;, &lt;code&gt;kafka-topic.bat&lt;/code&gt;, etc. to connect the brokers.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The command below uses the producer script to send messages.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;kafka-console-producer.bat --bootstrap-server localhost:9092 --topic example-demo aks=all&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;# once messages are sent we can list the topic with below commandkafka-topic.bat --bootstrap-server localhost:9092 --list&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-using-the-makefile&quot;&gt;Using the Makefile&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;Makefile&lt;/code&gt; below automates part of the process of &lt;code&gt;deploying the operator&lt;/code&gt;, &lt;code&gt;creating the cluster&lt;/code&gt; and &lt;code&gt;deleting the kind cluster&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Save below content in a file called &lt;code&gt;Makefile&lt;/code&gt;, make sure the recipe under the target starts with a &lt;code&gt;tab space&lt;/code&gt; else make command will error out.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;This &lt;code&gt;Makefile&lt;/code&gt; contains additional targets like &lt;code&gt;installing kind cli&lt;/code&gt; and &lt;code&gt;install kubectl&lt;/code&gt;, etc. but this only works on Linux machines.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;SHELL :=/bin/bashNAMESPACE ?= kafkaCLUSTERNAME ?= kafkaSLEEPSEC ?= 5000#KAFKAEPHEMERALCONFIG := kafka-ephemeral-single.yamlKAFKAEPHEMERALCONFIG := kraftmode.yamlKAFKACLUSTER := kafka_kind_cluster.yaml.DEFAULT_GOAL :=info.PHONY: install-kind-linuxinstall-kind-linux:     @curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.17.0/kind-linux-amd64     @chmod +x ./kind     @mv ./kind /usr/local/bin/kind     @chmod +x /usr/local/bin/kind  .PHONY: install-kubectlinstall-kubectl:     @curl -LO &quot;https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl&quot;    @chmod +x kubectl     @mkdir -p ~/.local/bin     @mv ./kubectl /usr/local/bin/kubectl     @chmod +x /usr/local/bin/kubectl.PHONY: install-clusterinstall-cluster:    @kind create cluster --name=${CLUSTERNAME} --config=./${KAFKACLUSTER}.PHONY: create-namespacecreate-namespace:    @kubectl create ns ${NAMESPACE}.PHONY: install-operatorinstall-operator:    @kubectl create -f &apos;https://strimzi.io/install/latest?namespace=${NAMESPACE}&apos; -n ${NAMESPACE}.PHONY: list-resourcelist-resource:    @kubectl -n kafka get pods,svc.PHONY: wait-zzwait-zz: # sleep 5 second    @echo &quot;waiting....&quot; \    sleep ${SLEEPSEC}.PHONY: delete-kind-clusterdelete-kind-cluster: ; @kind delete cluster --name=${CLUSTERNAME}.PHONY: install-kafka-clusterinstall-kafka-cluster: enable-kraft-feature wait-zz    @kubectl -n ${NAMESPACE} apply -f ${KAFKAEPHEMERALCONFIG}    @sleep ${SLEEPSEC}.PHONY: enable-kraft-featureenable-kraft-feature:     kubectl -n ${NAMESPACE} set env deployment/strimzi-cluster-operator STRIMZI_FEATURE_GATES=+UseKRaft.PHONY: deploy-operatordeploy-operator: install-cluster create-namespace install-operator wait-zz list-resource    @echo &quot;installing kafka&quot;.PHONY: kafka-producerkafka-producer:     echo &quot;kafka producer starting up...&quot;    @kubectl -n kafka run kafka-producer -ti --image=quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 --rm=true --restart=Never -- bin/kafka-console-producer.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 --topic my-topic.PHONY: kafka-consumerkafka-consumer:     echo &quot;kafka consumer starting to listen...&quot;    @kubectl -n kafka run kafka-consumer -ti --image=quay.io/strimzi/kafka:0.32.0-kafka-3.3.1 --rm=true --restart=Never -- bin/kafka-console-consumer.sh --bootstrap-server my-cluster-kafka-bootstrap:9092 --topic my-topic --from-beginninginfo:    @awk &apos;/^[a-zA-Z_-]+: / { print $$0; print &quot;\n&quot;}&apos; $(MAKEFILE_LIST) | \    awk -F&quot;:&quot; &apos;BEGIN {print &quot;targets&quot; } /^[a-zA-Z_-]+/ {print &quot;    &quot;$$1}&apos;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-using-makefile-targets&quot;&gt;Using Makefile Targets&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Executing the command &lt;code&gt;make&lt;/code&gt; will list the target names.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Step 1: To deploy the operator use command, &lt;code&gt;make deploy-operator&lt;/code&gt;,&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Step 2: Once the &lt;code&gt;Strimzi&lt;/code&gt; operator status is &lt;code&gt;Running&lt;/code&gt;. Execute &lt;code&gt;make install-kafka-cluster&lt;/code&gt; command to install the cluster. This will enable the &lt;code&gt;KRaft&lt;/code&gt; feature and install the cluster with the configuration.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note: Make sure the file name matches and all files are in the same directory.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make deploy-operator&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426061-1df530e5-e25c-4545-b0d4-055b8e896071.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make install-kafka-cluster&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426118-81f29c6d-a30d-4408-9161-bb51e5b9b7d8.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Created topic details&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/205426204-bdfecea8-ebb1-4bf5-8a88-edf466106704.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;CODE:-&lt;/strong&gt; Code can be downloaded from &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/thirumurthis/projects/tree/kafka_strimzi_kind_code&quot;&gt;Github&lt;/a&gt;.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-additional-info-on-using-zookeeper-configuraion&quot;&gt;Additional info on using Zookeeper configuraion&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;If the KRaft mode is disabled (environment variable &lt;code&gt;UseKraft&lt;/code&gt; is turned off), the configuration below can be used to deploy Kafka cluster that uses &lt;code&gt;Zookeeper&lt;/code&gt; to manage leader elections.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In that case &lt;code&gt;Makefile&lt;/code&gt; requires changes, remove the target that enables Kraft mode.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka.strimzi.io/v1beta2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;my-cluster&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kafka&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;kafka:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3.2&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listeners:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;plain&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9092&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;internal&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;external&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nodeport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;tls:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;configuration:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;bootstrap:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31092&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;brokers:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;broker:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;advertisedHost:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.1&lt;/span&gt;              &lt;span class=&quot;hljs-attr&quot;&gt;nodePort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;31234&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;offsets.topic.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;transaction.state.log.min.isr:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;default.replication.factor:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;min.insync.replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;inter.broker.protocol.version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;3.2&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;zookeeper:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;storage:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ephemeral&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;entityOperator:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;topicOperator:&lt;/span&gt; {}    &lt;span class=&quot;hljs-attr&quot;&gt;userOperator:&lt;/span&gt; {}&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Build Custom Kustomize Plugin With Containerized KRM function]]></title><description><![CDATA[use KRM function to build custom plugin in kustomize]]></description><link>https://thirumurthi.hashnode.dev/build-custom-kustomize-plugin-with-containerized-krm-function</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/build-custom-kustomize-plugin-with-containerized-krm-function</guid><category><![CDATA[Kustomize]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 26 Nov 2022 22:54:18 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-develop-kustomize-custom-plugin-with-containerized-krm-function-using-go&quot;&gt;Develop Kustomize custom plugin with containerized KRM function using Go&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog we will see how to develop custom plugin for Kustomize using containers KRM function. &lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The customized plugin in this blog, will add annotation with specified key and value to set of resources mentioned under the &lt;code&gt;target:&lt;/code&gt; tag of the &lt;code&gt;functionCondig:&lt;/code&gt;. The annotation information will be defined in a YAML file and referred in the &lt;code&gt;kustomization.yaml&lt;/code&gt; configuration using &lt;code&gt;transformers:&lt;/code&gt; tag. Some of this information might be not clear at this step.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of kubernetes and deploying resources using YAML manifest&lt;/li&gt;&lt;li&gt;Basic understanding of GO Lang. Installed locally for development. VS Code with Go plugin is easy to configure an use as IDE.&lt;/li&gt;&lt;li&gt;Docker desktop installed &lt;/li&gt;&lt;li&gt;Kustomize CLI installed&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To understand what Kustomize is and how to use to mange manifest check my previous blog &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;link here&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-how-kustomize-plugin-works&quot;&gt;How Kustomize plugin works?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;With containerized KRM function kustomize framework will read the manifest and generate all resource into as Kubernetes resource ResourceList.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ResourceList is further utilized by the framework by passing it to Generators and transformer pipeline finally rendering  the manifest.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kustomize provides &lt;code&gt;kyaml&lt;/code&gt; framework which is used to parse the ResourceList manifest in Go Language&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-work-flow&quot;&gt;Work flow&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Using &lt;code&gt;kyaml&lt;/code&gt; Go framework build the custom plugin with necessary logic.&lt;/li&gt;&lt;li&gt;Create container image, and push to docker hub or private image registry.&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create a transformer yaml file with the configuration required for the plugin logic. The container reference will be provided in this file as annotation.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below is sample transformers file were the image is referenced.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;transformers.example.co/v1&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# any name that is unique&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ValueAnnotator&lt;/span&gt;                   &lt;span class=&quot;hljs-comment&quot;&gt;# any name to identify as transformer&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;notImportantHere&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config.kubernetes.io/function:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|      container:        image: example.docker.com/my-functions/valueannotator:1.0.0  # container image name&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;important-data&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The transformer file should be reference in the &lt;code&gt;kustomization.yaml&lt;/code&gt; configuration using &lt;code&gt;transformer:&lt;/code&gt; tag&lt;/p&gt;&lt;/li&gt;&lt;li&gt;The Kustomize framework will use this file and send it as stdin to the container, the output manifest will be updated with the logic defined in containre code.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kustomize-krm-function&quot;&gt;Kustomize KRM function&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;Kustomize documentation&lt;/a&gt; explains an example on adding annotation value to resources. This blog uses the same approach but shows how to debug the code during development with a test case.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Kustomize provides a kyaml framework in GO language, with which we can build the custom plugin.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204107814-84c8d9fa-b41d-4f3f-bd64-c5a014eee065.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-plugin-development&quot;&gt;Plugin development:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;For local development we use a sample YAML which defines Kubernetes ResourceList type.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Since the kustomize framework uses the data under the &lt;code&gt;functionConfig:&lt;/code&gt; tag of the ResourseList resource as input to the container in stdin, we define the inputs to which set of resources the annotation value needs to be added.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;In the below yaml, we have defined the annotation value &lt;code&gt;holder: sample-io/add&lt;/code&gt; this will be added to ConfigMap and Service resources only, not to &lt;code&gt;kind: Deployment&lt;/code&gt; listed in the &lt;code&gt;items&lt;/code&gt; tag&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;config.kubernetes.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ResourceList&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;functionConfig:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotationList:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;applyAnnotationTo:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;holder&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;webconfig&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;websvc&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ClusterIP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;svcport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5000&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;fe-deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:1.14.2&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-go-project-setup&quot;&gt;Go project setup&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To initialize Go workspace from scratch, create a folder and issue &lt;code&gt;go mod init&lt;/code&gt; command. This will create &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; files.&lt;/li&gt;&lt;li&gt;In below example I created a folder named &lt;code&gt;project&lt;/code&gt; and the source code under folder named &lt;code&gt;source&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the project directory issued below command# &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; my project structure&amp;gt; go mod init source &amp;gt; go mod tiny&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;For developing test case installed testing and yaml package, for which issued below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the project directory&amp;gt; go get gopkg.in/yaml.v3&amp;gt; go get github.com/stretchr/testify/assert&amp;gt; go mod tidy&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Code Logic&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;struct&lt;/code&gt; type defined in the code represents information under the &lt;code&gt;functionConfig&lt;/code&gt; property. &lt;/li&gt;&lt;li&gt;The kyaml framework parse and injects the YAML data in the function argument that is passed to the Filter function. Our core logic should defined in this function and passed to the processor.&lt;/li&gt;&lt;li&gt;With the list of items passed by the kyaml framework, with the information under the &lt;code&gt;functionConfig&lt;/code&gt; we filter the matching resource and add the annotation with the specified key and value.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The code main() function has &lt;code&gt;runAsCommand&lt;/code&gt; with true will execute the code  block that can generates Dockerfile automatically with the command &lt;code&gt;go run kustomizePlugin.go gen .&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Below code can generate the Dockerfile for us&lt;pre&gt;&lt;code&gt;cmd := command.Build(p, command.StandaloneDisabled, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;//automatically generates the Dockerfile for us&lt;/span&gt;command.AddGenerateDockerfile(cmd)&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := cmd.Execute(); err != nil {     os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;framework.Execute()&lt;/code&gt; takes reader and writer object and the the ResourceList YAML file can be read and passed as input. Make development easy&lt;pre&gt;&lt;code&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; error := framework.Execute(p, byteReadWriter); error != nil {   panic(error) }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Code with the custom plugin logic, save this file as &lt;code&gt;kustomizePlugin.go&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;os&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/fn/framework&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/fn/framework/command&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/kio&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/yaml&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; AnnotationConfig &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Target framework.Selector &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;target,omitempty&quot;`&lt;/span&gt;    Key    &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;key,omitempty&quot;`&lt;/span&gt;    Value  &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;value,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; AnnotationConfigs &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    AnnotationList []AnnotationConfig &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;annotationList,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(byteReadWriter *kio.ByteReadWriter, runAsCommand &lt;span class=&quot;hljs-keyword&quot;&gt;bool&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {    config := &lt;span class=&quot;hljs-built_in&quot;&gt;new&lt;/span&gt;(AnnotationConfigs)    &lt;span class=&quot;hljs-comment&quot;&gt;//function that will be passed to the kustomize framework execute function&lt;/span&gt;    fn := &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(items []*yaml.RNode)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;([]*yaml.RNode, error)&lt;/span&gt;&lt;/span&gt; {        &lt;span class=&quot;hljs-comment&quot;&gt;// string data type null check&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; config.AnnotationList == &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; || &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(config.AnnotationList) == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, fmt.Errorf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;value is required and can&apos;t be empty&quot;&lt;/span&gt;)        }        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, annotationConfig := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; config.AnnotationList {            filterItemsByResourceType, err := annotationConfig.Target.Filter(items)            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, err            }            &lt;span class=&quot;hljs-comment&quot;&gt;// the range returns index, actual object&lt;/span&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// PipeE function is from the kyaml framework&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, filterResource := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; filterItemsByResourceType {                err := filterResource.PipeE(yaml.SetAnnotation(annotationConfig.Key, annotationConfig.Value))                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, err                }            }        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }    &lt;span class=&quot;hljs-comment&quot;&gt;// create a processor using the which will hold the actual logic of filtering the&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// resources in the -items of the resourceList and creates annotation to matching &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// resource defined in the functionConfig section&lt;/span&gt;    p := framework.SimpleProcessor{Config: config, Filter: kio.FilterFunc(fn)}    &lt;span class=&quot;hljs-comment&quot;&gt;/*        framework.Execute() is the entrypoint for invoking configuration functions built        with this framework from code. Execute reads a ResourceList        from the given source, passes it to a ResourceListProcessor,        and then writes the result to the target.        STDIN and STDOUT will be used if no reader or writer respectively is provided.    */&lt;/span&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; !runAsCommand {    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; error := framework.Execute(p, byteReadWriter); error != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {      &lt;span class=&quot;hljs-built_in&quot;&gt;panic&lt;/span&gt;(error)    }  }        &lt;span class=&quot;hljs-comment&quot;&gt;/*      With the below code it would be difficult to debug the code in local (IMO)      We can pass in the input directly, with execute we can pass the reader and writer      So I have used a flag to NOT run this block of code       But the kustomize documentation demonstrates this approach    */&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; runAsCommand {        &lt;span class=&quot;hljs-comment&quot;&gt;/*         command.Build() returns a cobra.Command to run a function.         The cobra.Command reads the input from STDIN, invokes the provided processor,         and then writes the output to STDOUT.        */&lt;/span&gt;        cmd := command.Build(p, command.StandaloneDisabled, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)        &lt;span class=&quot;hljs-comment&quot;&gt;//automatically generates the Dockerfile for us&lt;/span&gt;        command.AddGenerateDockerfile(cmd)        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := cmd.Execute(); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)        }    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(e error)&lt;/span&gt;&lt;/span&gt; {    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; e != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        fmt.Print(e)        &lt;span class=&quot;hljs-built_in&quot;&gt;panic&lt;/span&gt;(e)    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    runAsCommand := &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    byteReadWriter := &amp;amp;kio.ByteReadWriter{}    process(byteReadWriter, runAsCommand)}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Test case to validate the output&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;bytes&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;log&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;os&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;strings&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;testing&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;github.com/stretchr/testify/assert&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;gopkg.in/yaml.v3&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/kio&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;/*to install yaml packagego get gopkg.in/yaml.v3go get github.com/stretchr/testify/assertgo mod tidy*/&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;TestAnnotationPlugin&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(t *testing.T)&lt;/span&gt;&lt;/span&gt; {    runAsCommand := &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    inputFile, err := os.Open(&lt;span class=&quot;hljs-string&quot;&gt;&quot;resources.yaml&quot;&lt;/span&gt;)    outputFile := bytes.Buffer{}    check(err)    fmt.Print(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reading file..&quot;&lt;/span&gt;)    byteReadWriter := &amp;amp;kio.ByteReadWriter{        Reader: inputFile,        Writer: &amp;amp;outputFile,    }    process(byteReadWriter, runAsCommand)    outputAsStr := strings.TrimSpace(outputFile.String())    fmt.Println(outputAsStr)    readYamlStr := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{}]&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{})    err2 := yaml.Unmarshal([]&lt;span class=&quot;hljs-keyword&quot;&gt;byte&lt;/span&gt;(outputAsStr), &amp;amp;readYamlStr)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err2 != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Fatal(err2)    }    substr := &lt;span class=&quot;hljs-string&quot;&gt;&quot;holder: sample-io/add&quot;&lt;/span&gt;    configMap := &lt;span class=&quot;hljs-string&quot;&gt;&quot;ConfigMap&quot;&lt;/span&gt;    service := &lt;span class=&quot;hljs-string&quot;&gt;&quot;Service&quot;&lt;/span&gt;    deployment := &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deployment&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// initialize a map&lt;/span&gt;    output := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;bool&lt;/span&gt;)    output[configMap] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    output[service] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    output[deployment] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; k, v := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; readYamlStr {        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; k == &lt;span class=&quot;hljs-string&quot;&gt;&quot;items&quot;&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, value := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; v.([]&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{}) {                manifest, err := yaml.Marshal(&amp;amp;value)                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                    log.Fatalf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;error: %v&quot;&lt;/span&gt;, err)                }                &lt;span class=&quot;hljs-comment&quot;&gt;//fmt.Printf(&quot;---:\n%s\n\n&quot;, string(manifest))&lt;/span&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), substr) &amp;amp;&amp;amp;                    (strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), service) ||                        strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), configMap)) {                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), configMap) {                        output[configMap] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;                    }                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), service) {                        output[service] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;                    }                }            }        }    }    assert.True(t, output[service])    assert.True(t, output[configMap])    assert.False(t, output[deployment])    &lt;span class=&quot;hljs-keyword&quot;&gt;defer&lt;/span&gt; inputFile.Close()}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-run-go-program&quot;&gt;Run Go program&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use below command to run the Go code, which will also generate the Dockerfile only when the function &lt;code&gt;main()&lt;/code&gt; &lt;code&gt;runAsCommand&lt;/code&gt; is set to true.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; go run kustomizePlugin.go gen .&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Dockerfile generated and updated to create the image&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt; Additional note :-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Move the Dockerfile generated under &lt;code&gt;source&lt;/code&gt; folder to &lt;code&gt;project&lt;/code&gt; folder. &lt;/li&gt;&lt;li&gt;The &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; is under the &lt;code&gt;project&lt;/code&gt; directory and these files  are move to the image during creation process&lt;/li&gt;&lt;li&gt;Update the Docker &lt;code&gt;COPY&lt;/code&gt; command to copy only the file &lt;code&gt;source/kustomizePlugin.go&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code&gt;FROM golang:&lt;span class=&quot;hljs-number&quot;&gt;1.19&lt;/span&gt;-alpine &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; builderENV CGO_ENABLED=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;WORKDIR /go/src/COPY go.mod go.sum /go/src/RUN go mod download# update the path where the kustmizePlugin.go code is presentCOPY ./source/kustomizePlugin.go .RUN go build -ldflags &lt;span class=&quot;hljs-string&quot;&gt;&apos;-w -s&apos;&lt;/span&gt; -v -o /usr/local/bin/&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; ./&lt;span class=&quot;hljs-title&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;alpine&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;hljs-title&quot;&gt;COPY&lt;/span&gt; --&lt;span class=&quot;hljs-title&quot;&gt;from&lt;/span&gt;=&lt;span class=&quot;hljs-title&quot;&gt;builder&lt;/span&gt; /&lt;span class=&quot;hljs-title&quot;&gt;usr&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;local&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;bin&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt; /&lt;span class=&quot;hljs-title&quot;&gt;usr&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;local&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;bin&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;hljs-title&quot;&gt;ENTRYPOINT&lt;/span&gt; [&quot;&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt;&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Docker command to generate the image, in below example it mage is only pushed to local Docker Desktop&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; docker build -t kustomize_dev:&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; .&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-using-the-krm-function-custom-plugin-container&quot;&gt;Using the KRM function custom plugin container&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Once the image is created successfully, we can add a &lt;code&gt;prod&lt;/code&gt; folder under &lt;code&gt;overlay&lt;/code&gt; check my previous blog &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;link&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay\prod\annotationTransformer.yaml&lt;/code&gt; defining the input to wich resource the annotation should be added. In this case to service only&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;transformers.customplugin.co/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ResourceAnnotator&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-plugin&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config.kubernetes.io/function:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|      container:        image:  kustomize_dev:1.0.0&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;annotationList:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;applyToResources:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;holder&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay\prod\kustomization.yaml&lt;/code&gt; reference the transformer file path&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-prod&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# reference the path of the transformer file that uses the container&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;transformers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;annotationTransformer.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To render the manifest file for prod with below command&lt;/li&gt;&lt;li&gt;By default the custom plugins can&apos;t be used with kustomize CLI, we need to use &lt;code&gt;--enable-alpha-plugins&lt;/code&gt; option&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; kustomize build --enable-alpha-plugins prod\&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Rendered prod yaml file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;holder:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-prod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;holder:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-prod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-bonus&quot;&gt;Bonus&lt;/h2&gt;&lt;h3 id=&quot;heading-basics-of-go-language&quot;&gt;Basics of Go Language&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Go Lang program should be defined within main package, function main()  is the entry point&lt;/li&gt;&lt;li&gt;Go Lang statement doesn&apos;t require any delimiter like semicolon used in Java&lt;ul&gt;&lt;li&gt;By including the brackets at end of the function or block of code compiler will be identifying it as function or block. Refer below code example&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The function name first char uppercase indicates it is public function, lowercase is private function.&lt;/li&gt;&lt;li&gt;&lt;code&gt;struct&lt;/code&gt; is a used to define custom data type in Go&lt;/li&gt;&lt;li&gt;&lt;p&gt;The code below also includes a testcase which uses YAML Go library&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We don&apos;t define any data type to unmarshall the generated Kubernetes manifest, we use map of interface and iterate and assert based on the required output.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-comment&quot;&gt;// we need to import the package using below syntax,&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// fmt package contains utilities to print to stdout like print&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt;( &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// as mentioned above the function main should end with bracket { &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// else Go will report error&lt;/span&gt;function main(){&lt;span class=&quot;hljs-comment&quot;&gt;// alternate use of below code is var output = 0 &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// use := to initialize variable with value&lt;/span&gt;output := &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i := &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;; i++ {    &lt;span class=&quot;hljs-comment&quot;&gt;// use = to reassign values&lt;/span&gt;    output = output + i}&lt;span class=&quot;hljs-comment&quot;&gt;// in order to make any function in package to be public&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//the first char shoud be upper case&lt;/span&gt;fmt.Println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sum :-&quot;&lt;/span&gt;, output)fmt.Printf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sum:- %d&quot;&lt;/span&gt;, output)  }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-develop-kustomize-custom-plugin-with-containerized-krm-function-using-go&quot;&gt;Develop Kustomize custom plugin with containerized KRM function using Go&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog we will see how to develop custom plugin for Kustomize using containers KRM function. &lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The customized plugin in this blog, will add annotation with specified key and value to set of resources mentioned under the &lt;code&gt;target:&lt;/code&gt; tag of the &lt;code&gt;functionCondig:&lt;/code&gt;. The annotation information will be defined in a YAML file and referred in the &lt;code&gt;kustomization.yaml&lt;/code&gt; configuration using &lt;code&gt;transformers:&lt;/code&gt; tag. Some of this information might be not clear at this step.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Pre-requisites:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of kubernetes and deploying resources using YAML manifest&lt;/li&gt;&lt;li&gt;Basic understanding of GO Lang. Installed locally for development. VS Code with Go plugin is easy to configure an use as IDE.&lt;/li&gt;&lt;li&gt;Docker desktop installed &lt;/li&gt;&lt;li&gt;Kustomize CLI installed&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;To understand what Kustomize is and how to use to mange manifest check my previous blog &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;link here&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-how-kustomize-plugin-works&quot;&gt;How Kustomize plugin works?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;With containerized KRM function kustomize framework will read the manifest and generate all resource into as Kubernetes resource ResourceList.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The ResourceList is further utilized by the framework by passing it to Generators and transformer pipeline finally rendering  the manifest.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Kustomize provides &lt;code&gt;kyaml&lt;/code&gt; framework which is used to parse the ResourceList manifest in Go Language&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-work-flow&quot;&gt;Work flow&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Using &lt;code&gt;kyaml&lt;/code&gt; Go framework build the custom plugin with necessary logic.&lt;/li&gt;&lt;li&gt;Create container image, and push to docker hub or private image registry.&lt;/li&gt;&lt;li&gt;&lt;p&gt;Create a transformer yaml file with the configuration required for the plugin logic. The container reference will be provided in this file as annotation.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below is sample transformers file were the image is referenced.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;transformers.example.co/v1&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# any name that is unique&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ValueAnnotator&lt;/span&gt;                   &lt;span class=&quot;hljs-comment&quot;&gt;# any name to identify as transformer&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;notImportantHere&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config.kubernetes.io/function:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|      container:        image: example.docker.com/my-functions/valueannotator:1.0.0  # container image name&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&apos;important-data&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The transformer file should be reference in the &lt;code&gt;kustomization.yaml&lt;/code&gt; configuration using &lt;code&gt;transformer:&lt;/code&gt; tag&lt;/p&gt;&lt;/li&gt;&lt;li&gt;The Kustomize framework will use this file and send it as stdin to the container, the output manifest will be updated with the logic defined in containre code.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kustomize-krm-function&quot;&gt;Kustomize KRM function&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;Kustomize documentation&lt;/a&gt; explains an example on adding annotation value to resources. This blog uses the same approach but shows how to debug the code during development with a test case.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Kustomize provides a kyaml framework in GO language, with which we can build the custom plugin.&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204107814-84c8d9fa-b41d-4f3f-bd64-c5a014eee065.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h4 id=&quot;heading-plugin-development&quot;&gt;Plugin development:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;For local development we use a sample YAML which defines Kubernetes ResourceList type.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Since the kustomize framework uses the data under the &lt;code&gt;functionConfig:&lt;/code&gt; tag of the ResourseList resource as input to the container in stdin, we define the inputs to which set of resources the annotation value needs to be added.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;In the below yaml, we have defined the annotation value &lt;code&gt;holder: sample-io/add&lt;/code&gt; this will be added to ConfigMap and Service resources only, not to &lt;code&gt;kind: Deployment&lt;/code&gt; listed in the &lt;code&gt;items&lt;/code&gt; tag&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;config.kubernetes.io/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ResourceList&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;functionConfig:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotationList:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;applyAnnotationTo:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;holder&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;items:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ConfigMap&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;webconfig&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;websvc&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;namespace:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ClusterIP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;svcport&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5000&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;fe-deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;   &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;          &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:1.14.2&lt;/span&gt;            &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;            &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-go-project-setup&quot;&gt;Go project setup&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To initialize Go workspace from scratch, create a folder and issue &lt;code&gt;go mod init&lt;/code&gt; command. This will create &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; files.&lt;/li&gt;&lt;li&gt;In below example I created a folder named &lt;code&gt;project&lt;/code&gt; and the source code under folder named &lt;code&gt;source&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the project directory issued below command# &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; my project structure&amp;gt; go mod init source &amp;gt; go mod tiny&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;For developing test case installed testing and yaml package, for which issued below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; the project directory&amp;gt; go get gopkg.in/yaml.v3&amp;gt; go get github.com/stretchr/testify/assert&amp;gt; go mod tidy&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Code Logic&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;struct&lt;/code&gt; type defined in the code represents information under the &lt;code&gt;functionConfig&lt;/code&gt; property. &lt;/li&gt;&lt;li&gt;The kyaml framework parse and injects the YAML data in the function argument that is passed to the Filter function. Our core logic should defined in this function and passed to the processor.&lt;/li&gt;&lt;li&gt;With the list of items passed by the kyaml framework, with the information under the &lt;code&gt;functionConfig&lt;/code&gt; we filter the matching resource and add the annotation with the specified key and value.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Note:-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The code main() function has &lt;code&gt;runAsCommand&lt;/code&gt; with true will execute the code  block that can generates Dockerfile automatically with the command &lt;code&gt;go run kustomizePlugin.go gen .&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Below code can generate the Dockerfile for us&lt;pre&gt;&lt;code&gt;cmd := command.Build(p, command.StandaloneDisabled, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;//automatically generates the Dockerfile for us&lt;/span&gt;command.AddGenerateDockerfile(cmd)&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := cmd.Execute(); err != nil {     os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)}&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;framework.Execute()&lt;/code&gt; takes reader and writer object and the the ResourceList YAML file can be read and passed as input. Make development easy&lt;pre&gt;&lt;code&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; error := framework.Execute(p, byteReadWriter); error != nil {   panic(error) }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Code with the custom plugin logic, save this file as &lt;code&gt;kustomizePlugin.go&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;os&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/fn/framework&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/fn/framework/command&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/kio&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/yaml&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; AnnotationConfig &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    Target framework.Selector &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;target,omitempty&quot;`&lt;/span&gt;    Key    &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;key,omitempty&quot;`&lt;/span&gt;    Value  &lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;             &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;value,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; AnnotationConfigs &lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; {    AnnotationList []AnnotationConfig &lt;span class=&quot;hljs-string&quot;&gt;`yaml:&quot;annotationList,omitempty&quot;`&lt;/span&gt;}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(byteReadWriter *kio.ByteReadWriter, runAsCommand &lt;span class=&quot;hljs-keyword&quot;&gt;bool&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; {    config := &lt;span class=&quot;hljs-built_in&quot;&gt;new&lt;/span&gt;(AnnotationConfigs)    &lt;span class=&quot;hljs-comment&quot;&gt;//function that will be passed to the kustomize framework execute function&lt;/span&gt;    fn := &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(items []*yaml.RNode)&lt;/span&gt; &lt;span class=&quot;hljs-params&quot;&gt;([]*yaml.RNode, error)&lt;/span&gt;&lt;/span&gt; {        &lt;span class=&quot;hljs-comment&quot;&gt;// string data type null check&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; config.AnnotationList == &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; || &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(config.AnnotationList) == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, fmt.Errorf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;value is required and can&apos;t be empty&quot;&lt;/span&gt;)        }        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, annotationConfig := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; config.AnnotationList {            filterItemsByResourceType, err := annotationConfig.Target.Filter(items)            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, err            }            &lt;span class=&quot;hljs-comment&quot;&gt;// the range returns index, actual object&lt;/span&gt;            &lt;span class=&quot;hljs-comment&quot;&gt;// PipeE function is from the kyaml framework&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, filterResource := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; filterItemsByResourceType {                err := filterResource.PipeE(yaml.SetAnnotation(annotationConfig.Key, annotationConfig.Value))                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;, err                }            }        }        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; items, &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt;    }    &lt;span class=&quot;hljs-comment&quot;&gt;// create a processor using the which will hold the actual logic of filtering the&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// resources in the -items of the resourceList and creates annotation to matching &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// resource defined in the functionConfig section&lt;/span&gt;    p := framework.SimpleProcessor{Config: config, Filter: kio.FilterFunc(fn)}    &lt;span class=&quot;hljs-comment&quot;&gt;/*        framework.Execute() is the entrypoint for invoking configuration functions built        with this framework from code. Execute reads a ResourceList        from the given source, passes it to a ResourceListProcessor,        and then writes the result to the target.        STDIN and STDOUT will be used if no reader or writer respectively is provided.    */&lt;/span&gt;  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; !runAsCommand {    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; error := framework.Execute(p, byteReadWriter); error != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {      &lt;span class=&quot;hljs-built_in&quot;&gt;panic&lt;/span&gt;(error)    }  }        &lt;span class=&quot;hljs-comment&quot;&gt;/*      With the below code it would be difficult to debug the code in local (IMO)      We can pass in the input directly, with execute we can pass the reader and writer      So I have used a flag to NOT run this block of code       But the kustomize documentation demonstrates this approach    */&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; runAsCommand {        &lt;span class=&quot;hljs-comment&quot;&gt;/*         command.Build() returns a cobra.Command to run a function.         The cobra.Command reads the input from STDIN, invokes the provided processor,         and then writes the output to STDOUT.        */&lt;/span&gt;        cmd := command.Build(p, command.StandaloneDisabled, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;)        &lt;span class=&quot;hljs-comment&quot;&gt;//automatically generates the Dockerfile for us&lt;/span&gt;        command.AddGenerateDockerfile(cmd)        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err := cmd.Execute(); err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {            os.Exit(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)        }    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(e error)&lt;/span&gt;&lt;/span&gt; {    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; e != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        fmt.Print(e)        &lt;span class=&quot;hljs-built_in&quot;&gt;panic&lt;/span&gt;(e)    }}&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt; {    runAsCommand := &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    byteReadWriter := &amp;amp;kio.ByteReadWriter{}    process(byteReadWriter, runAsCommand)}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Simple Test case to validate the output&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; (    &lt;span class=&quot;hljs-string&quot;&gt;&quot;bytes&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;log&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;os&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;strings&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;testing&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;github.com/stretchr/testify/assert&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;gopkg.in/yaml.v3&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-string&quot;&gt;&quot;sigs.k8s.io/kustomize/kyaml/kio&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;/*to install yaml packagego get gopkg.in/yaml.v3go get github.com/stretchr/testify/assertgo mod tidy*/&lt;/span&gt;&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;TestAnnotationPlugin&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(t *testing.T)&lt;/span&gt;&lt;/span&gt; {    runAsCommand := &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    inputFile, err := os.Open(&lt;span class=&quot;hljs-string&quot;&gt;&quot;resources.yaml&quot;&lt;/span&gt;)    outputFile := bytes.Buffer{}    check(err)    fmt.Print(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reading file..&quot;&lt;/span&gt;)    byteReadWriter := &amp;amp;kio.ByteReadWriter{        Reader: inputFile,        Writer: &amp;amp;outputFile,    }    process(byteReadWriter, runAsCommand)    outputAsStr := strings.TrimSpace(outputFile.String())    fmt.Println(outputAsStr)    readYamlStr := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{}]&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{})    err2 := yaml.Unmarshal([]&lt;span class=&quot;hljs-keyword&quot;&gt;byte&lt;/span&gt;(outputAsStr), &amp;amp;readYamlStr)    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err2 != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {        log.Fatal(err2)    }    substr := &lt;span class=&quot;hljs-string&quot;&gt;&quot;holder: sample-io/add&quot;&lt;/span&gt;    configMap := &lt;span class=&quot;hljs-string&quot;&gt;&quot;ConfigMap&quot;&lt;/span&gt;    service := &lt;span class=&quot;hljs-string&quot;&gt;&quot;Service&quot;&lt;/span&gt;    deployment := &lt;span class=&quot;hljs-string&quot;&gt;&quot;Deployment&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// initialize a map&lt;/span&gt;    output := &lt;span class=&quot;hljs-built_in&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;map&lt;/span&gt;[&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;]&lt;span class=&quot;hljs-keyword&quot;&gt;bool&lt;/span&gt;)    output[configMap] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    output[service] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    output[deployment] = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; k, v := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; readYamlStr {        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; k == &lt;span class=&quot;hljs-string&quot;&gt;&quot;items&quot;&lt;/span&gt; {            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _, value := &lt;span class=&quot;hljs-keyword&quot;&gt;range&lt;/span&gt; v.([]&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt;{}) {                manifest, err := yaml.Marshal(&amp;amp;value)                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; err != &lt;span class=&quot;hljs-literal&quot;&gt;nil&lt;/span&gt; {                    log.Fatalf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;error: %v&quot;&lt;/span&gt;, err)                }                &lt;span class=&quot;hljs-comment&quot;&gt;//fmt.Printf(&quot;---:\n%s\n\n&quot;, string(manifest))&lt;/span&gt;                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), substr) &amp;amp;&amp;amp;                    (strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), service) ||                        strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), configMap)) {                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), configMap) {                        output[configMap] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;                    }                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; strings.Contains(&lt;span class=&quot;hljs-keyword&quot;&gt;string&lt;/span&gt;(manifest), service) {                        output[service] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;                    }                }            }        }    }    assert.True(t, output[service])    assert.True(t, output[configMap])    assert.False(t, output[deployment])    &lt;span class=&quot;hljs-keyword&quot;&gt;defer&lt;/span&gt; inputFile.Close()}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-run-go-program&quot;&gt;Run Go program&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Use below command to run the Go code, which will also generate the Dockerfile only when the function &lt;code&gt;main()&lt;/code&gt; &lt;code&gt;runAsCommand&lt;/code&gt; is set to true.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; go run kustomizePlugin.go gen .&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Dockerfile generated and updated to create the image&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt; Additional note :-&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Move the Dockerfile generated under &lt;code&gt;source&lt;/code&gt; folder to &lt;code&gt;project&lt;/code&gt; folder. &lt;/li&gt;&lt;li&gt;The &lt;code&gt;go.mod&lt;/code&gt; and &lt;code&gt;go.sum&lt;/code&gt; is under the &lt;code&gt;project&lt;/code&gt; directory and these files  are move to the image during creation process&lt;/li&gt;&lt;li&gt;Update the Docker &lt;code&gt;COPY&lt;/code&gt; command to copy only the file &lt;code&gt;source/kustomizePlugin.go&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code&gt;FROM golang:&lt;span class=&quot;hljs-number&quot;&gt;1.19&lt;/span&gt;-alpine &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; builderENV CGO_ENABLED=&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;WORKDIR /go/src/COPY go.mod go.sum /go/src/RUN go mod download# update the path where the kustmizePlugin.go code is presentCOPY ./source/kustomizePlugin.go .RUN go build -ldflags &lt;span class=&quot;hljs-string&quot;&gt;&apos;-w -s&apos;&lt;/span&gt; -v -o /usr/local/bin/&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;function&lt;/span&gt; ./&lt;span class=&quot;hljs-title&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;alpine&lt;/span&gt;:&lt;span class=&quot;hljs-title&quot;&gt;latest&lt;/span&gt;&lt;span class=&quot;hljs-title&quot;&gt;COPY&lt;/span&gt; --&lt;span class=&quot;hljs-title&quot;&gt;from&lt;/span&gt;=&lt;span class=&quot;hljs-title&quot;&gt;builder&lt;/span&gt; /&lt;span class=&quot;hljs-title&quot;&gt;usr&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;local&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;bin&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt; /&lt;span class=&quot;hljs-title&quot;&gt;usr&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;local&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;bin&lt;/span&gt;/&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;hljs-title&quot;&gt;ENTRYPOINT&lt;/span&gt; [&quot;&lt;span class=&quot;hljs-title&quot;&gt;function&lt;/span&gt;&quot;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Docker command to generate the image, in below example it mage is only pushed to local Docker Desktop&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; docker build -t kustomize_dev:&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt; .&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-using-the-krm-function-custom-plugin-container&quot;&gt;Using the KRM function custom plugin container&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Once the image is created successfully, we can add a &lt;code&gt;prod&lt;/code&gt; folder under &lt;code&gt;overlay&lt;/code&gt; check my previous blog &lt;a target=&quot;_blank&quot; href=&quot;https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize&quot;&gt;link&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay\prod\annotationTransformer.yaml&lt;/code&gt; defining the input to wich resource the annotation should be added. In this case to service only&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;transformers.customplugin.co/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ResourceAnnotator&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-plugin&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;config.kubernetes.io/function:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|      container:        image:  kustomize_dev:1.0.0&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;annotationList:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;applyToResources:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;key:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;holder&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay\prod\kustomization.yaml&lt;/code&gt; reference the transformer file path&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-prod&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# reference the path of the transformer file that uses the container&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;transformers:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;annotationTransformer.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To render the manifest file for prod with below command&lt;/li&gt;&lt;li&gt;By default the custom plugins can&apos;t be used with kustomize CLI, we need to use &lt;code&gt;--enable-alpha-plugins&lt;/code&gt; option&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; kustomize build --enable-alpha-plugins prod\&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Rendered prod yaml file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;holder:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-prod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;annotations:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;holder:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sample-io/add&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-prod&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-bonus&quot;&gt;Bonus&lt;/h2&gt;&lt;h3 id=&quot;heading-basics-of-go-language&quot;&gt;Basics of Go Language&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Go Lang program should be defined within main package, function main()  is the entry point&lt;/li&gt;&lt;li&gt;Go Lang statement doesn&apos;t require any delimiter like semicolon used in Java&lt;ul&gt;&lt;li&gt;By including the brackets at end of the function or block of code compiler will be identifying it as function or block. Refer below code example&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;The function name first char uppercase indicates it is public function, lowercase is private function.&lt;/li&gt;&lt;li&gt;&lt;code&gt;struct&lt;/code&gt; is a used to define custom data type in Go&lt;/li&gt;&lt;li&gt;&lt;p&gt;The code below also includes a testcase which uses YAML Go library&lt;/p&gt;&lt;ul&gt;&lt;li&gt;We don&apos;t define any data type to unmarshall the generated Kubernetes manifest, we use map of interface and iterate and assert based on the required output.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-go&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; main&lt;span class=&quot;hljs-comment&quot;&gt;// we need to import the package using below syntax,&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// fmt package contains utilities to print to stdout like print&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt;( &lt;span class=&quot;hljs-string&quot;&gt;&quot;fmt&quot;&lt;/span&gt;)&lt;span class=&quot;hljs-comment&quot;&gt;// as mentioned above the function main should end with bracket { &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// else Go will report error&lt;/span&gt;function main(){&lt;span class=&quot;hljs-comment&quot;&gt;// alternate use of below code is var output = 0 &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// use := to initialize variable with value&lt;/span&gt;output := &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i := &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;; i++ {    &lt;span class=&quot;hljs-comment&quot;&gt;// use = to reassign values&lt;/span&gt;    output = output + i}&lt;span class=&quot;hljs-comment&quot;&gt;// in order to make any function in package to be public&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;//the first char shoud be upper case&lt;/span&gt;fmt.Println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sum :-&quot;&lt;/span&gt;, output)fmt.Printf(&lt;span class=&quot;hljs-string&quot;&gt;&quot;sum:- %d&quot;&lt;/span&gt;, output)  }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Manage Kubernetes Manifest with Kustomize]]></title><description><![CDATA[Blog to demonstrate the use of kustomize in managing Kubernetes resource manifests]]></description><link>https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/manage-kubernetes-manifest-with-kustomize</guid><category><![CDATA[Kubernetes]]></category><category><![CDATA[Kustomize]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 26 Nov 2022 08:32:27 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-manage-kubernetes-manifest-using-kustomize&quot;&gt;Manage Kubernetes manifest using Kustomize&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;In this blog have demonstrated, how we can use Kustomize to manage Kubernetes manifest with simple example and also how to render Kubernetes manifest using Kustomize CLI.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes and how resources are deployed using yaml&lt;ul&gt;&lt;li&gt;Kustomize CLI installed in the machine. To install refer the &lt;a target=&quot;_blank&quot; href=&quot;https://kubectl.docs.kubernetes.io/installation/kustomize/&quot;&gt;documentation&lt;/a&gt; for more details&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-kustomize&quot;&gt;What is Kustomize?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kustomize provides a solution for customizing Kubernetes resource configuration free from templates and DSLs. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kustomize.io/&quot;&gt;kustomize.io&lt;/a&gt;&lt;ul&gt;&lt;li&gt;Kustomize lets you customize raw, template-free YAML files for multiple purposes, leaving the original YAML untouched and usable as is.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt; client already supports kustomize&lt;/li&gt;&lt;li&gt;Kustomize configuration can applied directly to Kubernetes cluster using &lt;code&gt;kubectl apply -k &amp;lt;directory\to\kustomization.yaml&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-high-level-overview&quot;&gt;High level overview&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In enterprise project to deploy the application into Kubernetes cluster the resources will be defined in many of YAML manifest file. If there are lots of manifest file and in case we need to apply different configuration for each environment like dev, test or production we can use &lt;code&gt;helm&lt;/code&gt; in order to render and deploy the manifest we need &lt;code&gt;helm&lt;/code&gt; command. Kustomize can helps in managing the environment specific configuration in a manageable way.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;With Kustomize we not need to template the manifest, the environment specific configuration can be applied to cluster directly using the &lt;code&gt;kubectl&lt;/code&gt; command. The manifest can also be rendered using &lt;code&gt;kustomize&lt;/code&gt; cli. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;With the kustomize structure the base or raw manifest will never change.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-how-kustomize-works&quot;&gt;How kustomize works?&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Say, we have a manifest for our application in a directory named &lt;code&gt;base&lt;/code&gt;, kustomize uses &lt;code&gt;kustomization.yaml&lt;/code&gt; file that configures the path these manifest under the same directory using &lt;code&gt;resources&lt;/code&gt; tag&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;The &lt;code&gt;resources&lt;/code&gt; tag is used to specify the path of the application manifest yaml this tag is identified by kustomize framework&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;In order to configure the environment specific configuration &lt;code&gt;overlay&lt;/code&gt; folder is created, which contains folders specific to environment. With reference to the image below, we use &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; folders refers the environment.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;Per Kustomize documentation example have used the folder name as &lt;code&gt;overlay&lt;/code&gt;, this folder name can be different.&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay\dev&lt;/code&gt; folder contains &lt;code&gt;kustomization.yaml&lt;/code&gt; file which defines the path to the base folder (in &lt;code&gt;resources&lt;/code&gt; tag), and dev environment specific changes. For dev the configuration adds &quot;-dev&quot; to the name using &lt;code&gt;nameSuffix&lt;/code&gt; and also updates the deployment replicas which is defined inline in the &lt;code&gt;kustomization.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay\test&lt;/code&gt; folder contains &lt;code&gt;kustomization.yaml&lt;/code&gt; file which defines the path to the base folder (in &lt;code&gt;resources&lt;/code&gt; tag), and path of the patch file using &lt;code&gt;patches&lt;/code&gt; tag. The &lt;code&gt;deployment_patch.yaml&lt;/code&gt; use patch transform to update the replicas of the deployment. There are other options to update the configuration of resources, using inline patch configuration where the deployment image tag and the secret properties are updated.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In order to render the environment specific manifest we can use the kustomize CLI command &lt;code&gt;kustomzie build /environment/directory/of/kustomization.yaml&lt;/code&gt; or use &lt;code&gt;kubectl apply -k /directory/of/kustomization.yaml&lt;/code&gt;.In both case the command takes in the environment specific folder where the &lt;code&gt;kustomization.yaml&lt;/code&gt; exists.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;The framework will use the &lt;code&gt;kustomize.yaml&lt;/code&gt; configuration to identify the base manifest.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kustomize-project-folder-structure&quot;&gt;Kustomize project folder structure&lt;/h4&gt;&lt;h5 id=&quot;heading-dev-environment-specific-representation&quot;&gt;Dev environment specific representation&lt;/h5&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204075864-fddca82d-d08e-4400-adf9-4ddaa252f81d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h5 id=&quot;heading-test-environment-specific-representation&quot;&gt;Test environment specific representation&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;With reference to the dev, the base folder is same for the test as well.&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204076298-992b39cb-ff10-4a5f-85dd-1d73831c4715.png&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-sample&quot;&gt;Code sample&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Below are the YAML file used for this demonstration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;base/deployment.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;base/secret.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;# For test we need to update this to TEST&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;base/kustomization.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;   &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment.yaml&lt;/span&gt;   &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-dev-environment-specific-configuration&quot;&gt;Dev environment specific configuration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay/dev/kustomization.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-dev&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# example of updating deployment replica from kustomization&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;Note:&lt;/span&gt;- Kustomize supports patch update where the same &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# changes can be created as a patch, will see this example in &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# overlay/test directory for demo&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# when using the replica in this kustomization.yaml, any change &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# to deployment replica will not be applied, noticed this update&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# takes precedence&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;count:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-render-dev-environment-manifest&quot;&gt;Render dev environment manifest&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Command to generate dev specific manifest&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# navigate to specific directory where the manifest is stored# &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; kustomization foder contains the base and overlay folder# refer the image above where the project structure is deplicted (fig &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&amp;gt; kustomize build overlay/dev&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;The manifest will be displayed in the stdout, we can redirect it to specific directory using the &lt;code&gt;-o&lt;/code&gt; switch, usage &lt;code&gt;kustomize build overlay/dev -o output/&lt;/code&gt; &lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-output-of-rendered-dev-manifest&quot;&gt;Output of rendered dev manifest&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-dev&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-dev&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-test-environment-specific-configuration&quot;&gt;Test environment specific configuration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay/test/deployment_patch.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;op :&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;replace&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/spec/replicas&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;There are couple ways to specify the patch files &lt;/p&gt;&lt;ul&gt;&lt;li&gt;The target can be specified directly in the &lt;code&gt;deployment_patch.yaml&lt;/code&gt; file like&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;This patch file can directly define the deployment manifest yaml, with the test specific configuration. The &lt;code&gt;kustomization.yaml&lt;/code&gt; file under test, will refer to the pathc using &lt;code&gt;patches&lt;/code&gt; tag.&lt;/li&gt;&lt;li&gt;kustomize framework will automatically infer the type of patch to be used when using &lt;code&gt;patches&lt;/code&gt; tag, like &lt;code&gt;patchesStrategicMerge&lt;/code&gt; or &lt;code&gt;patchTransform&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay/test/kustomization.yaml&lt;/code&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below yaml file defines different options to apply the patch, using external file and inline in the configuration yaml&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-test&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;patches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment_patch.yaml&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;patch:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|-     - op: replace       path: /spec/template/spec/containers/0/image       value: nginx:1.21.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;patch:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|-      apiVersion: v1      kind: Secret      metadata:        name: demo-app-secret        type: Opaque      data:        APP_NAME: demo_app        ENV_CODE: TEST ## UPDATE TO TEST IN THIS PATCH&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-render-test-environment-manifest&quot;&gt;Render test environment manifest&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To render test environment specific manifest, the command is &lt;code&gt;kustomzie build overlay/test&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-output-of-rendered-test-environment-manifest&quot;&gt;Output of rendered test environment manifest&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TEST&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-test&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-test&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:1.21.0&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;The rendered YAML file can be directly deployed to the cluster using &lt;code&gt;kubectl&lt;/code&gt; command. We can also directly use CD (continuous delivery) tool like &lt;code&gt;Argo CD&lt;/code&gt; to use the kustomize configuration to deploy the resources.&lt;/p&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-additional-info&quot;&gt;Additional Info&lt;/h4&gt;&lt;p&gt;Kustomize do supports different options to customize the configuration like &lt;/p&gt;&lt;ul&gt;&lt;li&gt;replacements&lt;/li&gt;&lt;li&gt;ConfigMap generator&lt;/li&gt;&lt;li&gt;SecretGenerator &lt;/li&gt;&lt;li&gt;built-in plugin&lt;/li&gt;&lt;li&gt;etc...&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Refer the &lt;a target=&quot;_blank&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/&quot;&gt;kustomize documentation&lt;/a&gt; for details.&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-manage-kubernetes-manifest-using-kustomize&quot;&gt;Manage Kubernetes manifest using Kustomize&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;In this blog have demonstrated, how we can use Kustomize to manage Kubernetes manifest with simple example and also how to render Kubernetes manifest using Kustomize CLI.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites:&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of Kubernetes and how resources are deployed using yaml&lt;ul&gt;&lt;li&gt;Kustomize CLI installed in the machine. To install refer the &lt;a target=&quot;_blank&quot; href=&quot;https://kubectl.docs.kubernetes.io/installation/kustomize/&quot;&gt;documentation&lt;/a&gt; for more details&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-what-is-kustomize&quot;&gt;What is Kustomize?&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Kustomize provides a solution for customizing Kubernetes resource configuration free from templates and DSLs. Refer &lt;a target=&quot;_blank&quot; href=&quot;https://kustomize.io/&quot;&gt;kustomize.io&lt;/a&gt;&lt;ul&gt;&lt;li&gt;Kustomize lets you customize raw, template-free YAML files for multiple purposes, leaving the original YAML untouched and usable as is.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt; client already supports kustomize&lt;/li&gt;&lt;li&gt;Kustomize configuration can applied directly to Kubernetes cluster using &lt;code&gt;kubectl apply -k &amp;lt;directory\to\kustomization.yaml&amp;gt;&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-high-level-overview&quot;&gt;High level overview&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In enterprise project to deploy the application into Kubernetes cluster the resources will be defined in many of YAML manifest file. If there are lots of manifest file and in case we need to apply different configuration for each environment like dev, test or production we can use &lt;code&gt;helm&lt;/code&gt; in order to render and deploy the manifest we need &lt;code&gt;helm&lt;/code&gt; command. Kustomize can helps in managing the environment specific configuration in a manageable way.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;With Kustomize we not need to template the manifest, the environment specific configuration can be applied to cluster directly using the &lt;code&gt;kubectl&lt;/code&gt; command. The manifest can also be rendered using &lt;code&gt;kustomize&lt;/code&gt; cli. &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;With the kustomize structure the base or raw manifest will never change.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-how-kustomize-works&quot;&gt;How kustomize works?&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Say, we have a manifest for our application in a directory named &lt;code&gt;base&lt;/code&gt;, kustomize uses &lt;code&gt;kustomization.yaml&lt;/code&gt; file that configures the path these manifest under the same directory using &lt;code&gt;resources&lt;/code&gt; tag&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;The &lt;code&gt;resources&lt;/code&gt; tag is used to specify the path of the application manifest yaml this tag is identified by kustomize framework&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;In order to configure the environment specific configuration &lt;code&gt;overlay&lt;/code&gt; folder is created, which contains folders specific to environment. With reference to the image below, we use &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; folders refers the environment.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;Per Kustomize documentation example have used the folder name as &lt;code&gt;overlay&lt;/code&gt;, this folder name can be different.&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay\dev&lt;/code&gt; folder contains &lt;code&gt;kustomization.yaml&lt;/code&gt; file which defines the path to the base folder (in &lt;code&gt;resources&lt;/code&gt; tag), and dev environment specific changes. For dev the configuration adds &quot;-dev&quot; to the name using &lt;code&gt;nameSuffix&lt;/code&gt; and also updates the deployment replicas which is defined inline in the &lt;code&gt;kustomization.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay\test&lt;/code&gt; folder contains &lt;code&gt;kustomization.yaml&lt;/code&gt; file which defines the path to the base folder (in &lt;code&gt;resources&lt;/code&gt; tag), and path of the patch file using &lt;code&gt;patches&lt;/code&gt; tag. The &lt;code&gt;deployment_patch.yaml&lt;/code&gt; use patch transform to update the replicas of the deployment. There are other options to update the configuration of resources, using inline patch configuration where the deployment image tag and the secret properties are updated.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In order to render the environment specific manifest we can use the kustomize CLI command &lt;code&gt;kustomzie build /environment/directory/of/kustomization.yaml&lt;/code&gt; or use &lt;code&gt;kubectl apply -k /directory/of/kustomization.yaml&lt;/code&gt;.In both case the command takes in the environment specific folder where the &lt;code&gt;kustomization.yaml&lt;/code&gt; exists.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;The framework will use the &lt;code&gt;kustomize.yaml&lt;/code&gt; configuration to identify the base manifest.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-kustomize-project-folder-structure&quot;&gt;Kustomize project folder structure&lt;/h4&gt;&lt;h5 id=&quot;heading-dev-environment-specific-representation&quot;&gt;Dev environment specific representation&lt;/h5&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204075864-fddca82d-d08e-4400-adf9-4ddaa252f81d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h5 id=&quot;heading-test-environment-specific-representation&quot;&gt;Test environment specific representation&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;With reference to the dev, the base folder is same for the test as well.&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/204076298-992b39cb-ff10-4a5f-85dd-1d73831c4715.png&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-sample&quot;&gt;Code sample&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Below are the YAML file used for this demonstration&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;base/deployment.yaml&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;base/secret.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;# For test we need to update this to TEST&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;base/kustomization.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt;   &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment.yaml&lt;/span&gt;   &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;secret.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-dev-environment-specific-configuration&quot;&gt;Dev environment specific configuration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay/dev/kustomization.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-dev&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# example of updating deployment replica from kustomization&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# &lt;span class=&quot;hljs-doctag&quot;&gt;Note:&lt;/span&gt;- Kustomize supports patch update where the same &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# changes can be created as a patch, will see this example in &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# overlay/test directory for demo&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# when using the replica in this kustomization.yaml, any change &lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# to deployment replica will not be applied, noticed this update&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# takes precedence&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;count:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-render-dev-environment-manifest&quot;&gt;Render dev environment manifest&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Command to generate dev specific manifest&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# navigate to specific directory where the manifest is stored# &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;case&lt;/span&gt; kustomization foder contains the base and overlay folder# refer the image above where the project structure is deplicted (fig &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)&amp;gt; kustomize build overlay/dev&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;The manifest will be displayed in the stdout, we can redirect it to specific directory using the &lt;code&gt;-o&lt;/code&gt; switch, usage &lt;code&gt;kustomize build overlay/dev -o output/&lt;/code&gt; &lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-output-of-rendered-dev-manifest&quot;&gt;Output of rendered dev manifest&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DEV&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-dev&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-dev&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-test-environment-specific-configuration&quot;&gt;Test environment specific configuration&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;overlay/test/deployment_patch.yaml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;op :&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;replace&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/spec/replicas&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;value:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;There are couple ways to specify the patch files &lt;/p&gt;&lt;ul&gt;&lt;li&gt;The target can be specified directly in the &lt;code&gt;deployment_patch.yaml&lt;/code&gt; file like&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;This patch file can directly define the deployment manifest yaml, with the test specific configuration. The &lt;code&gt;kustomization.yaml&lt;/code&gt; file under test, will refer to the pathc using &lt;code&gt;patches&lt;/code&gt; tag.&lt;/li&gt;&lt;li&gt;kustomize framework will automatically infer the type of patch to be used when using &lt;code&gt;patches&lt;/code&gt; tag, like &lt;code&gt;patchesStrategicMerge&lt;/code&gt; or &lt;code&gt;patchTransform&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;code&gt;overlay/test/kustomization.yaml&lt;/code&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Below yaml file defines different options to apply the patch, using external file and inline in the configuration yaml&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kustomize.config.k8s.io/v1beta1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Kustomization&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;../../base/&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nameSuffix:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;-test&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;patches:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;path:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;deployment_patch.yaml&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;       &lt;span class=&quot;hljs-attr&quot;&gt;group:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;patch:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|-     - op: replace       path: /spec/template/spec/containers/0/image       value: nginx:1.21.0&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;target:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;patch:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;|-      apiVersion: v1      kind: Secret      metadata:        name: demo-app-secret        type: Opaque      data:        APP_NAME: demo_app        ENV_CODE: TEST ## UPDATE TO TEST IN THIS PATCH&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-render-test-environment-manifest&quot;&gt;Render test environment manifest&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;To render test environment specific manifest, the command is &lt;code&gt;kustomzie build overlay/test&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-output-of-rendered-test-environment-manifest&quot;&gt;Output of rendered test environment manifest&lt;/h3&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;data:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;APP_NAME:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo_app&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ENV_CODE:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TEST&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Secret&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-secret-test&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Opaque&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;demo-app-test&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:1.21.0&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;The rendered YAML file can be directly deployed to the cluster using &lt;code&gt;kubectl&lt;/code&gt; command. We can also directly use CD (continuous delivery) tool like &lt;code&gt;Argo CD&lt;/code&gt; to use the kustomize configuration to deploy the resources.&lt;/p&gt;&lt;/blockquote&gt;&lt;h4 id=&quot;heading-additional-info&quot;&gt;Additional Info&lt;/h4&gt;&lt;p&gt;Kustomize do supports different options to customize the configuration like &lt;/p&gt;&lt;ul&gt;&lt;li&gt;replacements&lt;/li&gt;&lt;li&gt;ConfigMap generator&lt;/li&gt;&lt;li&gt;SecretGenerator &lt;/li&gt;&lt;li&gt;built-in plugin&lt;/li&gt;&lt;li&gt;etc...&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Refer the &lt;a target=&quot;_blank&quot; href=&quot;https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/&quot;&gt;kustomize documentation&lt;/a&gt; for details.&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Reactive App built with SpringBoot and Apache Camel to stream data using Apache Kafka]]></title><description><![CDATA[A simple reactive application that generates data (random number between 0-500) and streams it to an endpoint. using Apache Camel and Apache kafka]]></description><link>https://thirumurthi.hashnode.dev/reactive-app-built-with-springboot-and-apache-camel-to-stream-data-using-apache-kafka</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/reactive-app-built-with-springboot-and-apache-camel-to-stream-data-using-apache-kafka</guid><category><![CDATA[Springboot]]></category><category><![CDATA[apache-camel]]></category><category><![CDATA[Apache Kafka]]></category><category><![CDATA[Reactive Programming]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sat, 12 Nov 2022 07:11:07 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-simple-reactive-application-with-springboot-apache-camel-using-kafka-broker-to-stream-the-data&quot;&gt;Simple reactive application with SpringBoot, Apache Camel using Kafka Broker to stream the data.&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog have demonstrated how to integrate Apache Camel with Apache Kafka and SpringBoot, by building a simple Reactive application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Apache Camel components are used to generate random numbers every 2 seconds, this random number is sent to Kafka and consumed by different camel route finally connecting with SpringBoot Flux to stream the data via controller endpoint.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-about-the-application&quot;&gt;About the application&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Apache camel route definition details are as follows&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Route set 1:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: timer component used to poll every 2 seconds in this case&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;processor (this will generate Random number between 0-500 and set in camel exchange)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: direct endpoint (direct is specific to Apache Camel)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 2:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: kafka broker using the Camel kafka component&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 3:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;This will be&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: kafka broker consumes the message&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: send to direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 4:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: reactive-stream endpoint, named numbers&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;To integrate the Apache Camel &lt;code&gt;reactive-stream&lt;/code&gt; with the SpringBoot Flux, the publisher is retrieved from camel-context and subscribed using Flux.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;With Camel &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/components/3.18.x/reactive-streams-component.html&quot;&gt;reactive-streams component&lt;/a&gt; it is easy to use Project Reactor or RxJava or other reactive framework. In this case Spring Flux is used to subscribe to the publisher.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-flow-representation&quot;&gt;Code flow representation:&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/201460847-9d270f86-c934-45a4-9955-dc65640874bd.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kafka setup installed and running, accessible at &lt;code&gt;http://localhost:9092&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Apache Camel&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-code-details&quot;&gt;Code details&lt;/h2&gt;&lt;h3 id=&quot;heading-required-dependencies-for-the-project&quot;&gt;Required dependencies for the project&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create springboot project with Apache Camel and WebFlux dependencies, pom.xml details as follows&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.5&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.camel.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo project for Spring Boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-webflux&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-kafka-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.projectreactor&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;reactor-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-reactive-streams-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-reactor-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-camel-routing-configuration-details&quot;&gt;Camel Routing configuration details&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below code shows the route configuration mentioned above, we define it by extending the &lt;code&gt;RouteBuilder&lt;/code&gt; of Camel.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.RouteBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.kafka.KafkaConstants;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppCamelBasedProducerConsumer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RouteBuilder&lt;/span&gt; &lt;/span&gt;{    String kafkaProducerURI = &lt;span class=&quot;hljs-string&quot;&gt;&quot;kafka:camel-demo?brokers=localhost:9092&quot;&lt;/span&gt;;    String kafkaConsumerURI = kafkaProducerURI;    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 1&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer://demoapp?fixedRate=true&amp;amp;period=2000&quot;&lt;/span&gt;)                .process(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RandomGenerationProcess())                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 2&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;)                .setHeader(KafkaConstants.HEADERS, constant(&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-CAMEL&quot;&lt;/span&gt;))                .to(kafkaProducerURI);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 3&lt;/span&gt;        from(kafkaConsumerURI + &lt;span class=&quot;hljs-string&quot;&gt;&quot;&amp;amp;groupId=app&amp;amp;autoOffsetReset=earliest&amp;amp;seekTo=BEGINNING&quot;&lt;/span&gt;)                .log(&lt;span class=&quot;hljs-string&quot;&gt;&quot;message - ${body} from ${headers[kafka.TOPIC]}&quot;&lt;/span&gt;)                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:outputStream&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 4&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:outputStream&quot;&lt;/span&gt;)                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reactive-streams:numbers&quot;&lt;/span&gt;);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-camel-processor-configuration-that-generates-random-number&quot;&gt;Camel Processor configuration that generates random number&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Below is a implementation of Camel Processor which generates the random number.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In Camel with processor we can transform the messages retrieved from one endpoint to another.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;For example, we can use file component to read the contents of the file from a directory and use processor to transform all into uppercase.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.Exchange;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.Processor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RandomGenerationProcess&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Processor&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Exchange exchange)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        Integer rand = random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//Set the random number to the Camel exchange in the body&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//This will be sent to the next endpoint&lt;/span&gt;        exchange.getIn().setBody(rand);    }}&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt; We can pass the processor as lambda expression as well like below, so we don&apos;t need separate class for implement Processor&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;//.....&lt;/span&gt;   Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();   &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{       from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer://foo?fixedRate=true&amp;amp;period=2000&quot;&lt;/span&gt;)       &lt;span class=&quot;hljs-comment&quot;&gt;//pass in hte lamda directly&lt;/span&gt;       .process(exchange -&amp;gt; exchange.getIn().setBody(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;)))       .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;);   &lt;span class=&quot;hljs-comment&quot;&gt;//....&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-service-layer-to-subscribe-to-the-camel-stream-using-flux&quot;&gt;Service layer to subscribe to the Camel Stream using Flux&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is the service layer where the Camel reactive-streams and the Spring Flux are chained.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.CamelContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.ConsumerTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.reactive.streams.api.CamelReactiveStreams;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.reactive.streams.api.CamelReactiveStreamsService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.reactivestreams.Publisher;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; reactor.core.publisher.Flux;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-comment&quot;&gt;//Fetch the camel context from container&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    CamelContext camelContext;    &lt;span class=&quot;hljs-comment&quot;&gt;//Used to fetch the reactive stream publisher&lt;/span&gt;    CamelReactiveStreamsService camel;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Flux&amp;lt;Integer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;randomIntStream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        camel = CamelReactiveStreams.get(camelContext);        Publisher&amp;lt;Integer&amp;gt; numbers = camel.fromStream(&lt;span class=&quot;hljs-string&quot;&gt;&quot;numbers&quot;&lt;/span&gt;, Integer.class);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Flux.from(numbers);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-controller-code-to-create-an-event-stream-endpoint&quot;&gt;Controller code to create an event stream endpoint&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is a simple Controller, where we define the endpoint as a stream by defining a MediaType, so browsers can access the endpoint as stream of data&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.MediaType;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; reactor.core.publisher.Flux;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    AppService appService;    &lt;span class=&quot;hljs-comment&quot;&gt;//Including the Media Type TEXT_EVENT_STREAM_VALUE enables browser &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//to connect to the endpoint as event stream so data will be streamed continuously&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// accessing this endpoint with Chrome the data will be streamed&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// at this time when I tried with FireFox it downloads the stream as file&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(value=&quot;/stream&quot;,produces= MediaType.TEXT_EVENT_STREAM_VALUE)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Flux&amp;lt;Integer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getRandomIntegerStream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;invoked controller stream uri /stream&quot;&lt;/span&gt;);          &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; appService.randomIntStream();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-output&quot;&gt;Output:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Running the above code will throws exception message until an active subscriber is connected, in this case had to hit the &lt;code&gt;http://localhost:8080/api/stream&lt;/code&gt; from a browser browser. The console output once connected using browser starts streaming the data to the subscriber.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;2022-11-11 22:31:11.779  WARN 17004 --- [mer[camel-demo]] o.a.camel.component.kafka.KafkaConsumer  : Error during processing. Exchange[9D3C45E152C9A66-0000000000000437]. Caused by: [org.apache.camel.component.reactive.streams.ReactiveStreamsNoActiveSubscriptionsException - The stream has no active subscriptions]org.apache.camel.component.reactive.streams.ReactiveStreamsNoActiveSubscriptionsException: The stream has no active subscriptions    at org.apache.camel.component.reactive.streams.engine.CamelPublisher.publish(CamelPublisher.java:111) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.component.reactive.streams.engine.DefaultCamelReactiveStreamsService.sendCamelExchange(DefaultCamelReactiveStreamsService.java:151) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.component.reactive.streams.ReactiveStreamsProducer.process(ReactiveStreamsProducer.java:52) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.processor.Pipeline.process(Pipeline.java:175) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41) ~[camel-support-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessor.processExchange(KafkaRecordProcessor.java:109) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessorFacade.processRecord(KafkaRecordProcessorFacade.java:124) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessorFacade.processPolledRecords(KafkaRecordProcessorFacade.java:77) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.KafkaFetchRecords.startPolling(KafkaFetchRecords.java:318) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.KafkaFetchRecords.run(KafkaFetchRecords.java:158) ~[camel-kafka-3.19.0.jar:3.19.0]    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]2022-11-11 22:31:12.708  INFO 17004 --- [ctor-http-nio-2] com.camel.kafka.app.AppController        : invoked controller stream uri /stream2022-11-11 22:31:13.774  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 442 from camel-demo2022-11-11 22:31:15.783  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 205 from camel-demo2022-11-11 22:31:17.784  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 53 from&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;From Chrome browser below is the output where the data will be streamed continously&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/201460960-9a407f96-b92a-45af-a948-9e81150fa6d1.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-additional-notes&quot;&gt;Additional notes&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this pipeline instead of &lt;code&gt;timer&lt;/code&gt; component we can use &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;jms&lt;/code&gt;, etc. Camel component to fetch data and push to kafka.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Camel Kafka component has additional configuration that can be found in the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/components/3.18.x/kafka-component.html&quot;&gt;documentation&lt;/a&gt; like enabling transaction, reading from the offset, etc.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-simple-reactive-application-with-springboot-apache-camel-using-kafka-broker-to-stream-the-data&quot;&gt;Simple reactive application with SpringBoot, Apache Camel using Kafka Broker to stream the data.&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog have demonstrated how to integrate Apache Camel with Apache Kafka and SpringBoot, by building a simple Reactive application.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Apache Camel components are used to generate random numbers every 2 seconds, this random number is sent to Kafka and consumed by different camel route finally connecting with SpringBoot Flux to stream the data via controller endpoint.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-about-the-application&quot;&gt;About the application&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Apache camel route definition details are as follows&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Route set 1:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: timer component used to poll every 2 seconds in this case&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;processor (this will generate Random number between 0-500 and set in camel exchange)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: direct endpoint (direct is specific to Apache Camel)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 2:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: kafka broker using the Camel kafka component&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 3:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;This will be&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: kafka broker consumes the message&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: send to direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Route set 4:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;from: direct endpoint&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;to: reactive-stream endpoint, named numbers&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;To integrate the Apache Camel &lt;code&gt;reactive-stream&lt;/code&gt; with the SpringBoot Flux, the publisher is retrieved from camel-context and subscribed using Flux.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;With Camel &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/components/3.18.x/reactive-streams-component.html&quot;&gt;reactive-streams component&lt;/a&gt; it is easy to use Project Reactor or RxJava or other reactive framework. In this case Spring Flux is used to subscribe to the publisher.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code-flow-representation&quot;&gt;Code flow representation:&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/201460847-9d270f86-c934-45a4-9955-dc65640874bd.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-pre-requisites&quot;&gt;Pre-requisites:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Kafka setup installed and running, accessible at &lt;code&gt;http://localhost:9092&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Basic understanding of Apache Camel&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-code-details&quot;&gt;Code details&lt;/h2&gt;&lt;h3 id=&quot;heading-required-dependencies-for-the-project&quot;&gt;Required dependencies for the project&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create springboot project with Apache Camel and WebFlux dependencies, pom.xml details as follows&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;4.0.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-parent&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.5&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;relativePath&lt;/span&gt;/&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;parent&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.camel.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;0.0.1-SNAPSHOT&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;app&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;Demo project for Spring Boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;description&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;17&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;java.version&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-webflux&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-spring-boot-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-kafka-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;io.projectreactor&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;reactor-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-reactive-streams-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.apache.camel.springboot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;camel-reactor-starter&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;3.19.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;optional&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependencies&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;                            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;                        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;exclude&lt;/span&gt;&amp;gt;&lt;/span&gt;                    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;excludes&lt;/span&gt;&amp;gt;&lt;/span&gt;                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;configuration&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugin&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;plugins&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;build&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-camel-routing-configuration-details&quot;&gt;Camel Routing configuration details&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below code shows the route configuration mentioned above, we define it by extending the &lt;code&gt;RouteBuilder&lt;/code&gt; of Camel.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.builder.RouteBuilder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.kafka.KafkaConstants;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppCamelBasedProducerConsumer&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RouteBuilder&lt;/span&gt; &lt;/span&gt;{    String kafkaProducerURI = &lt;span class=&quot;hljs-string&quot;&gt;&quot;kafka:camel-demo?brokers=localhost:9092&quot;&lt;/span&gt;;    String kafkaConsumerURI = kafkaProducerURI;    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 1&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer://demoapp?fixedRate=true&amp;amp;period=2000&quot;&lt;/span&gt;)                .process(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RandomGenerationProcess())                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 2&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;)                .setHeader(KafkaConstants.HEADERS, constant(&lt;span class=&quot;hljs-string&quot;&gt;&quot;FROM-CAMEL&quot;&lt;/span&gt;))                .to(kafkaProducerURI);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 3&lt;/span&gt;        from(kafkaConsumerURI + &lt;span class=&quot;hljs-string&quot;&gt;&quot;&amp;amp;groupId=app&amp;amp;autoOffsetReset=earliest&amp;amp;seekTo=BEGINNING&quot;&lt;/span&gt;)                .log(&lt;span class=&quot;hljs-string&quot;&gt;&quot;message - ${body} from ${headers[kafka.TOPIC]}&quot;&lt;/span&gt;)                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:outputStream&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//route set 4&lt;/span&gt;        from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:outputStream&quot;&lt;/span&gt;)                .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;reactive-streams:numbers&quot;&lt;/span&gt;);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-camel-processor-configuration-that-generates-random-number&quot;&gt;Camel Processor configuration that generates random number&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Below is a implementation of Camel Processor which generates the random number.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In Camel with processor we can transform the messages retrieved from one endpoint to another.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;For example, we can use file component to read the contents of the file from a directory and use processor to transform all into uppercase.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.Exchange;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.Processor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Random;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RandomGenerationProcess&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Processor&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();    &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Exchange exchange)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        Integer rand = random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//Set the random number to the Camel exchange in the body&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;//This will be sent to the next endpoint&lt;/span&gt;        exchange.getIn().setBody(rand);    }}&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt; We can pass the processor as lambda expression as well like below, so we don&apos;t need separate class for implement Processor&lt;/p&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;   &lt;span class=&quot;hljs-comment&quot;&gt;//.....&lt;/span&gt;   Random random = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; Random();   &lt;span class=&quot;hljs-meta&quot;&gt;@Override&lt;/span&gt;   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{       from(&lt;span class=&quot;hljs-string&quot;&gt;&quot;timer://foo?fixedRate=true&amp;amp;period=2000&quot;&lt;/span&gt;)       &lt;span class=&quot;hljs-comment&quot;&gt;//pass in hte lamda directly&lt;/span&gt;       .process(exchange -&amp;gt; exchange.getIn().setBody(random.nextInt(&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;)))       .to(&lt;span class=&quot;hljs-string&quot;&gt;&quot;direct:message&quot;&lt;/span&gt;);   &lt;span class=&quot;hljs-comment&quot;&gt;//....&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-service-layer-to-subscribe-to-the-camel-stream-using-flux&quot;&gt;Service layer to subscribe to the Camel Stream using Flux&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is the service layer where the Camel reactive-streams and the Spring Flux are chained.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.CamelContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.ConsumerTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.reactive.streams.api.CamelReactiveStreams;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.camel.component.reactive.streams.api.CamelReactiveStreamsService;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.reactivestreams.Publisher;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; reactor.core.publisher.Flux;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-comment&quot;&gt;//Fetch the camel context from container&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    CamelContext camelContext;    &lt;span class=&quot;hljs-comment&quot;&gt;//Used to fetch the reactive stream publisher&lt;/span&gt;    CamelReactiveStreamsService camel;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Flux&amp;lt;Integer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;randomIntStream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        camel = CamelReactiveStreams.get(camelContext);        Publisher&amp;lt;Integer&amp;gt; numbers = camel.fromStream(&lt;span class=&quot;hljs-string&quot;&gt;&quot;numbers&quot;&lt;/span&gt;, Integer.class);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Flux.from(numbers);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-controller-code-to-create-an-event-stream-endpoint&quot;&gt;Controller code to create an event stream endpoint&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Below is a simple Controller, where we define the endpoint as a stream by defining a MediaType, so browsers can access the endpoint as stream of data&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.camel.kafka.app;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.MediaType;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; reactor.core.publisher.Flux;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;AppController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    AppService appService;    &lt;span class=&quot;hljs-comment&quot;&gt;//Including the Media Type TEXT_EVENT_STREAM_VALUE enables browser &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//to connect to the endpoint as event stream so data will be streamed continuously&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// accessing this endpoint with Chrome the data will be streamed&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// at this time when I tried with FireFox it downloads the stream as file&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(value=&quot;/stream&quot;,produces= MediaType.TEXT_EVENT_STREAM_VALUE)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Flux&amp;lt;Integer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getRandomIntegerStream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;invoked controller stream uri /stream&quot;&lt;/span&gt;);          &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; appService.randomIntStream();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;heading-output&quot;&gt;Output:&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Running the above code will throws exception message until an active subscriber is connected, in this case had to hit the &lt;code&gt;http://localhost:8080/api/stream&lt;/code&gt; from a browser browser. The console output once connected using browser starts streaming the data to the subscriber.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-plaintext&quot;&gt;2022-11-11 22:31:11.779  WARN 17004 --- [mer[camel-demo]] o.a.camel.component.kafka.KafkaConsumer  : Error during processing. Exchange[9D3C45E152C9A66-0000000000000437]. Caused by: [org.apache.camel.component.reactive.streams.ReactiveStreamsNoActiveSubscriptionsException - The stream has no active subscriptions]org.apache.camel.component.reactive.streams.ReactiveStreamsNoActiveSubscriptionsException: The stream has no active subscriptions    at org.apache.camel.component.reactive.streams.engine.CamelPublisher.publish(CamelPublisher.java:111) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.component.reactive.streams.engine.DefaultCamelReactiveStreamsService.sendCamelExchange(DefaultCamelReactiveStreamsService.java:151) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.component.reactive.streams.ReactiveStreamsProducer.process(ReactiveStreamsProducer.java:52) ~[camel-reactive-streams-3.19.0.jar:3.19.0]    at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:172) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.processor.errorhandler.RedeliveryErrorHandler$SimpleTask.run(RedeliveryErrorHandler.java:477) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultReactiveExecutor$Worker.schedule(DefaultReactiveExecutor.java:181) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultReactiveExecutor.scheduleMain(DefaultReactiveExecutor.java:59) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.processor.Pipeline.process(Pipeline.java:175) ~[camel-core-processor-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:392) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.impl.engine.DefaultAsyncProcessorAwaitManager.process(DefaultAsyncProcessorAwaitManager.java:83) ~[camel-base-engine-3.19.0.jar:3.19.0]    at org.apache.camel.support.AsyncProcessorSupport.process(AsyncProcessorSupport.java:41) ~[camel-support-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessor.processExchange(KafkaRecordProcessor.java:109) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessorFacade.processRecord(KafkaRecordProcessorFacade.java:124) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.consumer.support.KafkaRecordProcessorFacade.processPolledRecords(KafkaRecordProcessorFacade.java:77) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.KafkaFetchRecords.startPolling(KafkaFetchRecords.java:318) ~[camel-kafka-3.19.0.jar:3.19.0]    at org.apache.camel.component.kafka.KafkaFetchRecords.run(KafkaFetchRecords.java:158) ~[camel-kafka-3.19.0.jar:3.19.0]    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) ~[na:na]    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]    at java.base/java.lang.Thread.run(Thread.java:833) ~[na:na]2022-11-11 22:31:12.708  INFO 17004 --- [ctor-http-nio-2] com.camel.kafka.app.AppController        : invoked controller stream uri /stream2022-11-11 22:31:13.774  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 442 from camel-demo2022-11-11 22:31:15.783  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 205 from camel-demo2022-11-11 22:31:17.784  INFO 17004 --- [mer[camel-demo]] route3                                   : message - 53 from&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;From Chrome browser below is the output where the data will be streamed continously&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/201460960-9a407f96-b92a-45af-a948-9e81150fa6d1.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-additional-notes&quot;&gt;Additional notes&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this pipeline instead of &lt;code&gt;timer&lt;/code&gt; component we can use &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;jms&lt;/code&gt;, etc. Camel component to fetch data and push to kafka.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Camel Kafka component has additional configuration that can be found in the &lt;a target=&quot;_blank&quot; href=&quot;https://camel.apache.org/components/3.18.x/kafka-component.html&quot;&gt;documentation&lt;/a&gt; like enabling transaction, reading from the offset, etc.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Deploy KIND cluster in Docker Desktop and Access the container from Windows host]]></title><description><![CDATA[Access container running in KIND Kubernetes cluster in Window Docker Desktop
What is Kind?

With Kind (Kubernetes IN Docker) it is easy to spin up a local kubernetes cluster within Docker Desktop. The Kind runs as a container by itself.
Kind document...]]></description><link>https://thirumurthi.hashnode.dev/deploy-kind-cluster-in-docker-desktop-and-access-the-container-from-windows-host</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/deploy-kind-cluster-in-docker-desktop-and-access-the-container-from-windows-host</guid><category><![CDATA[kind]]></category><category><![CDATA[Kubernetes]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Mon, 07 Nov 2022 02:46:55 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h1 id=&quot;heading-access-container-running-in-kind-kubernetes-cluster-in-window-docker-desktop&quot;&gt;Access container running in KIND Kubernetes cluster in Window Docker Desktop&lt;/h1&gt;&lt;h2 id=&quot;heading-what-is-kind&quot;&gt;What is Kind?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;With Kind (Kubernetes IN Docker) it is easy to spin up a local kubernetes cluster within Docker Desktop. The Kind runs as a container by itself.&lt;/li&gt;&lt;li&gt;Kind documentation is easy to understand, for more details and understanding refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/&quot;&gt;documentation&lt;/a&gt; link.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-motivation&quot;&gt;Motivation&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;KIND cluster deployed in Windows Docker Desktop with default configuration we will not be able to access the container running in the cluster from the host machine.&lt;/li&gt;&lt;li&gt;In order to access the container from the host machine we need to create KIND cluster using  &lt;code&gt;extraPortMappings&lt;/code&gt; cluster configuration.&lt;/li&gt;&lt;li&gt;This is not the case if we create the KIND cluster in Linux based system, based on the documentation this is network based limitation in Windows and Mac.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-pre-requisite-tools-installed&quot;&gt;Pre-requisite tools installed&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Docker Desktop installed and running.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;KIND&lt;/strong&gt; using Chocolatey package manager refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/docs/user/quick-start/#installation&quot;&gt;Kind documentation&lt;/a&gt; or &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kind&quot;&gt;Chocolatey documentation&lt;/a&gt; package manager.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;Kubectl&lt;/strong&gt; installed using &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kubernetes-cli&quot;&gt;chocolatey&lt;/a&gt; package manager.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;GNU make&lt;/strong&gt; in Windows using &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/make&quot;&gt;Chocolatey&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In this blog we will also see how to use the make utility to automate the steps to create the Kind cluster and deploy simple nginx container in the cluster. Once deployed we can use a target to verify whether we are able to access the container.&lt;/p&gt;&lt;h2 id=&quot;heading-instruction-to-create-kind-cluster-in-docker-desktop-and-deployed-a-nginx-container&quot;&gt;Instruction to create KIND cluster in Docker Desktop and deployed a Nginx container&lt;/h2&gt;&lt;h3 id=&quot;heading-1-create-kind-cluster-with-cli&quot;&gt;1. Create KIND cluster with CLI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;KIND CLI used to create cluster with default configuration and specify the configuration in yaml file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# command to create cluster &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; config. # the &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; cluster name is kind&amp;gt; kind create cluster&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;# --name &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; can be used to provide name &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; cluster &amp;gt; kind create cluster --name=test01&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-kind-cluster-configuration-exposes-the-port&quot;&gt;KIND cluster configuration exposes the port&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;In order to expose the port, we can use &lt;code&gt;extraPortMappings&lt;/code&gt; option in the cluster config yaml file. The content of the cluster config, save it as &lt;code&gt;kind_cluster.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# port forward 8010 on the host to 80 on this node&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8010&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;KIND CLI command to use the config file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; kind create cluster --name=test --config=.\kind_cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;List of context created after the KIND cluster is created&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/199400230-f65e22a1-f65a-46cc-92f9-b7bf10201d58.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;After cluster deployed the KIND kube config is automatically merged to the kubectl kube config file, so we can use kubectl command directly to access the context. &lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Command that lists the contexts after the KIND cluster is created&lt;/li&gt;&lt;li&gt;&lt;code&gt;*&lt;/code&gt; indicates the kubectl is using it as current context&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ kubectl config get-contextsCURRENT   NAME              CLUSTER           AUTHINFO          NAMESPACE          docker-desktop    docker-desktop    docker-desktop*         kind-test         kind-test         kind-test          kind-test01       kind-test01       kind-test01&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the above configuration once the cluster is deployed if we check the &lt;code&gt;docker ps&lt;/code&gt; we should see the 8010 port exposed.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200222117-b9d1d2ca-2cc0-451b-ae63-e2cd4a981c57.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-2-create-a-nginx-container-with-the-config-file&quot;&gt;2. Create a nginx container with the config file&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Instead of running nginx container using &lt;code&gt;kubectl run&lt;/code&gt; command, we use the deployment manifest file below with ports specified.&lt;ul&gt;&lt;li&gt;We can see the &lt;code&gt;containerPort&lt;/code&gt; and the &lt;code&gt;hostPort&lt;/code&gt; in the deployment manifest both match cluster container port value 80.&lt;/li&gt;&lt;li&gt;The service type ClusterIP expose the container 80 port, so the container can be accessed from the host machine.&lt;/li&gt;&lt;li&gt;Save the deployment content to the file named &lt;code&gt;app_deployment.yaml&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;To access the nginx container from the host laptop, the service needs to be created.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-svc&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Create the deployment with &lt;code&gt;kubectl -n web apply -f app_deployment.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-3-access-the-container-from-host-machine&quot;&gt;3. Access the container from host machine&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;With the Git Bash use the &lt;code&gt;curl&lt;/code&gt; command to hit the 8010 port.&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;&lt;code&gt;curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8010&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or from the browser on host machine which displays the default nginx home page like below&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/199401277-6ab2bb24-8f5e-45ec-9b82-ff47b4af281d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-makefile-to-deploy-the-kind-cluster&quot;&gt;Makefile to deploy the KIND cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make&lt;/code&gt; is a build tool used in Linux/Unix systems to build C/C++ code earlier&lt;/li&gt;&lt;li&gt;The make file included all the above steps,&lt;ul&gt;&lt;li&gt;Create the KIND cluster, &lt;/li&gt;&lt;li&gt;Create a deployment to run a nginx container&lt;/li&gt;&lt;li&gt;Target to run the curl command to access the container&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;GNU make also supports lots of features, refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.gnu.org/doc/doc.html&quot;&gt;makde documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# Makefile simple representation&lt;span class=&quot;hljs-attr&quot;&gt;target&lt;/span&gt;:&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;tab-space&lt;/span&gt;&amp;gt;&lt;/span&gt;recipe&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The recipe in the Makefile followed by the target name should start with tab.else it won&apos;t make will not be able to execute the Makefile&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Below make file content should be created as &lt;code&gt;Makefile&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-make&quot;&gt;SHELL :=/bin/bashNAMESPACE ?= webCLUSTERNAME ?= testCLUSTERCONFIG := kind_cluster.yamlDEPLOYMENT_MANIFEST := app_deployment.yaml.DEFAULT_GOAL :=info#------------------------------#  Note:-#     - PHONY - usually the targets will be a file in make, in order to indicate it as a task we use PHONY#     - using @ before the commands in the recipe indicate the statement not to be printed in the stdout#       without @, the statement will be printed and command will get executed#     - $$ in the recipe is way to escape the character between the make and the shell command. (refer info target)#.PHONY: create-namespace create-namespace: # create namespace    @kubectl create ns ${NAMESPACE}.PHONY: install-clusterinstall-cluster: # install cluster    @kind create cluster --name=${CLUSTERNAME} --config=./${CLUSTERCONFIG}.PHONY: list-resourcelist-resource: # list resources deployment, pods, service    @kubectl -n ${NAMESPACE} get deploy,pods,svc.PHONY: display-logdisplay-log: # display pod logs (first index is used)    @kubectl -n ${NAMESPACE} logs pod/$(shell kubectl -n ${NAMESPACE} get pods --no-headers -o=jsonpath=&apos;{.items[0].metadata.name}&apos;)# target within single line alternate approach.PHONY: delete-clusterdelete-cluster: ; @kind delete cluster --name=${CLUSTERNAME}.PHONY: apply-manifestapply-manifest: # apply the manifest    @kubectl -n ${NAMESPACE} apply -f ${DEPLOYMENT_MANIFEST}.PHONY: deploy # creates cluster and deploy appdeploy: install-cluster create-namespace apply-manifest list-resource     @echo &quot;Deploy cluster&quot;.PHONY: check-container-accesscheck-container-access: # checks the container after deployment    @curl http://localhost:8010info: # display the target names    @awk &apos;/^[a-zA-Z_-]+: / { print $$0; print &quot;\n&quot;}&apos; $(MAKEFILE_LIST) | \    awk -F&quot;:&quot; &apos;BEGIN {print &quot;targets&quot; } /^[a-zA-Z_-]+/ {print &quot;    &quot;$$1}&apos;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Place the cluster config (as kind_cluster.yaml) and manifest content (as app_deployment.yaml) in same directory as the Makefile.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;From Git Bash editor, navigate to the directory and issue the below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; make deploy&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-using-make-targets&quot;&gt;Output - using make targets&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The output of using the &lt;code&gt;make deploy&lt;/code&gt;, deploy target which deploys the cluster and Nginx container.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200214360-6279da19-8fd8-4e5a-8430-94cc5cb917a7.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output of &lt;code&gt;make check-container-access&lt;/code&gt; once the deployment is complete&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200217172-8e715297-d081-49c0-a27b-c7ddd0bfd52a.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output of &lt;code&gt;make&lt;/code&gt; or or &lt;code&gt;make info&lt;/code&gt; will list the targets like below&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200217353-2576f8c9-d894-4de6-8756-aee4e5fdb1b6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-exposing-multiple-port-from-cluster&quot;&gt;Exposing multiple port from cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Cluster configuration to expose multiple port in this case 8012 and 8013&lt;/li&gt;&lt;li&gt;Once exposed we can access the container from host via these ports.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8012&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8013&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below are the two nginx deployment using different ports&lt;ul&gt;&lt;li&gt;8012.yaml&lt;ul&gt;&lt;li&gt;The nginx &lt;code&gt;containerPort : 80&lt;/code&gt;, the service definition targetPort is 80 which handles the traffic to the web-pod1 container&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;8013.yaml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h1 id=&quot;heading-access-container-running-in-kind-kubernetes-cluster-in-window-docker-desktop&quot;&gt;Access container running in KIND Kubernetes cluster in Window Docker Desktop&lt;/h1&gt;&lt;h2 id=&quot;heading-what-is-kind&quot;&gt;What is Kind?&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;With Kind (Kubernetes IN Docker) it is easy to spin up a local kubernetes cluster within Docker Desktop. The Kind runs as a container by itself.&lt;/li&gt;&lt;li&gt;Kind documentation is easy to understand, for more details and understanding refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/&quot;&gt;documentation&lt;/a&gt; link.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-motivation&quot;&gt;Motivation&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;KIND cluster deployed in Windows Docker Desktop with default configuration we will not be able to access the container running in the cluster from the host machine.&lt;/li&gt;&lt;li&gt;In order to access the container from the host machine we need to create KIND cluster using  &lt;code&gt;extraPortMappings&lt;/code&gt; cluster configuration.&lt;/li&gt;&lt;li&gt;This is not the case if we create the KIND cluster in Linux based system, based on the documentation this is network based limitation in Windows and Mac.&lt;/li&gt;&lt;/ul&gt;&lt;h2 id=&quot;heading-pre-requisite-tools-installed&quot;&gt;Pre-requisite tools installed&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Docker Desktop installed and running.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;KIND&lt;/strong&gt; using Chocolatey package manager refer &lt;a target=&quot;_blank&quot; href=&quot;https://kind.sigs.k8s.io/docs/user/quick-start/#installation&quot;&gt;Kind documentation&lt;/a&gt; or &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kind&quot;&gt;Chocolatey documentation&lt;/a&gt; package manager.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;Kubectl&lt;/strong&gt; installed using &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/kubernetes-cli&quot;&gt;chocolatey&lt;/a&gt; package manager.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;Install &lt;strong&gt;GNU make&lt;/strong&gt; in Windows using &lt;a target=&quot;_blank&quot; href=&quot;https://community.chocolatey.org/packages/make&quot;&gt;Chocolatey&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In this blog we will also see how to use the make utility to automate the steps to create the Kind cluster and deploy simple nginx container in the cluster. Once deployed we can use a target to verify whether we are able to access the container.&lt;/p&gt;&lt;h2 id=&quot;heading-instruction-to-create-kind-cluster-in-docker-desktop-and-deployed-a-nginx-container&quot;&gt;Instruction to create KIND cluster in Docker Desktop and deployed a Nginx container&lt;/h2&gt;&lt;h3 id=&quot;heading-1-create-kind-cluster-with-cli&quot;&gt;1. Create KIND cluster with CLI&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;KIND CLI used to create cluster with default configuration and specify the configuration in yaml file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# command to create cluster &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; config. # the &lt;span class=&quot;hljs-keyword&quot;&gt;default&lt;/span&gt; cluster name is kind&amp;gt; kind create cluster&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;# --name &lt;span class=&quot;hljs-keyword&quot;&gt;switch&lt;/span&gt; can be used to provide name &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; cluster &amp;gt; kind create cluster --name=test01&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-kind-cluster-configuration-exposes-the-port&quot;&gt;KIND cluster configuration exposes the port&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;In order to expose the port, we can use &lt;code&gt;extraPortMappings&lt;/code&gt; option in the cluster config yaml file. The content of the cluster config, save it as &lt;code&gt;kind_cluster.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;# port forward 8010 on the host to 80 on this node&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8010&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;KIND CLI command to use the config file&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; kind create cluster --name=test --config=.\kind_cluster.yaml&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;List of context created after the KIND cluster is created&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/199400230-f65e22a1-f65a-46cc-92f9-b7bf10201d58.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;After cluster deployed the KIND kube config is automatically merged to the kubectl kube config file, so we can use kubectl command directly to access the context. &lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Command that lists the contexts after the KIND cluster is created&lt;/li&gt;&lt;li&gt;&lt;code&gt;*&lt;/code&gt; indicates the kubectl is using it as current context&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;$ kubectl config get-contextsCURRENT   NAME              CLUSTER           AUTHINFO          NAMESPACE          docker-desktop    docker-desktop    docker-desktop*         kind-test         kind-test         kind-test          kind-test01       kind-test01       kind-test01&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;With the above configuration once the cluster is deployed if we check the &lt;code&gt;docker ps&lt;/code&gt; we should see the 8010 port exposed.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200222117-b9d1d2ca-2cc0-451b-ae63-e2cd4a981c57.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-2-create-a-nginx-container-with-the-config-file&quot;&gt;2. Create a nginx container with the config file&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Instead of running nginx container using &lt;code&gt;kubectl run&lt;/code&gt; command, we use the deployment manifest file below with ports specified.&lt;ul&gt;&lt;li&gt;We can see the &lt;code&gt;containerPort&lt;/code&gt; and the &lt;code&gt;hostPort&lt;/code&gt; in the deployment manifest both match cluster container port value 80.&lt;/li&gt;&lt;li&gt;The service type ClusterIP expose the container 80 port, so the container can be accessed from the host machine.&lt;/li&gt;&lt;li&gt;Save the deployment content to the file named &lt;code&gt;app_deployment.yaml&lt;/code&gt; &lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;To access the nginx container from the host laptop, the service needs to be created.&lt;/p&gt;&lt;/blockquote&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-svc&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Create the deployment with &lt;code&gt;kubectl -n web apply -f app_deployment.yaml&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-3-access-the-container-from-host-machine&quot;&gt;3. Access the container from host machine&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;With the Git Bash use the &lt;code&gt;curl&lt;/code&gt; command to hit the 8010 port.&lt;/li&gt;&lt;/ol&gt;&lt;pre&gt;&lt;code&gt;curl http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8010&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or from the browser on host machine which displays the default nginx home page like below&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/199401277-6ab2bb24-8f5e-45ec-9b82-ff47b4af281d.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-makefile-to-deploy-the-kind-cluster&quot;&gt;Makefile to deploy the KIND cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;make&lt;/code&gt; is a build tool used in Linux/Unix systems to build C/C++ code earlier&lt;/li&gt;&lt;li&gt;The make file included all the above steps,&lt;ul&gt;&lt;li&gt;Create the KIND cluster, &lt;/li&gt;&lt;li&gt;Create a deployment to run a nginx container&lt;/li&gt;&lt;li&gt;Target to run the curl command to access the container&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;GNU make also supports lots of features, refer &lt;a target=&quot;_blank&quot; href=&quot;https://www.gnu.org/doc/doc.html&quot;&gt;makde documentation&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# Makefile simple representation&lt;span class=&quot;hljs-attr&quot;&gt;target&lt;/span&gt;:&lt;span class=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;tab-space&lt;/span&gt;&amp;gt;&lt;/span&gt;recipe&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;INFO:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The recipe in the Makefile followed by the target name should start with tab.else it won&apos;t make will not be able to execute the Makefile&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Below make file content should be created as &lt;code&gt;Makefile&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-make&quot;&gt;SHELL :=/bin/bashNAMESPACE ?= webCLUSTERNAME ?= testCLUSTERCONFIG := kind_cluster.yamlDEPLOYMENT_MANIFEST := app_deployment.yaml.DEFAULT_GOAL :=info#------------------------------#  Note:-#     - PHONY - usually the targets will be a file in make, in order to indicate it as a task we use PHONY#     - using @ before the commands in the recipe indicate the statement not to be printed in the stdout#       without @, the statement will be printed and command will get executed#     - $$ in the recipe is way to escape the character between the make and the shell command. (refer info target)#.PHONY: create-namespace create-namespace: # create namespace    @kubectl create ns ${NAMESPACE}.PHONY: install-clusterinstall-cluster: # install cluster    @kind create cluster --name=${CLUSTERNAME} --config=./${CLUSTERCONFIG}.PHONY: list-resourcelist-resource: # list resources deployment, pods, service    @kubectl -n ${NAMESPACE} get deploy,pods,svc.PHONY: display-logdisplay-log: # display pod logs (first index is used)    @kubectl -n ${NAMESPACE} logs pod/$(shell kubectl -n ${NAMESPACE} get pods --no-headers -o=jsonpath=&apos;{.items[0].metadata.name}&apos;)# target within single line alternate approach.PHONY: delete-clusterdelete-cluster: ; @kind delete cluster --name=${CLUSTERNAME}.PHONY: apply-manifestapply-manifest: # apply the manifest    @kubectl -n ${NAMESPACE} apply -f ${DEPLOYMENT_MANIFEST}.PHONY: deploy # creates cluster and deploy appdeploy: install-cluster create-namespace apply-manifest list-resource     @echo &quot;Deploy cluster&quot;.PHONY: check-container-accesscheck-container-access: # checks the container after deployment    @curl http://localhost:8010info: # display the target names    @awk &apos;/^[a-zA-Z_-]+: / { print $$0; print &quot;\n&quot;}&apos; $(MAKEFILE_LIST) | \    awk -F&quot;:&quot; &apos;BEGIN {print &quot;targets&quot; } /^[a-zA-Z_-]+/ {print &quot;    &quot;$$1}&apos;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Place the cluster config (as kind_cluster.yaml) and manifest content (as app_deployment.yaml) in same directory as the Makefile.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;From Git Bash editor, navigate to the directory and issue the below command&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;&amp;gt; make deploy&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output-using-make-targets&quot;&gt;Output - using make targets&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The output of using the &lt;code&gt;make deploy&lt;/code&gt;, deploy target which deploys the cluster and Nginx container.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200214360-6279da19-8fd8-4e5a-8430-94cc5cb917a7.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output of &lt;code&gt;make check-container-access&lt;/code&gt; once the deployment is complete&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200217172-8e715297-d081-49c0-a27b-c7ddd0bfd52a.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Output of &lt;code&gt;make&lt;/code&gt; or or &lt;code&gt;make info&lt;/code&gt; will list the targets like below&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/200217353-2576f8c9-d894-4de6-8756-aee4e5fdb1b6.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h2 id=&quot;heading-exposing-multiple-port-from-cluster&quot;&gt;Exposing multiple port from cluster&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Cluster configuration to expose multiple port in this case 8012 and 8013&lt;/li&gt;&lt;li&gt;Once exposed we can access the container from host via these ports.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Cluster&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;nodes:&lt;/span&gt;&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;control-plane&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;extraPortMappings:&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8012&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8013&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;listenAddress:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;127.0.0.1&quot;&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Below are the two nginx deployment using different ports&lt;ul&gt;&lt;li&gt;8012.yaml&lt;ul&gt;&lt;li&gt;The nginx &lt;code&gt;containerPort : 80&lt;/code&gt;, the service definition targetPort is 80 which handles the traffic to the web-pod1 container&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8000&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;8013.yaml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;apps/v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Deployment&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;replicas:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;matchLabels:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;strategy:&lt;/span&gt; {}  &lt;span class=&quot;hljs-attr&quot;&gt;template:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;labels:&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;containers:&lt;/span&gt;      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;        &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;containerPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;          &lt;span class=&quot;hljs-attr&quot;&gt;hostPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;        &lt;span class=&quot;hljs-attr&quot;&gt;resources:&lt;/span&gt; {}&lt;span class=&quot;hljs-attr&quot;&gt;status:&lt;/span&gt; {}&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;apiVersion:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;kind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;metadata:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spec:&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;selector:&lt;/span&gt;    &lt;span class=&quot;hljs-attr&quot;&gt;app:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;web-pod2&lt;/span&gt;  &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;    &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;protocol:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TCP&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;port:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;8001&lt;/span&gt;      &lt;span class=&quot;hljs-attr&quot;&gt;targetPort:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Integration test Kafka using Awaitality library]]></title><description><![CDATA[Simple Kafka broker consumer integration test case using awaitaility]]></description><link>https://thirumurthi.hashnode.dev/integration-test-kafka-using-awaitality-library</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/integration-test-kafka-using-awaitality-library</guid><category><![CDATA[awaitality]]></category><category><![CDATA[Apache Kafka]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[integration test]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 30 Oct 2022 22:34:06 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-using-awaitality-in-integration-test-kafka-broker&quot;&gt;Using Awaitality in integration test Kafka Broker&lt;/h2&gt;&lt;p&gt;In this blog will briefly explain how to can use &lt;code&gt;Awaitility&lt;/code&gt; library to test Kafka in integration test. &lt;/p&gt;&lt;h3 id=&quot;heading-why-use-awaitility-dependency&quot;&gt;Why use Awaitility dependency&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Awaitility library can be used for testing external services like Kafka, RabbitMQ, etc. mostly this can be used when application handling asynchronized calls and wait for responses.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Awaitility has different method to support application built in asynchronized way, for more details about Awaitlity refer the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/awaitility/awaitility&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In below have created a simple SpringBoot application with a Producer to send message to Kafka Broker and Consumer to consumes the message. The Listener in the Consumer, will wait for message s to be received from the topic.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Consumer has to wait till the message is received and this mostly happens in asynchronous application. The application has to wait for a response from external service which might be immediate or delayed after few seconds in such case we can use Awaitility library to perform integration test. &lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note, there are cases where we can mock the external service like in this case we use embedded Kafka broker, this might not be always possible since some projects might have dedicated environment. In such scenarios we can use Awaitlity library.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For integration testing in this example have used the embedded Kafka Broker to test the  ConsumerService.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create SpringBoot application with &lt;code&gt;lombok&lt;/code&gt; and &lt;code&gt;kafka&lt;/code&gt; dependency form &lt;code&gt;start.spring.io&lt;/code&gt; or IDE.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-required-maven-dependencies&quot;&gt;Required maven dependencies&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Include &lt;code&gt;awaitility&lt;/code&gt; dependency in &lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.awaitility&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;awaitility&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Kafka testing dependency should already be included if not add it to pom.xml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-kafka-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-producerservice-code-that-sends-message-to-broker&quot;&gt;ProducerService Code that sends message to broker&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple producer code, where the Kafka broker configuration are defined in &lt;code&gt;application.properties&lt;/code&gt;, SpringBoot will use it to create the KafkaTemplate&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.text.MessageFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.core.KafkaTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    KafkaTemplate&amp;lt;String,String&amp;gt; kafkaTemplate;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String topic, String message)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sending message from producer - {}&quot;&lt;/span&gt;,message);        kafkaTemplate.send(topic,message);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageFormat.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Message Sent from Producer - {0}&quot;&lt;/span&gt;,message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-consumerservice-code-that-consumes-message-from-broker&quot;&gt;ConsumerService Code that consumes message from broker&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple Consumer code which will use the &lt;code&gt;@KafakListener&lt;/code&gt; configuration defined in the &lt;code&gt;application.properties&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.kafka.clients.consumer.ConsumerRecord;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.annotation.KafkaListener;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String payload;    &lt;span class=&quot;hljs-meta&quot;&gt;@KafkaListener(topics=&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;consumeMessageAppTopic&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ConsumerRecord&amp;lt;?,?&amp;gt; consumerRecord)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;payload consuming {}&quot;&lt;/span&gt;,consumerRecord.toString());        payload = consumerRecord.value().toString();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-kafka-broker-configuration-details&quot;&gt;Kafka broker configuration details&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;application.properties&lt;/code&gt; file with the Kafka broker configuration&lt;ul&gt;&lt;li&gt;Using 9094 as Kafka port instead of default 9092.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# topic nametest.app.topic=test-topic# Consumer configurationspring.kafka.consumer.bootstrap-servers= localhost:&lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;spring.kafka.consumer.group-id= consume-test-idspring.kafka.consumer.auto-offset-reset= earliestspring.kafka.consumer.key-deserializer= org.apache.kafka.common.serialization.StringDeserializerspring.kafka.consumer.value-deserializer= org.apache.kafka.common.serialization.StringDeserializer# Producer configurationspring.kafka.producer.bootstrap-servers= localhost:&lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;spring.kafka.producer.key-serializer= org.apache.kafka.common.serialization.StringSerializerspring.kafka.producer.value-serializer= org.apache.kafka.common.serialization.StringSerializer&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-integration-test-case-code-using-awaitality-library&quot;&gt;Integration test case code using Awaitality library&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below code should be placed in the test folder in the SpringBoot project structure&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.awaitility.Awaitility;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.junit.jupiter.api.Test;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.test.context.SpringBootTest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.test.context.EmbeddedKafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.test.annotation.DirtiesContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.Duration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootTest&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@DirtiesContext&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;/*properties to the EmbeddedKafka brokerpartitions  # of partitions to be used per topic, default 2.brokerProperties  Kafka broker configuration, using plain text listener.*/&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@EmbeddedKafka(partitions = 1,        brokerProperties = { &quot;listeners=PLAINTEXT://localhost:9094&quot;, &quot;port=9094&quot; })&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerServiceTest&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ConsumerService consumer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ProducerService producer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String topic;    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testUsingAwaitility_messageConsumed&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;/*          Awaitality which will wait for 15 seconds to receive the           message, if message is received before 15 seconds          the test case will be passed and assertion gets validated          until() requires a callable to return the Boolean here,          where the payLoad is obtained        */&lt;/span&gt;        Awaitility.await().atMost(Duration.ofSeconds(&lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;))                .until(()-&amp;gt;Objects.nonNull(consumer.getPayload()));    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testUsingAwaitility_messageEquality&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;/*          The Awaitality until() method callable to validate the           expected message with the consumed message        */&lt;/span&gt;        Awaitility.await().atMost(Duration.ofSeconds(&lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;))                .until(()-&amp;gt;Objects.equals(expectedData,consumer.getPayload()));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-alternate-approach-to-test-kafka&quot;&gt;Alternate approach to test Kafka&lt;/h3&gt;&lt;h4 id=&quot;heading-integration-test-case-using-countdownlatch&quot;&gt;Integration test case using CountDownLatch&lt;/h4&gt;&lt;h5 id=&quot;heading-consumerservice-code-changes-to-use-countdownlatch&quot;&gt;ConsumerService code changes to use CountDownLatch&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Alternatively we can use &lt;code&gt;CountDownLatch&lt;/code&gt; to wait till the consumer listener recieves the message. Only the ConsumerService code will change in this case, the ProducerService remains the same.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The consumer code looks like below when using CountDownLatch &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.kafka.clients.consumer.ConsumerRecord;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.annotation.KafkaListener;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.CountDownLatch;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String payload;    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; CountDownLatch latch = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; CountDownLatch(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);    &lt;span class=&quot;hljs-meta&quot;&gt;@KafkaListener(topics=&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;consumeMessageAppTopic&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ConsumerRecord&amp;lt;?,?&amp;gt; consumerRecord)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;payload consuming {}&quot;&lt;/span&gt;,consumerRecord.toString());        payload = consumerRecord.value().toString();        &lt;span class=&quot;hljs-comment&quot;&gt;//once the message is consumed we call the countdown latch to &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// decrement the count&lt;/span&gt;        latch.countDown();    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;resetLatch&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        latch = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; CountDownLatch(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-test-case-code-using-countdownlatch&quot;&gt;Test case code using CountDownLatch&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;consumer.getLatch().await()&lt;/code&gt; in test case will wait the thread till  the message is consumed by the ConsumerService class consumerMessageAppTopic() method, since this method invokes &lt;code&gt;countDown()&lt;/code&gt; after the message is received from the Listener releasing the thread to proceed further.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.awaitility.Awaitility;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.junit.jupiter.api.Test;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.test.context.SpringBootTest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.test.context.EmbeddedKafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.test.annotation.DirtiesContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.Duration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootTest&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@DirtiesContext&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@EmbeddedKafka(partitions = 1,        brokerProperties = { &quot;listeners=PLAINTEXT://localhost:9094&quot;, &quot;port=9094&quot; })&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerServiceTest&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ConsumerService consumer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ProducerService producer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String topic;    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testConsumeMessage_countDownLatch&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;// CountDownLatch await() method will wait for 10 seconds or till the&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// ConsumerService consumeMessageAppTopic() invokes countDown() method.&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; messageConsumed = consumer.getLatch().await(&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;, TimeUnit.SECONDS);        assertTrue(messageConsumed);                assertTrue(expectedData.equals(consumer.getPayload()));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Running the test cases should succeed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/198904572-db399126-69db-4aa0-bbde-b461e1e81553.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-using-awaitality-in-integration-test-kafka-broker&quot;&gt;Using Awaitality in integration test Kafka Broker&lt;/h2&gt;&lt;p&gt;In this blog will briefly explain how to can use &lt;code&gt;Awaitility&lt;/code&gt; library to test Kafka in integration test. &lt;/p&gt;&lt;h3 id=&quot;heading-why-use-awaitility-dependency&quot;&gt;Why use Awaitility dependency&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Awaitility library can be used for testing external services like Kafka, RabbitMQ, etc. mostly this can be used when application handling asynchronized calls and wait for responses.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Awaitility has different method to support application built in asynchronized way, for more details about Awaitlity refer the &lt;a target=&quot;_blank&quot; href=&quot;https://github.com/awaitility/awaitility&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;In below have created a simple SpringBoot application with a Producer to send message to Kafka Broker and Consumer to consumes the message. The Listener in the Consumer, will wait for message s to be received from the topic.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The Consumer has to wait till the message is received and this mostly happens in asynchronous application. The application has to wait for a response from external service which might be immediate or delayed after few seconds in such case we can use Awaitility library to perform integration test. &lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Note, there are cases where we can mock the external service like in this case we use embedded Kafka broker, this might not be always possible since some projects might have dedicated environment. In such scenarios we can use Awaitlity library.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For integration testing in this example have used the embedded Kafka Broker to test the  ConsumerService.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Create SpringBoot application with &lt;code&gt;lombok&lt;/code&gt; and &lt;code&gt;kafka&lt;/code&gt; dependency form &lt;code&gt;start.spring.io&lt;/code&gt; or IDE.&lt;/li&gt;&lt;/ul&gt;&lt;h4 id=&quot;heading-required-maven-dependencies&quot;&gt;Required maven dependencies&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Include &lt;code&gt;awaitility&lt;/code&gt; dependency in &lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.awaitility&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;awaitility&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;Kafka testing dependency should already be included if not add it to pom.xml&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.kafka&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-kafka-test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;test&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-producerservice-code-that-sends-message-to-broker&quot;&gt;ProducerService Code that sends message to broker&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple producer code, where the Kafka broker configuration are defined in &lt;code&gt;application.properties&lt;/code&gt;, SpringBoot will use it to create the KafkaTemplate&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.text.MessageFormat;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.core.KafkaTemplate;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ProducerService&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    KafkaTemplate&amp;lt;String,String&amp;gt; kafkaTemplate;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String topic, String message)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Sending message from producer - {}&quot;&lt;/span&gt;,message);        kafkaTemplate.send(topic,message);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; MessageFormat.format(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Message Sent from Producer - {0}&quot;&lt;/span&gt;,message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-consumerservice-code-that-consumes-message-from-broker&quot;&gt;ConsumerService Code that consumes message from broker&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple Consumer code which will use the &lt;code&gt;@KafakListener&lt;/code&gt; configuration defined in the &lt;code&gt;application.properties&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.kafka.clients.consumer.ConsumerRecord;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.annotation.KafkaListener;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String payload;    &lt;span class=&quot;hljs-meta&quot;&gt;@KafkaListener(topics=&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;consumeMessageAppTopic&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ConsumerRecord&amp;lt;?,?&amp;gt; consumerRecord)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;payload consuming {}&quot;&lt;/span&gt;,consumerRecord.toString());        payload = consumerRecord.value().toString();    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-kafka-broker-configuration-details&quot;&gt;Kafka broker configuration details&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;application.properties&lt;/code&gt; file with the Kafka broker configuration&lt;ul&gt;&lt;li&gt;Using 9094 as Kafka port instead of default 9092.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;# topic nametest.app.topic=test-topic# Consumer configurationspring.kafka.consumer.bootstrap-servers= localhost:&lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;spring.kafka.consumer.group-id= consume-test-idspring.kafka.consumer.auto-offset-reset= earliestspring.kafka.consumer.key-deserializer= org.apache.kafka.common.serialization.StringDeserializerspring.kafka.consumer.value-deserializer= org.apache.kafka.common.serialization.StringDeserializer# Producer configurationspring.kafka.producer.bootstrap-servers= localhost:&lt;span class=&quot;hljs-number&quot;&gt;9094&lt;/span&gt;spring.kafka.producer.key-serializer= org.apache.kafka.common.serialization.StringSerializerspring.kafka.producer.value-serializer= org.apache.kafka.common.serialization.StringSerializer&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-integration-test-case-code-using-awaitality-library&quot;&gt;Integration test case code using Awaitality library&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below code should be placed in the test folder in the SpringBoot project structure&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.awaitility.Awaitility;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.junit.jupiter.api.Test;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.test.context.SpringBootTest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.test.context.EmbeddedKafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.test.annotation.DirtiesContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.Duration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootTest&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@DirtiesContext&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;/*properties to the EmbeddedKafka brokerpartitions  # of partitions to be used per topic, default 2.brokerProperties  Kafka broker configuration, using plain text listener.*/&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@EmbeddedKafka(partitions = 1,        brokerProperties = { &quot;listeners=PLAINTEXT://localhost:9094&quot;, &quot;port=9094&quot; })&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerServiceTest&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ConsumerService consumer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ProducerService producer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String topic;    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testUsingAwaitility_messageConsumed&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;/*          Awaitality which will wait for 15 seconds to receive the           message, if message is received before 15 seconds          the test case will be passed and assertion gets validated          until() requires a callable to return the Boolean here,          where the payLoad is obtained        */&lt;/span&gt;        Awaitility.await().atMost(Duration.ofSeconds(&lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;))                .until(()-&amp;gt;Objects.nonNull(consumer.getPayload()));    }    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testUsingAwaitility_messageEquality&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;/*          The Awaitality until() method callable to validate the           expected message with the consumed message        */&lt;/span&gt;        Awaitility.await().atMost(Duration.ofSeconds(&lt;span class=&quot;hljs-number&quot;&gt;15&lt;/span&gt;))                .until(()-&amp;gt;Objects.equals(expectedData,consumer.getPayload()));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-alternate-approach-to-test-kafka&quot;&gt;Alternate approach to test Kafka&lt;/h3&gt;&lt;h4 id=&quot;heading-integration-test-case-using-countdownlatch&quot;&gt;Integration test case using CountDownLatch&lt;/h4&gt;&lt;h5 id=&quot;heading-consumerservice-code-changes-to-use-countdownlatch&quot;&gt;ConsumerService code changes to use CountDownLatch&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;Alternatively we can use &lt;code&gt;CountDownLatch&lt;/code&gt; to wait till the consumer listener recieves the message. Only the ConsumerService code will change in this case, the ProducerService remains the same.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;The consumer code looks like below when using CountDownLatch &lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Getter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Setter;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.apache.kafka.clients.consumer.ConsumerRecord;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.annotation.KafkaListener;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.CountDownLatch;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String payload;    &lt;span class=&quot;hljs-meta&quot;&gt;@Getter&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Setter&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; CountDownLatch latch = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; CountDownLatch(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);    &lt;span class=&quot;hljs-meta&quot;&gt;@KafkaListener(topics=&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;consumeMessageAppTopic&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ConsumerRecord&amp;lt;?,?&amp;gt; consumerRecord)&lt;/span&gt;&lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;payload consuming {}&quot;&lt;/span&gt;,consumerRecord.toString());        payload = consumerRecord.value().toString();        &lt;span class=&quot;hljs-comment&quot;&gt;//once the message is consumed we call the countdown latch to &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// decrement the count&lt;/span&gt;        latch.countDown();    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;resetLatch&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        latch = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; CountDownLatch(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&quot;heading-test-case-code-using-countdownlatch&quot;&gt;Test case code using CountDownLatch&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The &lt;code&gt;consumer.getLatch().await()&lt;/code&gt; in test case will wait the thread till  the message is consumed by the ConsumerService class consumerMessageAppTopic() method, since this method invokes &lt;code&gt;countDown()&lt;/code&gt; after the message is received from the Listener releasing the thread to proceed further.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.kafka.example.kafkademo.code;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.awaitility.Awaitility;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.junit.jupiter.api.Test;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Value;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.test.context.SpringBootTest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.kafka.test.context.EmbeddedKafka;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.test.annotation.DirtiesContext;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.Duration;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.concurrent.TimeUnit;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootTest&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@DirtiesContext&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@EmbeddedKafka(partitions = 1,        brokerProperties = { &quot;listeners=PLAINTEXT://localhost:9094&quot;, &quot;port=9094&quot; })&lt;/span&gt;&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ConsumerServiceTest&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ConsumerService consumer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; ProducerService producer;    &lt;span class=&quot;hljs-meta&quot;&gt;@Value(&quot;${test.app.topic}&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String topic;    &lt;span class=&quot;hljs-meta&quot;&gt;@Test&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;testConsumeMessage_countDownLatch&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Exception &lt;/span&gt;{        String expectedData = &lt;span class=&quot;hljs-string&quot;&gt;&quot;message data&quot;&lt;/span&gt;;        producer.sendMessage(topic,expectedData);        &lt;span class=&quot;hljs-comment&quot;&gt;// CountDownLatch await() method will wait for 10 seconds or till the&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// ConsumerService consumeMessageAppTopic() invokes countDown() method.&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;boolean&lt;/span&gt; messageConsumed = consumer.getLatch().await(&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;, TimeUnit.SECONDS);        assertTrue(messageConsumed);                assertTrue(expectedData.equals(consumer.getPayload()));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Running the test cases should succeed&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/198904572-db399126-69db-4aa0-bbde-b461e1e81553.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Validate input JSON payload with SpringBoot AOP]]></title><description><![CDATA[The SpringBoot AOP to perform custom validation with the annotation]]></description><link>https://thirumurthi.hashnode.dev/validate-input-json-payload-with-springboot-aop</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/validate-input-json-payload-with-springboot-aop</guid><category><![CDATA[spring-aop]]></category><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 23 Oct 2022 16:40:58 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-validate-input-json-payload-with-springboot-aop&quot;&gt;Validate input JSON payload with SpringBoot AOP&lt;/h2&gt;&lt;p&gt;In this blog will demonstrate an use case to use SpringBoot AOP to perform input validation in the &lt;code&gt;@Controller&lt;/code&gt; or &lt;code&gt;@Service&lt;/code&gt; layer level.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of AOP concept like Point Cut, ProceedingJointPoint, Adivces - Around, Before , After, etc.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-use-case-validate-payload-in-controller-or-service-layer&quot;&gt;Use case - Validate payload in controller or service layer&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;When building REST based application at circumstance we might need to perform customized validation on the JSON payload before passing request to the repository layer or further next layer.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Defining JSON schema, is another possible option this might requires more coding effort.&lt;/p&gt;&lt;p&gt;The validation can be performed using the &lt;code&gt;hibernate-validator&lt;/code&gt;, with built-in annotation &lt;code&gt;@NotNull&lt;/code&gt;, &lt;code&gt;@NotEmpty&lt;/code&gt;, etc. defined in the entity class.&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Create SpringBoot project using &lt;code&gt;start.spring.io&lt;/code&gt; with &lt;code&gt;spring web&lt;/code&gt; and &lt;code&gt;lombok&lt;/code&gt; dependencies.&lt;/li&gt;&lt;li&gt;Add the Spring starter AOP dependencies in the &lt;code&gt;pom.xml&lt;/code&gt;, like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-aop&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog have included few additional points,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How to easily create builder pattern on POJO using &lt;code&gt;@Build&lt;/code&gt; annotation from Lombok project &lt;/li&gt;&lt;li&gt;Extending RuntimeException to create custom exception used to handle Input validation in this case&lt;/li&gt;&lt;li&gt;Custom Spring annotation creation and registering it in AOP &lt;code&gt;@Around&lt;/code&gt; advice which will be invoked and used to intercept the method calls&lt;/li&gt;&lt;li&gt;&lt;code&gt;java.utils.Objects&lt;/code&gt; to validate null. Objects contains few other methods which is not detailed here&lt;/li&gt;&lt;li&gt;Java feature to perform &lt;code&gt;instanceof&lt;/code&gt; check and directly store the converted data to variable&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// Code where the Object instanceof Customer and the converted data stored in customers&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ( requestObject.length &amp;gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;  &amp;amp;&amp;amp; requestObject[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;instanceof&lt;/span&gt; Customer customers ){        &lt;span class=&quot;hljs-comment&quot;&gt;// first object in the arguments&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (Objects.isNull(customers)){            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Input invalid - Cannot be null&quot;&lt;/span&gt;);        }  &lt;span class=&quot;hljs-comment&quot;&gt;//.....&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt; SpringBoot AOP only used to intercept methods.  For advanced feature we need to use AspectJ, for example to check if fields have changed.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;h4 id=&quot;heading-create-spring-annotation&quot;&gt;Create Spring Annotation&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Create Spring Annotation, which will be configured in the Aspect &lt;code&gt;@Around&lt;/code&gt; advice class.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.ElementType;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.Retention;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.RetentionPolicy;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.Target;&lt;span class=&quot;hljs-meta&quot;&gt;@Target(ElementType.METHOD)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-meta&quot;&gt;@interface&lt;/span&gt; ValidateInputRequest {}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-aspect-to-intercept-the-method-calls&quot;&gt;Create Aspect to intercept the method calls&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below code defines the Aspect using &lt;code&gt;@Aspect&lt;/code&gt; annotation (note, this aspect needs to be regiestered as a bean using &lt;code&gt;@Component&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;The custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt; in the previous code snippet is registered in the &lt;code&gt;@Around&lt;/code&gt; advice.&lt;/li&gt;&lt;li&gt;The Aspect class &lt;code&gt;validateInput()&lt;/code&gt; method will be invoked if the custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt; is annotated on the method defined in &lt;code&gt;@Controller&lt;/code&gt; or &lt;code&gt;@Service&lt;/code&gt; layer.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.InvalidInputException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.ProceedingJoinPoint;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Around;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Aspect;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Arrays;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Optional;&lt;span class=&quot;hljs-meta&quot;&gt;@Aspect&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidationAspectConfig&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-comment&quot;&gt;//Using the Around advice, with the Annotation created and place the annotation &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//over the method will invoke this call&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Around(&quot;@annotation(ValidateInputRequest)&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Object &lt;span class=&quot;hljs-title&quot;&gt;validateInput&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ProceedingJoinPoint  pjp)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Throwable &lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;AOP intercept for method - &quot;&lt;/span&gt;+pjp.getSignature());        Object[] requestObject = pjp.getArgs();        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ( requestObject.length &amp;gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;  &amp;amp;&amp;amp;requestObject[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;instanceof&lt;/span&gt; Customer customers ){            &lt;span class=&quot;hljs-comment&quot;&gt;// first object in the arguments&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (Objects.isNull(customers)){                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Input invalid - Cannot be null&quot;&lt;/span&gt;);            }            &lt;span class=&quot;hljs-comment&quot;&gt;//Performing validation for the input request intercepted and received&lt;/span&gt;            ValidateInput.validateRequest(customers);        }&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;{            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;input object is not of customer instance&quot;&lt;/span&gt;);        }        &lt;span class=&quot;hljs-comment&quot;&gt;//just obtain the obj from the ProceedingJoinPoint&lt;/span&gt;        Object obj = pjp.proceed();        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Completed executing the AOP intercept&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; obj;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-custom-validation-logic-to-validate-input-json-payload&quot;&gt;Custom validation logic to validate input JSON payload&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Class where we perform the basic validation, to demonstrate basic validation&lt;ul&gt;&lt;li&gt;Where we check if the input Customer JSON payload received contains name attribute and should NOT be empty.&lt;/li&gt;&lt;li&gt;Also checking if the address attributes should be available.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.InvalidInputException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonProcessingException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidateInput&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;validateRequest&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Customer customer)&lt;/span&gt;&lt;/span&gt;{       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;( Objects.isNull(customer.getName()) || customer.getName().isEmpty()){           &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - name cannot be null&quot;&lt;/span&gt;);       }       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;( Objects.isNull(customer.getAddresses())               || (Objects.nonNull(customer.getAddresses()) &amp;amp;&amp;amp; customer.getAddresses().isEmpty())){           &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - address cannot be null&quot;&lt;/span&gt;);       }    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-customer-and-address-pojo-class&quot;&gt;Customer and Address POJO class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple POJO class defining Customer related info&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.dto;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Builder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Address&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String addressLine1;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String addressLine2;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String aptNo;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String city;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String state;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; zipcode;}&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.dto;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Builder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Customer&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String name;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; id;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String department;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; List&amp;lt;Address&amp;gt; addresses;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-controller-class&quot;&gt;Controller class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;A simple controller object&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.controller;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.config.ValidateInputRequest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.ResponseEntity;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.service.CustomerService;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomerController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; CustomerService customerService;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/customer&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// the annotation can be used at controller method, commented for now&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;List&amp;lt;Customer&amp;gt;&amp;gt; getCustomers(){        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(customerService.getAllCustomers());    }    &lt;span class=&quot;hljs-meta&quot;&gt;@PostMapping(&quot;/customer&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;addCustomer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestBody&lt;/span&gt; Customer customer)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(customerService.addCustomer(customer));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-service-class&quot;&gt;Service class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Service layer where we have included the custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Have used List of items to load when the application is successfully started&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.config.ValidateInputRequest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Address;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.ArrayList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Customer&amp;gt; inMemoryDb = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; List&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getAllCustomers&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; fetchCustomers();    }    &lt;span class=&quot;hljs-comment&quot;&gt;//The annotation which will be intercepted by AOP&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Customer &lt;span class=&quot;hljs-title&quot;&gt;addCustomer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Customer customer)&lt;/span&gt; &lt;/span&gt;{        inMemoryDb.add(customer);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; customer;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;protected&lt;/span&gt; List&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;fetchCustomers&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inMemoryDb;    }    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; {        Address address1 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;work adddress of customer1&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Customer customer1 = Customer.builder()                .name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;user1&quot;&lt;/span&gt;)                .addresses(List.of(address1))                .build();        Address address20 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;work address customer2&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Address address21 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;home address customer2&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Customer customer2 = Customer.builder()                .name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;user2&quot;&lt;/span&gt;)                .addresses(List.of(address20, address21))                .build();        inMemoryDb.add(customer1);        inMemoryDb.add(customer2);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-custom-exception&quot;&gt;Custom Exception&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Creating custom Exception extending RuntimeException, used to throw this exception when validating the input JSON payload.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvalidInputException&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RuntimeException&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvalidInputException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String message)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;SpringBoot Application entry point&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.EnableAspectJAutoProxy;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;DemoApplication&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{      SpringApplication.run(DemoApplication.class, args);   }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-project-structure-snapshot&quot;&gt;Project structure snapshot&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/197376393-af8db8c9-d9e8-4aa5-8598-c66cba5b8320.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;h4 id=&quot;heading-curl-command-to-send-an-json-payload-with-empty-customer-name&quot;&gt;Curl command to send an JSON payload with empty Customer name&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The output with the below response will trigger an exception in output&lt;/li&gt;&lt;li&gt;&lt;pre&gt;&lt;code&gt;curl -X POST -H &lt;span class=&quot;hljs-string&quot;&gt;&quot;Content-Type:application/json&quot;&lt;/span&gt; http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/customer -d &apos;{&quot;name&quot;:&quot;&quot;,&quot;id&quot;:0,&quot;department&quot;:null,&quot;addresses&quot;:[{&quot;addressLine1&quot;:&quot;work adddress of customer3&quot;,&quot;addressLine2&quot;:null,&quot;aptNo&quot;:null,&quot;city&quot;:&quot;city1&quot;,&quot;state&quot;:null,&quot;zipcode&quot;:0}]}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Exception message&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;2022-10-23T04:42:35.931+00:00&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;status&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;error&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;trace&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;com.app.demo.demo.InvalidInputException: Invalid input - name cannot be null\r\n\tat com.app.demo.demo.config.ValidateInput.validateRequest(ValidateInput.java:19)com.app.demo.demo.config.ValidationAspectConfig.validateInput(ValidationAspectConfig.java:38)java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.base/java.lang.reflect.Method.invoke(Method.java:568)org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)com.app.demo.demo.service.CustomerService$$EnhancerBySpringCGLIB$$e764f31c.addCustomer(&amp;lt;generated&amp;gt;)com.app.demo.demo.controller.CustomerController.addCustomer(CustomerController.java:29)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.base/java.lang.reflect.Method.invoke(Method.java:568) ........org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:833)\r\n&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - name cannot be null&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;path&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api/customer&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-validate-input-json-payload-with-springboot-aop&quot;&gt;Validate input JSON payload with SpringBoot AOP&lt;/h2&gt;&lt;p&gt;In this blog will demonstrate an use case to use SpringBoot AOP to perform input validation in the &lt;code&gt;@Controller&lt;/code&gt; or &lt;code&gt;@Service&lt;/code&gt; layer level.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pre-requisites&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Basic understanding of AOP concept like Point Cut, ProceedingJointPoint, Adivces - Around, Before , After, etc.&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-use-case-validate-payload-in-controller-or-service-layer&quot;&gt;Use case - Validate payload in controller or service layer&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;When building REST based application at circumstance we might need to perform customized validation on the JSON payload before passing request to the repository layer or further next layer.&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Defining JSON schema, is another possible option this might requires more coding effort.&lt;/p&gt;&lt;p&gt;The validation can be performed using the &lt;code&gt;hibernate-validator&lt;/code&gt;, with built-in annotation &lt;code&gt;@NotNull&lt;/code&gt;, &lt;code&gt;@NotEmpty&lt;/code&gt;, etc. defined in the entity class.&lt;/p&gt;&lt;/blockquote&gt;&lt;ul&gt;&lt;li&gt;Create SpringBoot project using &lt;code&gt;start.spring.io&lt;/code&gt; with &lt;code&gt;spring web&lt;/code&gt; and &lt;code&gt;lombok&lt;/code&gt; dependencies.&lt;/li&gt;&lt;li&gt;Add the Spring starter AOP dependencies in the &lt;code&gt;pom.xml&lt;/code&gt;, like below&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-aop&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p&gt;In this blog have included few additional points,&lt;/p&gt;&lt;ul&gt;&lt;li&gt;How to easily create builder pattern on POJO using &lt;code&gt;@Build&lt;/code&gt; annotation from Lombok project &lt;/li&gt;&lt;li&gt;Extending RuntimeException to create custom exception used to handle Input validation in this case&lt;/li&gt;&lt;li&gt;Custom Spring annotation creation and registering it in AOP &lt;code&gt;@Around&lt;/code&gt; advice which will be invoked and used to intercept the method calls&lt;/li&gt;&lt;li&gt;&lt;code&gt;java.utils.Objects&lt;/code&gt; to validate null. Objects contains few other methods which is not detailed here&lt;/li&gt;&lt;li&gt;Java feature to perform &lt;code&gt;instanceof&lt;/code&gt; check and directly store the converted data to variable&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// Code where the Object instanceof Customer and the converted data stored in customers&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ( requestObject.length &amp;gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;  &amp;amp;&amp;amp; requestObject[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;instanceof&lt;/span&gt; Customer customers ){        &lt;span class=&quot;hljs-comment&quot;&gt;// first object in the arguments&lt;/span&gt;        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (Objects.isNull(customers)){            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Input invalid - Cannot be null&quot;&lt;/span&gt;);        }  &lt;span class=&quot;hljs-comment&quot;&gt;//.....&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Info:-&lt;/strong&gt;&lt;/p&gt;&lt;p&gt; SpringBoot AOP only used to intercept methods.  For advanced feature we need to use AspectJ, for example to check if fields have changed.&lt;/p&gt;&lt;/blockquote&gt;&lt;h3 id=&quot;heading-code&quot;&gt;Code&lt;/h3&gt;&lt;h4 id=&quot;heading-create-spring-annotation&quot;&gt;Create Spring Annotation&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Create Spring Annotation, which will be configured in the Aspect &lt;code&gt;@Around&lt;/code&gt; advice class.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.ElementType;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.Retention;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.RetentionPolicy;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.lang.annotation.Target;&lt;span class=&quot;hljs-meta&quot;&gt;@Target(ElementType.METHOD)&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-meta&quot;&gt;@interface&lt;/span&gt; ValidateInputRequest {}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-create-aspect-to-intercept-the-method-calls&quot;&gt;Create Aspect to intercept the method calls&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Below code defines the Aspect using &lt;code&gt;@Aspect&lt;/code&gt; annotation (note, this aspect needs to be regiestered as a bean using &lt;code&gt;@Component&lt;/code&gt;).&lt;/li&gt;&lt;li&gt;The custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt; in the previous code snippet is registered in the &lt;code&gt;@Around&lt;/code&gt; advice.&lt;/li&gt;&lt;li&gt;The Aspect class &lt;code&gt;validateInput()&lt;/code&gt; method will be invoked if the custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt; is annotated on the method defined in &lt;code&gt;@Controller&lt;/code&gt; or &lt;code&gt;@Service&lt;/code&gt; layer.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.InvalidInputException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.extern.slf4j.Slf4j;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.ProceedingJoinPoint;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Around;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Aspect;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Arrays;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Optional;&lt;span class=&quot;hljs-meta&quot;&gt;@Aspect&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Slf4j&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidationAspectConfig&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-comment&quot;&gt;//Using the Around advice, with the Annotation created and place the annotation &lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//over the method will invoke this call&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@Around(&quot;@annotation(ValidateInputRequest)&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Object &lt;span class=&quot;hljs-title&quot;&gt;validateInput&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ProceedingJoinPoint  pjp)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Throwable &lt;/span&gt;{        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;AOP intercept for method - &quot;&lt;/span&gt;+pjp.getSignature());        Object[] requestObject = pjp.getArgs();        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; ( requestObject.length &amp;gt;&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;  &amp;amp;&amp;amp;requestObject[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] &lt;span class=&quot;hljs-keyword&quot;&gt;instanceof&lt;/span&gt; Customer customers ){            &lt;span class=&quot;hljs-comment&quot;&gt;// first object in the arguments&lt;/span&gt;            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (Objects.isNull(customers)){                &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Input invalid - Cannot be null&quot;&lt;/span&gt;);            }            &lt;span class=&quot;hljs-comment&quot;&gt;//Performing validation for the input request intercepted and received&lt;/span&gt;            ValidateInput.validateRequest(customers);        }&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;{            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;input object is not of customer instance&quot;&lt;/span&gt;);        }        &lt;span class=&quot;hljs-comment&quot;&gt;//just obtain the obj from the ProceedingJoinPoint&lt;/span&gt;        Object obj = pjp.proceed();        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Completed executing the AOP intercept&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; obj;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-custom-validation-logic-to-validate-input-json-payload&quot;&gt;Custom validation logic to validate input JSON payload&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Class where we perform the basic validation, to demonstrate basic validation&lt;ul&gt;&lt;li&gt;Where we check if the input Customer JSON payload received contains name attribute and should NOT be empty.&lt;/li&gt;&lt;li&gt;Also checking if the address attributes should be available.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.config;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.InvalidInputException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonProcessingException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Objects;&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ValidateInput&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;validateRequest&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Customer customer)&lt;/span&gt;&lt;/span&gt;{       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;( Objects.isNull(customer.getName()) || customer.getName().isEmpty()){           &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - name cannot be null&quot;&lt;/span&gt;);       }       &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt;( Objects.isNull(customer.getAddresses())               || (Objects.nonNull(customer.getAddresses()) &amp;amp;&amp;amp; customer.getAddresses().isEmpty())){           &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; InvalidInputException(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - address cannot be null&quot;&lt;/span&gt;);       }    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-customer-and-address-pojo-class&quot;&gt;Customer and Address POJO class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Simple POJO class defining Customer related info&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.dto;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Builder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Address&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String addressLine1;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String addressLine2;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String aptNo;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String city;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String state;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; zipcode;}&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.dto;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.AllArgsConstructor;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Builder;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.Data;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; lombok.NoArgsConstructor;&lt;span class=&quot;hljs-meta&quot;&gt;@Data&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@NoArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@AllArgsConstructor&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;Customer&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String name;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; id;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String department;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; List&amp;lt;Address&amp;gt; addresses;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-controller-class&quot;&gt;Controller class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;A simple controller object&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.controller;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.config.ValidateInputRequest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.beans.factory.annotation.Autowired;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.http.ResponseEntity;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.*;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.service.CustomerService;&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/api&quot;)&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomerController&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-meta&quot;&gt;@Autowired&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; CustomerService customerService;    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/customer&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;// the annotation can be used at controller method, commented for now&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;List&amp;lt;Customer&amp;gt;&amp;gt; getCustomers(){        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(customerService.getAllCustomers());    }    &lt;span class=&quot;hljs-meta&quot;&gt;@PostMapping(&quot;/customer&quot;)&lt;/span&gt;    &lt;span class=&quot;hljs-comment&quot;&gt;//@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; ResponseEntity&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;addCustomer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@RequestBody&lt;/span&gt; Customer customer)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; ResponseEntity.ok(customerService.addCustomer(customer));    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-service-class&quot;&gt;Service class&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Service layer where we have included the custom annotation &lt;code&gt;@ValidateInputRequest&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Have used List of items to load when the application is successfully started&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo.service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.config.ValidateInputRequest;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Address;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.app.demo.dto.Customer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.ArrayList;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;CustomerService&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; List&amp;lt;Customer&amp;gt; inMemoryDb = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ArrayList&amp;lt;&amp;gt;();    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; List&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;getAllCustomers&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; fetchCustomers();    }    &lt;span class=&quot;hljs-comment&quot;&gt;//The annotation which will be intercepted by AOP&lt;/span&gt;    &lt;span class=&quot;hljs-meta&quot;&gt;@ValidateInputRequest&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Customer &lt;span class=&quot;hljs-title&quot;&gt;addCustomer&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Customer customer)&lt;/span&gt; &lt;/span&gt;{        inMemoryDb.add(customer);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; customer;    }    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;protected&lt;/span&gt; List&amp;lt;Customer&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;fetchCustomers&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inMemoryDb;    }    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; {        Address address1 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;work adddress of customer1&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Customer customer1 = Customer.builder()                .name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;user1&quot;&lt;/span&gt;)                .addresses(List.of(address1))                .build();        Address address20 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;work address customer2&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Address address21 = Address.builder()                .addressLine1(&lt;span class=&quot;hljs-string&quot;&gt;&quot;home address customer2&quot;&lt;/span&gt;)                .city(&lt;span class=&quot;hljs-string&quot;&gt;&quot;city1&quot;&lt;/span&gt;).build();        Customer customer2 = Customer.builder()                .name(&lt;span class=&quot;hljs-string&quot;&gt;&quot;user2&quot;&lt;/span&gt;)                .addresses(List.of(address20, address21))                .build();        inMemoryDb.add(customer1);        inMemoryDb.add(customer2);    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-custom-exception&quot;&gt;Custom Exception&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Creating custom Exception extending RuntimeException, used to throw this exception when validating the input JSON payload.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvalidInputException&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;RuntimeException&lt;/span&gt;&lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;InvalidInputException&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String message)&lt;/span&gt;&lt;/span&gt;{        &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;(message);    }}&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;SpringBoot Application entry point&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.app.demo;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.SpringApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.boot.autoconfigure.SpringBootApplication;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.context.annotation.EnableAspectJAutoProxy;&lt;span class=&quot;hljs-meta&quot;&gt;@SpringBootApplication&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;DemoApplication&lt;/span&gt; &lt;/span&gt;{   &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;/span&gt;{      SpringApplication.run(DemoApplication.class, args);   }}&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-project-structure-snapshot&quot;&gt;Project structure snapshot&lt;/h3&gt;&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/6425536/197376393-af8db8c9-d9e8-4aa5-8598-c66cba5b8320.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;&lt;h3 id=&quot;heading-output&quot;&gt;Output&lt;/h3&gt;&lt;h4 id=&quot;heading-curl-command-to-send-an-json-payload-with-empty-customer-name&quot;&gt;Curl command to send an JSON payload with empty Customer name&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The output with the below response will trigger an exception in output&lt;/li&gt;&lt;li&gt;&lt;pre&gt;&lt;code&gt;curl -X POST -H &lt;span class=&quot;hljs-string&quot;&gt;&quot;Content-Type:application/json&quot;&lt;/span&gt; http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:8080/api/customer -d &apos;{&quot;name&quot;:&quot;&quot;,&quot;id&quot;:0,&quot;department&quot;:null,&quot;addresses&quot;:[{&quot;addressLine1&quot;:&quot;work adddress of customer3&quot;,&quot;addressLine2&quot;:null,&quot;aptNo&quot;:null,&quot;city&quot;:&quot;city1&quot;,&quot;state&quot;:null,&quot;zipcode&quot;:0}]}&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Exception message&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;2022-10-23T04:42:35.931+00:00&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;status&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;error&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Internal Server Error&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;trace&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;com.app.demo.demo.InvalidInputException: Invalid input - name cannot be null\r\n\tat com.app.demo.demo.config.ValidateInput.validateRequest(ValidateInput.java:19)com.app.demo.demo.config.ValidationAspectConfig.validateInput(ValidationAspectConfig.java:38)java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.base/java.lang.reflect.Method.invoke(Method.java:568)org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:634)org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:624)org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:72)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)com.app.demo.demo.service.CustomerService$$EnhancerBySpringCGLIB$$e764f31c.addCustomer(&amp;lt;generated&amp;gt;)com.app.demo.demo.controller.CustomerController.addCustomer(CustomerController.java:29)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)java.base/java.lang.reflect.Method.invoke(Method.java:568) ........org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789)org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.base/java.lang.Thread.run(Thread.java:833)\r\n&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;message&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;Invalid input - name cannot be null&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;path&quot;&lt;/span&gt;:&lt;span class=&quot;hljs-string&quot;&gt;&quot;/api/customer&quot;&lt;/span&gt;}&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item><item><title><![CDATA[Parse part of JSON string using Java]]></title><description><![CDATA[Given a string in JSON format parse only part of the JSON using Java library without mapping to POJO's

When working with JSON objects, there are possible scenarios where we only need a part of the JSON. 
Mostly in this scenario, we also don't want t...]]></description><link>https://thirumurthi.hashnode.dev/parse-part-of-json-string-using-java</link><guid isPermaLink="true">https://thirumurthi.hashnode.dev/parse-part-of-json-string-using-java</guid><category><![CDATA[jackson]]></category><category><![CDATA[json]]></category><category><![CDATA[Java]]></category><category><![CDATA[jsonpath]]></category><dc:creator><![CDATA[Thirumurthi S]]></dc:creator><pubDate>Sun, 09 Oct 2022 00:17:24 GMT</pubDate><content:encoded>&lt;![CDATA[&lt;h2 id=&quot;heading-given-a-string-in-json-format-parse-only-part-of-the-json-using-java-library-without-mapping-to-pojos&quot;&gt;Given a string in JSON format parse only part of the JSON using Java library without mapping to POJO&apos;s&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;When working with JSON objects, there are possible scenarios where we only need a part of the JSON. &lt;/li&gt;&lt;li&gt;&lt;p&gt;Mostly in this scenario, we also don&apos;t want to create dedicated POJO&apos;s to map the properties.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For example, &lt;/p&gt;&lt;ul&gt;&lt;li&gt;In a case when working with third party API&apos;s returning JSON repsonse, and if our requirement is to only use part of that JSON.&lt;/li&gt;&lt;li&gt;Say, below is the sample JSON from the third-party API, and we need to check only the status property.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;app&quot;&lt;/span&gt; : {          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;demo-app&quot;&lt;/span&gt;,          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;version&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;1.0&quot;&lt;/span&gt;,          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;description&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;simple app demo&quot;&lt;/span&gt;          },   &lt;span class=&quot;hljs-attr&quot;&gt;&quot;request&quot;&lt;/span&gt; : {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;status&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;ACCEPTED&quot;&lt;/span&gt;     },      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;details&quot;&lt;/span&gt; : [          {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;endpoint&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://domain.com/api/v1/user&quot;&lt;/span&gt;},          {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;trackId&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;1234554321&quot;&lt;/span&gt; },   ]   }&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To fetch the status we can represent the Json path like &lt;code&gt;request.status&lt;/code&gt;. &lt;ul&gt;&lt;li&gt;In JsonPath library, the path can be represented &lt;code&gt;$.request.status&lt;/code&gt;&lt;/li&gt;&lt;li&gt;In Fasterxml library, the path can be represented &lt;code&gt;/request/status&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;In this blog have demonstrated how to parse part of the JSON using two types java Json parsing library&lt;ul&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/json-path/JsonPath&quot;&gt;Jayway Jsonpath&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Fasterxml Jackson&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-1-using-jayway-jsonpath-library-to-fetch-part-of-the-json-value-provided-the-path-till-the-key-property&quot;&gt;1. Using &lt;code&gt;Jayway Jsonpath&lt;/code&gt; library to fetch part of the json value provided the path till the key property&lt;/h3&gt;&lt;h4 id=&quot;heading-add-dependency-in-pomxml&quot;&gt;Add dependency in &lt;code&gt;pom.xml&lt;/code&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The Jayway jsonpath requires slf4j jars&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.jayway.jsonpath&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;json-path&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.slf4j&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;slf4j-api&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;1.7.36&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.slf4j&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;1.7.30&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-java-code-using-the-jsonpath-library-to-fetch-part-of-the-json&quot;&gt;Java code using the jsonpath library to fetch part of the json&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We specify the path part of the command, JsonPath.compile().&lt;/li&gt;&lt;li&gt;Using the  JsonPath.compile().read(), will return the value of the json specified in the path.&lt;/li&gt;&lt;li&gt;Additionally, have used BiFunction&amp;lt;&amp;gt; Lambda functions as example usage for points.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; org.example;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.jayway.jsonpath.JsonPath;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.function.BiFunction;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JaywayJsonPathBasedJSONParser&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt;&lt;/span&gt;{        String inputJson = getJsonString();        &lt;span class=&quot;hljs-comment&quot;&gt;// define the path the $ - represents the root&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// path is represented with `.`&lt;/span&gt;        JsonPath jsonPath = JsonPath.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;$.store.bicycle.color&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;// parse json string for the path&lt;/span&gt;        String bicycleColor = jsonPath.read(inputJson);        &lt;span class=&quot;hljs-comment&quot;&gt;// print the parsed string&lt;/span&gt;        System.out.println(bicycleColor);        &lt;span class=&quot;hljs-comment&quot;&gt;// additionally below is a representation just parsing hte &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// in this case the path returns List&amp;lt;&amp;gt; which is json Array &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// the list of book will be returned as List of map&lt;/span&gt;        String bookJsonPathExpression = &lt;span class=&quot;hljs-string&quot;&gt;&quot;$.store.book&quot;&lt;/span&gt;;        List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt; result = fetchMapUsingPath.apply(inputJson,bookJsonPathExpression);        result.forEach( (item)-&amp;gt;{            item.forEach((key,value)-&amp;gt;{System.out.println(key+&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;+value);});            System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;--------------------------&quot;&lt;/span&gt;);        });    }    &lt;span class=&quot;hljs-comment&quot;&gt;//Below is a Function definition to convert &lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; BiFunction&amp;lt;String, String , List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt;&amp;gt; fetchMapUsingPath = (jsonString, pathExpression)-&amp;gt;{        JsonPath jsonPath = JsonPath.compile(pathExpression);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; jsonPath.read(jsonString);    } ;    &lt;span class=&quot;hljs-comment&quot;&gt;/**     * The method to return the simple json as string     * &lt;span class=&quot;hljs-doctag&quot;&gt;@return&lt;/span&gt;     */&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getJsonString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String inputJson = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;                {                    &quot;&lt;/span&gt;store&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                        &quot;&lt;/span&gt;book&lt;span class=&quot;hljs-string&quot;&gt;&quot;: [                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;sci-fi&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Douglas Adams&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;The &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; dark tea-time of the soul&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 14.25                            },                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;fiction&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Stella Gibbons&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Cold comfort farm&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;isbn&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;-&lt;span class=&quot;hljs-number&quot;&gt;1476783000&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 13.79                            }                        ],                        &quot;&lt;/span&gt;bicycle&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                            &quot;&lt;/span&gt;color&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;blue&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                            &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 39.99                        }                    },                    &quot;&lt;/span&gt;expensive&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 10                }                &quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inputJson;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output&quot;&gt;Output:&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;blue&lt;span class=&quot;hljs-attr&quot;&gt;category&lt;/span&gt; : sci-fi&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Douglas Adams&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : The long dark tea-time &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the soul&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;14.25&lt;/span&gt;-----------------category : fiction&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Stella Gibbons&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : Cold comfort farm&lt;span class=&quot;hljs-attr&quot;&gt;isbn&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-1476783000&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;13.79&lt;/span&gt;-----------------&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-2-using-fasterxml-jackson-library-to-parse-part-of-the-json-using-the-provided-json-key-as-path&quot;&gt;2. Using &lt;code&gt;Fasterxml Jackson&lt;/code&gt; library to parse part of the json using the provided json key as path.&lt;/h3&gt;&lt;h4 id=&quot;heading-add-below-dependency-in-pomxml-to-load-the-fasterxml-jackson-library&quot;&gt;Add below dependency in &lt;code&gt;pom.xml&lt;/code&gt; to load the fasterxml jackson library&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-databind&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-annotations&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-java-code-uses-the-jackson-library-to-fetch-the-part-of-json&quot;&gt;Java code uses the jackson library to fetch the part of JSON&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Using ObjectMapper read the complete json as Jsonnode&lt;/li&gt;&lt;li&gt;Defining a JsonPointer with path to the JSON specified properties&lt;/li&gt;&lt;li&gt;With the returned JsonNode, use the at(&amp;lt;pass the JsonPointer) method to read the value&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; org.example;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonPointer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonProcessingException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.type.TypeReference;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.JsonNode;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JacksonBasedJSONParser&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;// json input string&lt;/span&gt;        String inputJson = getJsonString();        &lt;span class=&quot;hljs-comment&quot;&gt;// jackson ObjectMapper object&lt;/span&gt;        ObjectMapper objectMapper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();        &lt;span class=&quot;hljs-comment&quot;&gt;//path represented using / to fetch the color&lt;/span&gt;        JsonPointer bicycleColorPointer = JsonPointer.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/store/bicycle/color&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//path represented to fetch book list&lt;/span&gt;        JsonPointer bookJsonPathPointer = JsonPointer.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/store/book&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {            JsonNode completeJsonNode = objectMapper.readValue(inputJson,JsonNode.class);            String bicycleColor = completeJsonNode.at(bicycleColorPointer).toString();            //print bicycelcolor             System.out.println(bicycleColor);            List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt; bookList = objectMapper.readValue(completeJsonNode.at(bookJsonPathPointer).toString(),&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; TypeReference&amp;lt;&amp;gt;(){});            bookList.forEach( (item)-&amp;gt;{                item.forEach((key,value)-&amp;gt;{                    System.out.println(key+&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;+value);                });                System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;------------------------&quot;&lt;/span&gt;);            });        } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (JsonProcessingException e) {            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RuntimeException(e);        }    }    &lt;span class=&quot;hljs-comment&quot;&gt;/**     * This method returns the json string sample     * &lt;span class=&quot;hljs-doctag&quot;&gt;@return&lt;/span&gt;     */&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getJsonString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String inputJson = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;                {                    &quot;&lt;/span&gt;store&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                        &quot;&lt;/span&gt;book&lt;span class=&quot;hljs-string&quot;&gt;&quot;: [                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;sci-fi&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Douglas Adams&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;The &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; dark tea-time of the soul&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 14.25                            },                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;fiction&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Stella Gibbons&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Cold comfort farm&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;isbn&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;-&lt;span class=&quot;hljs-number&quot;&gt;1476783000&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 13.79                            }                        ],                        &quot;&lt;/span&gt;bicycle&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                            &quot;&lt;/span&gt;color&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;blue&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                            &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 39.99                        }                    },                    &quot;&lt;/span&gt;expensive&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 10                }                &quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inputJson;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output&quot;&gt;Output:&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;category&lt;/span&gt; : sci-fi&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Douglas Adams&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : The long dark tea-time &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the soul&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;14.25&lt;/span&gt;------------------------category : fiction&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Stella Gibbons&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : Cold comfort farm&lt;span class=&quot;hljs-attr&quot;&gt;isbn&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-1476783000&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;13.79&lt;/span&gt;------------------------&lt;/code&gt;&lt;/pre&gt;]]&gt;</content:encoded><hashnode:content>&lt;![CDATA[&lt;h2 id=&quot;heading-given-a-string-in-json-format-parse-only-part-of-the-json-using-java-library-without-mapping-to-pojos&quot;&gt;Given a string in JSON format parse only part of the JSON using Java library without mapping to POJO&apos;s&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;When working with JSON objects, there are possible scenarios where we only need a part of the JSON. &lt;/li&gt;&lt;li&gt;&lt;p&gt;Mostly in this scenario, we also don&apos;t want to create dedicated POJO&apos;s to map the properties.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;For example, &lt;/p&gt;&lt;ul&gt;&lt;li&gt;In a case when working with third party API&apos;s returning JSON repsonse, and if our requirement is to only use part of that JSON.&lt;/li&gt;&lt;li&gt;Say, below is the sample JSON from the third-party API, and we need to check only the status property.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-json&quot;&gt;{  &lt;span class=&quot;hljs-attr&quot;&gt;&quot;app&quot;&lt;/span&gt; : {          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;name&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;demo-app&quot;&lt;/span&gt;,          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;version&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;1.0&quot;&lt;/span&gt;,          &lt;span class=&quot;hljs-attr&quot;&gt;&quot;description&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;simple app demo&quot;&lt;/span&gt;          },   &lt;span class=&quot;hljs-attr&quot;&gt;&quot;request&quot;&lt;/span&gt; : {        &lt;span class=&quot;hljs-attr&quot;&gt;&quot;status&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;ACCEPTED&quot;&lt;/span&gt;     },      &lt;span class=&quot;hljs-attr&quot;&gt;&quot;details&quot;&lt;/span&gt; : [          {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;endpoint&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;http://domain.com/api/v1/user&quot;&lt;/span&gt;},          {&lt;span class=&quot;hljs-attr&quot;&gt;&quot;trackId&quot;&lt;/span&gt; : &lt;span class=&quot;hljs-string&quot;&gt;&quot;1234554321&quot;&lt;/span&gt; },   ]   }&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;To fetch the status we can represent the Json path like &lt;code&gt;request.status&lt;/code&gt;. &lt;ul&gt;&lt;li&gt;In JsonPath library, the path can be represented &lt;code&gt;$.request.status&lt;/code&gt;&lt;/li&gt;&lt;li&gt;In Fasterxml library, the path can be represented &lt;code&gt;/request/status&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;In this blog have demonstrated how to parse part of the JSON using two types java Json parsing library&lt;ul&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/json-path/JsonPath&quot;&gt;Jayway Jsonpath&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;ol&gt;&lt;li&gt;&lt;a target=&quot;_blank&quot; href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Fasterxml Jackson&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 id=&quot;heading-1-using-jayway-jsonpath-library-to-fetch-part-of-the-json-value-provided-the-path-till-the-key-property&quot;&gt;1. Using &lt;code&gt;Jayway Jsonpath&lt;/code&gt; library to fetch part of the json value provided the path till the key property&lt;/h3&gt;&lt;h4 id=&quot;heading-add-dependency-in-pomxml&quot;&gt;Add dependency in &lt;code&gt;pom.xml&lt;/code&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;The Jayway jsonpath requires slf4j jars&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.jayway.jsonpath&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;json-path&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.7.0&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.slf4j&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;slf4j-api&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;1.7.36&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.slf4j&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;slf4j-simple&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;1.7.30&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-java-code-using-the-jsonpath-library-to-fetch-part-of-the-json&quot;&gt;Java code using the jsonpath library to fetch part of the json&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;We specify the path part of the command, JsonPath.compile().&lt;/li&gt;&lt;li&gt;Using the  JsonPath.compile().read(), will return the value of the json specified in the path.&lt;/li&gt;&lt;li&gt;Additionally, have used BiFunction&amp;lt;&amp;gt; Lambda functions as example usage for points.&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; org.example;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.jayway.jsonpath.JsonPath;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.function.BiFunction;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JaywayJsonPathBasedJSONParser&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt;&lt;/span&gt;{        String inputJson = getJsonString();        &lt;span class=&quot;hljs-comment&quot;&gt;// define the path the $ - represents the root&lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// path is represented with `.`&lt;/span&gt;        JsonPath jsonPath = JsonPath.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;$.store.bicycle.color&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;// parse json string for the path&lt;/span&gt;        String bicycleColor = jsonPath.read(inputJson);        &lt;span class=&quot;hljs-comment&quot;&gt;// print the parsed string&lt;/span&gt;        System.out.println(bicycleColor);        &lt;span class=&quot;hljs-comment&quot;&gt;// additionally below is a representation just parsing hte &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// in this case the path returns List&amp;lt;&amp;gt; which is json Array &lt;/span&gt;        &lt;span class=&quot;hljs-comment&quot;&gt;// the list of book will be returned as List of map&lt;/span&gt;        String bookJsonPathExpression = &lt;span class=&quot;hljs-string&quot;&gt;&quot;$.store.book&quot;&lt;/span&gt;;        List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt; result = fetchMapUsingPath.apply(inputJson,bookJsonPathExpression);        result.forEach( (item)-&amp;gt;{            item.forEach((key,value)-&amp;gt;{System.out.println(key+&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;+value);});            System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;--------------------------&quot;&lt;/span&gt;);        });    }    &lt;span class=&quot;hljs-comment&quot;&gt;//Below is a Function definition to convert &lt;/span&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; BiFunction&amp;lt;String, String , List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt;&amp;gt; fetchMapUsingPath = (jsonString, pathExpression)-&amp;gt;{        JsonPath jsonPath = JsonPath.compile(pathExpression);        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; jsonPath.read(jsonString);    } ;    &lt;span class=&quot;hljs-comment&quot;&gt;/**     * The method to return the simple json as string     * &lt;span class=&quot;hljs-doctag&quot;&gt;@return&lt;/span&gt;     */&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getJsonString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String inputJson = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;                {                    &quot;&lt;/span&gt;store&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                        &quot;&lt;/span&gt;book&lt;span class=&quot;hljs-string&quot;&gt;&quot;: [                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;sci-fi&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Douglas Adams&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;The &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; dark tea-time of the soul&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 14.25                            },                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;fiction&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Stella Gibbons&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Cold comfort farm&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;isbn&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;-&lt;span class=&quot;hljs-number&quot;&gt;1476783000&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 13.79                            }                        ],                        &quot;&lt;/span&gt;bicycle&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                            &quot;&lt;/span&gt;color&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;blue&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                            &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 39.99                        }                    },                    &quot;&lt;/span&gt;expensive&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 10                }                &quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inputJson;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output&quot;&gt;Output:&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;blue&lt;span class=&quot;hljs-attr&quot;&gt;category&lt;/span&gt; : sci-fi&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Douglas Adams&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : The long dark tea-time &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the soul&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;14.25&lt;/span&gt;-----------------category : fiction&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Stella Gibbons&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : Cold comfort farm&lt;span class=&quot;hljs-attr&quot;&gt;isbn&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-1476783000&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;13.79&lt;/span&gt;-----------------&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;heading-2-using-fasterxml-jackson-library-to-parse-part-of-the-json-using-the-provided-json-key-as-path&quot;&gt;2. Using &lt;code&gt;Fasterxml Jackson&lt;/code&gt; library to parse part of the json using the provided json key as path.&lt;/h3&gt;&lt;h4 id=&quot;heading-add-below-dependency-in-pomxml-to-load-the-fasterxml-jackson-library&quot;&gt;Add below dependency in &lt;code&gt;pom.xml&lt;/code&gt; to load the fasterxml jackson library&lt;/h4&gt;&lt;pre&gt;&lt;code class=&quot;lang-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-databind&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;jackson-annotations&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;2.13.4&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-java-code-uses-the-jackson-library-to-fetch-the-part-of-json&quot;&gt;Java code uses the jackson library to fetch the part of JSON&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Using ObjectMapper read the complete json as Jsonnode&lt;/li&gt;&lt;li&gt;Defining a JsonPointer with path to the JSON specified properties&lt;/li&gt;&lt;li&gt;With the returned JsonNode, use the at(&amp;lt;pass the JsonPointer) method to read the value&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code class=&quot;lang-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; org.example;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonPointer;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.JsonProcessingException;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.core.type.TypeReference;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.JsonNode;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.fasterxml.jackson.databind.ObjectMapper;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.Map;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;JacksonBasedJSONParser&lt;/span&gt; &lt;/span&gt;{    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String ... args)&lt;/span&gt; &lt;/span&gt;{        &lt;span class=&quot;hljs-comment&quot;&gt;// json input string&lt;/span&gt;        String inputJson = getJsonString();        &lt;span class=&quot;hljs-comment&quot;&gt;// jackson ObjectMapper object&lt;/span&gt;        ObjectMapper objectMapper = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; ObjectMapper();        &lt;span class=&quot;hljs-comment&quot;&gt;//path represented using / to fetch the color&lt;/span&gt;        JsonPointer bicycleColorPointer = JsonPointer.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/store/bicycle/color&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-comment&quot;&gt;//path represented to fetch book list&lt;/span&gt;        JsonPointer bookJsonPathPointer = JsonPointer.compile(&lt;span class=&quot;hljs-string&quot;&gt;&quot;/store/book&quot;&lt;/span&gt;);        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {            JsonNode completeJsonNode = objectMapper.readValue(inputJson,JsonNode.class);            String bicycleColor = completeJsonNode.at(bicycleColorPointer).toString();            //print bicycelcolor             System.out.println(bicycleColor);            List&amp;lt;Map&amp;lt;String,Object&amp;gt;&amp;gt; bookList = objectMapper.readValue(completeJsonNode.at(bookJsonPathPointer).toString(),&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; TypeReference&amp;lt;&amp;gt;(){});            bookList.forEach( (item)-&amp;gt;{                item.forEach((key,value)-&amp;gt;{                    System.out.println(key+&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;+value);                });                System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;------------------------&quot;&lt;/span&gt;);            });        } &lt;span class=&quot;hljs-keyword&quot;&gt;catch&lt;/span&gt; (JsonProcessingException e) {            &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; RuntimeException(e);        }    }    &lt;span class=&quot;hljs-comment&quot;&gt;/**     * This method returns the json string sample     * &lt;span class=&quot;hljs-doctag&quot;&gt;@return&lt;/span&gt;     */&lt;/span&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String &lt;span class=&quot;hljs-title&quot;&gt;getJsonString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt;&lt;/span&gt;{        String inputJson = &lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;                {                    &quot;&lt;/span&gt;store&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                        &quot;&lt;/span&gt;book&lt;span class=&quot;hljs-string&quot;&gt;&quot;: [                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;sci-fi&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Douglas Adams&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;The &lt;span class=&quot;hljs-keyword&quot;&gt;long&lt;/span&gt; dark tea-time of the soul&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 14.25                            },                            {                                &quot;&lt;/span&gt;category&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;fiction&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;author&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Stella Gibbons&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;title&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;Cold comfort farm&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;isbn&lt;span class=&quot;hljs-string&quot;&gt;&quot; : &quot;&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;-&lt;span class=&quot;hljs-number&quot;&gt;1476783000&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                                &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 13.79                            }                        ],                        &quot;&lt;/span&gt;bicycle&lt;span class=&quot;hljs-string&quot;&gt;&quot;: {                            &quot;&lt;/span&gt;color&lt;span class=&quot;hljs-string&quot;&gt;&quot;: &quot;&lt;/span&gt;blue&lt;span class=&quot;hljs-string&quot;&gt;&quot;,                            &quot;&lt;/span&gt;price&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 39.99                        }                    },                    &quot;&lt;/span&gt;expensive&lt;span class=&quot;hljs-string&quot;&gt;&quot;: 10                }                &quot;&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;;        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; inputJson;    }}&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&quot;heading-output&quot;&gt;Output:&lt;/h4&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;category&lt;/span&gt; : sci-fi&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Douglas Adams&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : The long dark tea-time &lt;span class=&quot;hljs-keyword&quot;&gt;of&lt;/span&gt; the soul&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;14.25&lt;/span&gt;------------------------category : fiction&lt;span class=&quot;hljs-attr&quot;&gt;author&lt;/span&gt; : Stella Gibbons&lt;span class=&quot;hljs-attr&quot;&gt;title&lt;/span&gt; : Cold comfort farm&lt;span class=&quot;hljs-attr&quot;&gt;isbn&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;978&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;-1476783000&lt;/span&gt;&lt;span class=&quot;hljs-attr&quot;&gt;price&lt;/span&gt; : &lt;span class=&quot;hljs-number&quot;&gt;13.79&lt;/span&gt;------------------------&lt;/code&gt;&lt;/pre&gt;]]&gt;</hashnode:content></item></channel></rss>