<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Sagar Parmar</title>
    <description>The latest articles on Forem by Sagar Parmar (@sagar0419).</description>
    <link>https://forem.com/sagar0419</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F979074%2F32b5c956-a3a8-487a-a7ef-a3c85b7fbceb.jpeg</url>
      <title>Forem: Sagar Parmar</title>
      <link>https://forem.com/sagar0419</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sagar0419"/>
    <language>en</language>
    <item>
      <title>NVIDIA GPU Operator Explained: Simplifying GPU Workloads on Kubernetes</title>
      <dc:creator>Sagar Parmar</dc:creator>
      <pubDate>Wed, 05 Nov 2025 13:28:19 +0000</pubDate>
      <link>https://forem.com/aws-builders/nvidia-gpu-operator-explained-simplifying-gpu-workloads-on-kubernetes-479b</link>
      <guid>https://forem.com/aws-builders/nvidia-gpu-operator-explained-simplifying-gpu-workloads-on-kubernetes-479b</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdozo5dmd9t2f2dl1vvns.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdozo5dmd9t2f2dl1vvns.png" alt="Integrating NVIDIA GPU’s with Kubernetes.&amp;lt;br&amp;gt;
" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While GPUs have long been a staple in industries like gaming, video editing, CAD, and 3D rendering, their role has evolved dramatically over the years. Originally designed to handle graphics-intensive tasks, GPUs have proven to be powerful tools for a wide range of computationally demanding applications. Today, their ability to perform massive parallel processing has made them indispensable in modern fields such as data science, artificial intelligence and machine learning (AI/ML), robotics, cryptocurrency mining, and scientific computing. This shift was catalysed by the introduction of CUDA (Compute Unified Device Architecture) by NVIDIA in 2007, which unlocked the potential of GPUs for general-purpose computing. As a result, GPUs are no longer just graphics accelerators they’re now at the heart of cutting-edge innovation across industries.&lt;/p&gt;

&lt;p&gt;In this blog post we will discuss about NVIDIA GPU operator on Kubernetes and how to deploy it on the Kubernetes Cluster.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why run GPU workload on Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Running GPU workload on Kubernetes offer significant advantage because it enables developer to seamlessly schedule and run GPU powered application, it simplify deployment and scaling of these workloads. With Kubernetes, workloads can be easily scaled up or down based on demand, while features like Role-Based Access Control (RBAC) provide isolation and multi-tenancy for secure, shared environments. Additionally, Kubernetes supports the creation of multi-cloud GPU clusters, allowing organizations to leverage GPU resources across different cloud providers with consistent orchestration and control.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore the GPU-Kubernetes integration stack in depth with the help of NVIDIA GPU Operator. From the host operating system to the Kubernetes control plane, we’ll peel back each layer to understand the components required to make GPUs work seamlessly within a Kubernetes environment. More importantly, we’ll uncover why each component matters and how they interact with one another.&lt;/p&gt;
&lt;h2&gt;
  
  
  How are GPUs integrated into Kubernetes without using the GPU Operator?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfy761jrzcbboryl1vqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfy761jrzcbboryl1vqa.png" alt="Three Foundational Layers" width="720" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kubernetes excels at managing standard compute workloads, but orchestrating high-performance hardware like GPUs introduces unique challenges. Before diving into the GPU Operator, it’s important to understand the &lt;strong&gt;three foundational layers&lt;/strong&gt; required to run GPU workloads in Kubernetes. Think of it as a recipe, each step must be correctly configured for the GPU to function seamlessly within the cluster.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1: The Host Operating System
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxrpj1n81phrw9pmy3j0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxrpj1n81phrw9pmy3j0.png" alt="CUDA Toolkit" width="720" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything begins at the host level. The &lt;strong&gt;NVIDIA device driver&lt;/strong&gt; is the critical software that communicates directly with the GPU hardware. A key requirement here is &lt;strong&gt;version compatibility&lt;/strong&gt; between the driver and the &lt;strong&gt;CUDA toolkit&lt;/strong&gt; embedded in your container image. This compatibility matrix must be accurate any mismatch can break GPU functionality.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step-2: The container runtime e.g, Docker, Container-d, CRI-O, RunC etc.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyyioo7wigxl7h88rq5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdyyioo7wigxl7h88rq5f.png" alt="Bridging the gap between container runtime and the GPU." width="720" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we need a bridge between the container runtime (e.g., Docker, containerd, CRI-O) and the host GPU. This is where the &lt;strong&gt;NVIDIA Container Toolkit&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Functions of the Toolkit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPU Access Enablement&lt;/strong&gt;: Provides essential libraries like &lt;code&gt;libnvidia-container&lt;/code&gt; and &lt;code&gt;nvidia-container-cli&lt;/code&gt; to configure runtimes for GPU access.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runtime Configuration&lt;/strong&gt;: Injects GPU device files, drivers, and environment variables into containers via runtime hooks (e.g., updates to &lt;code&gt;/etc/containerd/config.toml&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Device Plugin Dependency&lt;/strong&gt;: The NVIDIA Device Plugin relies on the toolkit to expose GPU resources to Kubernetes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Abstraction Layer&lt;/strong&gt;: Allows containers to use GPUs without bundling drivers or CUDA libraries inside the image keeping containers lightweight and portable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this toolkit, containers remain unaware of the GPU hardware on the node.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step-3: The Kubernetes Orchestration layer.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8ae6dgg494mmwa9pv85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8ae6dgg494mmwa9pv85.png" alt="Device Plugin and it’s role." width="720" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, Kubernetes needs to recognize and schedule GPU resources. This is achieved through the &lt;strong&gt;NVIDIA Device Plugin&lt;/strong&gt;, which runs as a DaemonSet on GPU-enabled nodes.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Core Functions of the Device Plugin:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPU Discovery &amp;amp; Advertising&lt;/strong&gt;: Detects available GPUs and registers them with the Kubelet as extended resources (e.g., &lt;code&gt;nvidia.com/gpu&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Allocation&lt;/strong&gt;: When a pod requests a GPU, the plugin ensures the container receives the correct device files, drivers, and environment variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Health Monitoring&lt;/strong&gt;: Continuously checks GPU health and updates Kubernetes to prevent scheduling on faulty devices.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPU Sharing &amp;amp; Partitioning:&lt;/strong&gt; It maximizes utilization via advanced features: -&lt;br&gt;&lt;br&gt;
&lt;strong&gt;• Time-Slicing:&lt;/strong&gt; Allows multiple containers to share a single GPU’s compute power.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;• Multi-Instance GPU (MIG):&lt;/strong&gt; Partitions high-end GPUs (like the A100) into multiple, fully isolated hardware instances.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;• Virtual GPU(vGPU )&lt;/strong&gt;: Enables the sharing of a single GPU among multiple virtual machines.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why Scaling GPU Workloads in Kubernetes Is Hard and How Operators Help?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanmgwkke9r78tllaqlxm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanmgwkke9r78tllaqlxm.png" alt="The Challenge of Scale: Moving from One Machine to a Fleet." width="720" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The three-layer setup we discussed works well on a single machine. But things get complicated when you scale to a production-grade Kubernetes cluster with hundreds or thousands of nodes. That’s when the manual approach starts to fall apart and the real operational pain begins.&lt;/p&gt;

&lt;p&gt;Manually managing an entire fleet introduces a massive operational challenge that can bring projects to a grinding halt. You’re navigating a minefield of issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Driver Compatibility:&lt;/strong&gt; Different GPU models require different, specific driver versions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configuration Drift:&lt;/strong&gt; Nodes inevitably fall out of sync over time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Risky Upgrades:&lt;/strong&gt; The upgrade process becomes a high-risk nightmare.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Doubled Workload:&lt;/strong&gt; You often end up managing two completely separate software stacks one for CPU nodes and another for GPU nodes effectively doubling your workload.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve these scaling challenges, the Kubernetes community embraced a powerful cloud-native pattern: ‘The &lt;strong&gt;Operator’&lt;/strong&gt;. Think of it as an automated expert a robotic administrator that continuously monitors your cluster and handles all the tedious, error-prone tasks for you. It brings consistency, reliability, and automation to GPU management at scale.&lt;/p&gt;

&lt;p&gt;The GPU Operator works in a &lt;strong&gt;control loop&lt;/strong&gt;, constantly observing the state of your nodes and ensuring they match the &lt;strong&gt;desired configuration&lt;/strong&gt; you’ve defined. This means no more manual setup, no more configuration drift, and no more juggling separate software stacks for CPU and GPU nodes. Instead, you get consistency, reliability, and automation at scale.&lt;/p&gt;

&lt;p&gt;This shift from manual management to automated orchestration is what makes the Operator pattern so transformative. It turns GPU infrastructure from a fragile, high-maintenance setup into a resilient, self-healing system.&lt;/p&gt;
&lt;h2&gt;
  
  
  How NVIDIA GPU Operator works?
&lt;/h2&gt;

&lt;p&gt;The Operator establishes a consistent, automated workflow for every node in your cluster. It eliminates manual intervention through a streamlined process. It begins by: -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Discovery:&lt;/strong&gt; It first identifies which nodes physically possess GPUs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Installation and Configuration:&lt;/strong&gt; In the required order, it automatically installs the necessary containerised drivers, configures the Container Toolkit, and deploys the device plugin along with monitoring tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Validation&lt;/strong&gt;: This final step is critical: the Operator validates that every component is working perfectly before allowing Kubernetes to schedule any AI workloads on that node.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process guarantees reliability and prevents misconfigured nodes from disrupting GPU-intensive applications.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation the NVIDIA GPU Operator.
&lt;/h2&gt;

&lt;p&gt;Installing the &lt;strong&gt;NVIDIA GPU Operator&lt;/strong&gt; in Kubernetes is straightforward with Helm. The Operator automates the deployment and configuration of all essential GPU components including drivers, the container toolkit, and device plugins across your cluster. To ensure a smooth setup, follow a step-by-step approach.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites:
&lt;/h2&gt;

&lt;p&gt;Before proceeding please make sure that you have met the following prerequisites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Operating System Requirements for the GPU Operator:&lt;br&gt;&lt;br&gt;
• To use the NVIDIA GPU Driver container for your workloads, all GPU-enabled worker nodes must share the &lt;strong&gt;same operating system version&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
• If you need to mix different operating systems across GPU nodes, you must &lt;strong&gt;pre-install the NVIDIA GPU Driver manually&lt;/strong&gt; on each respective node instead of using the containerized driver.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;• CPU-only nodes&lt;/strong&gt; have no OS restrictions, as the GPU Operator does not manage or configure them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Helm is installed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have permission to execute &lt;code&gt;kubectl&lt;/code&gt; commands against the target cluster.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Installation steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Add NVIDIA Helm Repository
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \&lt;/span&gt;
 &lt;span class="s"&gt;&amp;amp;&amp;amp; helm repo update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;2. Install GPU Operator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;helm install --wait --generate-name \&lt;/span&gt;
 &lt;span class="s"&gt;-n gpu-operator --create-namespace \&lt;/span&gt;
 &lt;span class="s"&gt;nvidia/gpu-operator \&lt;/span&gt;
 &lt;span class="s"&gt;--version=v25.10.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the NVIDIA driver or toolkit is already installed on your nodes, you can disable either or both during GPU Operator deployment by using the following flags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;--set driver.enabled=false&lt;/span&gt;
&lt;span class="s"&gt;--set toolkit.enabled=false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3. Verify the installation, by checking the status of the deployed resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubectl get pods -n gpu-operator&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the GPU operator components running in the namespace.&lt;/p&gt;

&lt;p&gt;4. We can also check the configuration of the node to check if the nodes with the GPU are configured correctly&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubectl describe nodes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;               &lt;span class="s"&gt;sagar.rajput27@live.com&lt;/span&gt;
&lt;span class="na"&gt;Roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;              &lt;span class="s"&gt;worker&lt;/span&gt;
&lt;span class="na"&gt;Labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;             &lt;span class="s"&gt;node-role.kubernetes.io/worker=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.count=1&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.container-toolkit=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.dcgm=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.dcgm-exporter=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.device-plugin=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.driver=pre-installed&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.gpu-feature-discovery=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.mig-manager=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.node-status-exporter=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.nvsm=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.deploy.operator-validator=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.mode=compute&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.present=true&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.product=NVIDIA-H100-PCIe&lt;/span&gt;
                    &lt;span class="s"&gt;nvidia.com/gpu.replicas=1&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;Annotations:        nvidia.com/gpu-driver-upgrade-enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                    &lt;span class="s"&gt;projectcalico.org/IPv4Address&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.*.*.*/*&lt;/span&gt;
                    &lt;span class="s"&gt;projectcalico.org/IPv4VXLANTunnelAddr&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10.*.*.*&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;Capacity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                &lt;span class="m"&gt;64&lt;/span&gt;
  &lt;span class="na"&gt;ephemeral-storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;32758Mi&lt;/span&gt;
  &lt;span class="na"&gt;hugepages-1Gi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;hugepages-2Mi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;             &lt;span class="s"&gt;527533864Ki&lt;/span&gt;
  &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;               &lt;span class="m"&gt;110&lt;/span&gt;
&lt;span class="na"&gt;Allocatable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                &lt;span class="m"&gt;64&lt;/span&gt;
  &lt;span class="na"&gt;ephemeral-storage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;32631789953&lt;/span&gt;
  &lt;span class="na"&gt;hugepages-1Gi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;hugepages-2Mi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;      &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;             &lt;span class="s"&gt;527533864Ki&lt;/span&gt;
  &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;     &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;pods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;               &lt;span class="m"&gt;110&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the node with a GPU hardware attached has GPU-related labels and annotations added to it. Additionally, the GPU resources are visible under the &lt;strong&gt;Capacity&lt;/strong&gt; and &lt;strong&gt;Allocatable&lt;/strong&gt; sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verification by running sample GPU application
&lt;/h3&gt;

&lt;p&gt;We can test the setup by deploying the CUDA &lt;strong&gt;vectoradd&lt;/strong&gt; application provided by NVIDIA on our cluster. This image is an NVIDIA CUDA sample that demonstrates vector addition a basic GPU computation.&lt;/p&gt;

&lt;p&gt;Under the &lt;strong&gt;resources → limits&lt;/strong&gt; section of this manifest, you’ll notice &lt;code&gt;nvidia.com/gpu: 1&lt;/code&gt;. This instructs Kubernetes to schedule the Pod on a node equipped with an NVIDIA GPU.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;cat &amp;lt;&amp;lt; EOF | kubectl create -f -&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cuda-vectoradd&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cuda-vectoradd&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubuntu20.04"&lt;/span&gt;
    &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;nvidia.com/gpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;pod/cuda-vectoradd created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can check the logs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;kubectl logs pod/cuda-vectoradd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logs Output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Vector addition of 50000 elements&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="s"&gt;Copy input data from the host memory to the CUDA device&lt;/span&gt;
&lt;span class="s"&gt;CUDA kernel launch with 196 blocks of 256 threads&lt;/span&gt;
&lt;span class="s"&gt;Copy output data from the CUDA device to the host memory&lt;/span&gt;
&lt;span class="s"&gt;Test PASSED&lt;/span&gt;
&lt;span class="s"&gt;Done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our cluster is ready to deploy the GPU workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  GPU Sharing to Maximize GPU Utilization
&lt;/h2&gt;

&lt;p&gt;GPUs are expensive, high-performance hardware and leaving them idle is a waste of valuable resources. Once your GPUs are up and running in Kubernetes, the real challenge becomes &lt;strong&gt;efficient sharing&lt;/strong&gt;. The goal is to extract maximum value from every single card.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;GPU Operator&lt;/strong&gt; makes this easy by allowing you to configure advanced sharing strategies declaratively. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MIG (Multi-Instance GPU)&lt;/strong&gt;: Physically partitions a single GPU into multiple, fully isolated instances each with dedicated memory and compute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MPS (Multi-Process Service)&lt;/strong&gt;: Enables concurrent execution of multiple GPU processes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Time-Slicing&lt;/strong&gt;: Ideal for development workloads that only need occasional GPU access.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahs61ib9twwur520bjfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fahs61ib9twwur520bjfw.png" alt="GPU Sharing Strategy" width="693" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The optimal GPU sharing strategy depends entirely on your specific workload requirements and operational goals. The choice involves balancing factors like performance isolation, dynamic flexibility, and raw utilization. A workload that demands predictable performance in a multi-tenant cluster has very different needs than an interactive development workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional GPU Operator Components: Streamlining Data Movement
&lt;/h2&gt;

&lt;p&gt;The GPU Operator includes additional components that are not enabled by default, such as GPUDirect RDMA and GPUDirect Storage. These tools are designed to streamline data movement between GPUs and other system components, effectively bypassing traditional bottlenecks like the CPU and system memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  GPUDirect RDMA (Remote Direct Memory Access)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GPUDirect RDMA&lt;/strong&gt; enables direct memory access between GPUs and PCIe devices (such as NICs or storage adapters), without involving the CPU or system RAM. This is ideal for High-Performance Computing (HPC) and AI training, where latency is critical.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fses9wfgi32gbk1mtybx5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fses9wfgi32gbk1mtybx5.png" alt="Direct Communication between NVIDIA GPUs&amp;lt;br&amp;gt;
" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lower latency&lt;/strong&gt;: Data moves directly between the GPU and the device.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced CPU load&lt;/strong&gt;: Frees up CPU cycles for compute tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Higher bandwidth&lt;/strong&gt;: Enables faster data transfer for distributed workloads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GPU-to-GPU communication across nodes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Real-time inference at the edge&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High-speed networking in HPC clusters&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GPUDirect Storage
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GPUDirect Storage&lt;/strong&gt; allows GPUs to read data directly from NVMe or other storage devices again bypassing the CPU and system memory. This is essential for AI/ML workloads that need access and process large datasets quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmct56gbc6tpbjlhbgaeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmct56gbc6tpbjlhbgaeo.png" alt="GPUDirect Storage A Direct Path Between Storage and GPU Memory&amp;lt;br&amp;gt;
" width="720" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Faster data ingestion&lt;/strong&gt;: Minimizes I/O bottlenecks during training or inference.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Efficient data pipeline&lt;/strong&gt;: Direct flow from storage to GPU memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified architecture&lt;/strong&gt;: Eliminates unnecessary memory copies and CPU involvement.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use Cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Large-scale deep learning training&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data analytics pipelines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scientific simulations with massive datasets&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both technologies are part of NVIDIA’s strategy to optimize data movement for GPU workloads. By enabling direct communication paths between GPUs and external devices, they unlock higher performance and lower latency, better resource utilization in Kubernetes environments where scalability and efficiency are critical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Integrating NVIDIA GPUs into Kubernetes typically involves a complex, three-layer manual setup: host drivers, the container toolkit, and the Kubernetes device plugin. This approach works for single machines but creates massive operational challenges like configuration drift and incompatible drivers at scale.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;NVIDIA GPU Operator&lt;/strong&gt; is the solution. It uses the Operator pattern to automate the entire lifecycle, acting as a “robotic administrator” that discovers GPUs, installs the necessary software stack in the correct order, validates the setup, and streamlines maintenance.&lt;/p&gt;

&lt;p&gt;The core benefit? Simplifying your infrastructure so you can focus on AI workloads, not operational headaches.&lt;/p&gt;

&lt;p&gt;I hope you found this post informative and engaging. I would love to hear your thoughts on this post, so do start a conversation on &lt;a href="https://twitter.com/sagarrajput27" rel="noopener noreferrer"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/sagar-parmar-834403a6/" rel="noopener noreferrer"&gt;&lt;strong&gt;LinkedIn&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4clkle3rl9y1iyeqw8pw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4clkle3rl9y1iyeqw8pw.png" alt="Bye-Bye" width="574" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/overview.html" rel="noopener noreferrer"&gt;&lt;strong&gt;About the NVIDIA GPU Operator — NVIDIA GPU Operator&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
*Kubernetes provides access to special hardware resources such as NVIDIA GPUs, NICs, Infiniband adapters and other…*docs.nvidia.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.nvidia.com/gpudirect" rel="noopener noreferrer"&gt;&lt;strong&gt;GPUDirect&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
*Enhancing Data Movement and Access for GPUs Whether you are exploring mountains of data, researching scientific…*developer.nvidia.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gpu</category>
      <category>nvidia</category>
      <category>kubernetes</category>
      <category>ai</category>
    </item>
    <item>
      <title>Creating Infra Using Backstage Templates, Terraform and GitHub actions.</title>
      <dc:creator>Sagar Parmar</dc:creator>
      <pubDate>Sun, 14 Jan 2024 09:58:05 +0000</pubDate>
      <link>https://forem.com/aws-builders/creating-infra-using-backstage-templates-terraform-and-github-actions-27gg</link>
      <guid>https://forem.com/aws-builders/creating-infra-using-backstage-templates-terraform-and-github-actions-27gg</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepsrwfmlner8bjvfq1mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepsrwfmlner8bjvfq1mn.png" alt="Platform Engineering Using Backstage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Backstage is an open-source platform for constructing Internal Developer Portals (IDPs). Internal Developer Portals serve as a one-stop shop, that provides a unified view of all our resources. IDPs enable us to seamlessly create, manage, monitor, and document our software resources from a single location. The primary goal of the IDP is to eliminate the reliance on the connection between DevOps and developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Backstage is up and running. If you need assistance with deploying Backstage, please follow this &lt;a href="https://backstage.io/docs/features/software-templates/" rel="noopener noreferrer"&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Backstage integration with Github.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A working Terraform code is uploaded on the GitHub repo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitHub action file is created to execute the terraform code.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the sake of this blog, we are using GitHub and AWS, but you can use any CI/CD tool and cloud provider.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Templates&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Backstage provides a software catalog which is used to manage all of our software resources, which include CI-CD, Docs, API, K8s, Websites, microservices etc. To create a new component(entity) in the software catalog we need Templates.&lt;/p&gt;

&lt;p&gt;The structure of the template file is almost similar to the kubernetes manifests. This similarity in structure makes it easier for users familiar with Kubernetes to work with Backstage templates.&lt;/p&gt;

&lt;p&gt;Below is a backstage template that you can use to create an EC2 instance on AWS.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

apiVersion: scaffolder.backstage.io/v1beta3
    kind: Template
    metadata:
      name: sagar
      title: Backstage automation
      description: creating ec2 using backstage and terraform.
    spec:
      owner: guest
      type: service

      parameters:
        - title: backstage demo template
          required:
            - name
          properties:
            name:
              type: string

      steps:
        - id: test
          name: backstage-blog
          action: debug:log
          input:
            message: 'Hello, ${{ parameters.name }}!'

      output:
        links:
          - title: Open in catalog
            icon: catalog
            entityRef: ${{ steps['register'].output.entityRef


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;apiVersion: -&lt;/em&gt;&lt;/strong&gt; is the required field and the latest value of the API version is &lt;code&gt;scaffolder.backstage.io/v1beta3&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;**Kind: - *&lt;/em&gt;*template is the entity in the backstage and to configure it, set the value of kind to Template.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;**metadata: - *&lt;/em&gt;*Information you will add in metadata will appear on the template card.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;spec: -&lt;/em&gt;&lt;/strong&gt; It contains the name of the owner/group of the template and the type of template it could be anything for example:- service/ website/app etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;parameters: -&lt;/em&gt;&lt;/strong&gt; These are the list of options you can add to the template to get the information from the user. Parameters must contain these components: -&lt;br&gt;
&lt;strong&gt;5.1.&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;title&lt;/em&gt;&lt;/strong&gt;: - contains the title of the template&lt;br&gt;
&lt;strong&gt;5.2.&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;required&lt;/em&gt;&lt;/strong&gt;: - You can add the parameters which are mandatory for the template so that a user cannot skip it.&lt;br&gt;
&lt;strong&gt;5.3.&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;properties&lt;/em&gt;&lt;/strong&gt;: - It is used to take input from the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;steps&lt;/em&gt;&lt;/strong&gt;: - Here we define actions taken by the template while executing the template.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;*** Output ***: - This is the final section in the template file. After completing all the actions specified in the ‘steps,’ this part is executed. It is used to display the result of the template execution, although it is not mandatory.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find out more about the template format &lt;a href="https://backstage.io/docs/features/software-catalog/descriptor-format" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Deploying Custom Template
&lt;/h2&gt;

&lt;p&gt;Now let's see the files which we have created for the demo. In my backstage code, I have created a directory ec2-demo/template inside the template directory I have created a template.yaml file. Also, I have created a content directory where I have created 2 files component-info.yaml, index.json and package.json.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvlPtr8j957Noy02ZXp0vsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AvlPtr8j957Noy02ZXp0vsw.png" alt="Screenshot of the template directory."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have added component-info.yaml, index.json and package.json files below. In the component-info.yaml file I have given the reference of the GitHub repo where my Terraform workflow is present.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
After adding all these files, navigate to your app-config.yaml file and insert the template path under the catalogue section, as illustrated in the screenshot below. Adjust the target path according to your requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ARLf5TAFIqxkhgU99pJth9Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ARLf5TAFIqxkhgU99pJth9Q.png" alt="screenshot of app-config.yaml"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding the path, execute the yarn dev command. Now, on the Backstage portal, under the Create option, you will notice the newly created template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKh1qBiYM9oAGXXYI81jKGg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AKh1qBiYM9oAGXXYI81jKGg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the template.yaml file, Under the parameter I have added instanceName, region and instanceType. Once you open the ec2-template it will ask you to add these values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AB8GNte78-LZaLBSi0jDfcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AB8GNte78-LZaLBSi0jDfcw.png" alt="screenshot of the template (Parameter Part)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding the values on the next page it will ask you to add a repository name and owner. You can give any name to the repo, whatever name you add here the template will create a repo on GitHub with that name. The owner can be a backstage group or users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkPaKM_MS-_B5ibJCXZ2qIg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkPaKM_MS-_B5ibJCXZ2qIg.png" alt="Screenshot of the repository location"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once all the details are filled, the template will ask you to verify the details which you have added.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3258%2F1%2AGvK4jnEinN3YNsweIRx2tQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3258%2F1%2AGvK4jnEinN3YNsweIRx2tQ.png" alt="Screenshot of review page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After reviewing, click on ‘Create.’ It will take a couple of seconds to generate your catalog. In the background, Backstage will trigger the GitHub workflow. This workflow will execute the ‘terraform apply’ command, which will then create an EC2 instance. Below is the screenshot of the GitHub action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3680%2F1%2Au58Ni9eiFFDSBeWNLir1Yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3680%2F1%2Au58Ni9eiFFDSBeWNLir1Yw.png" alt="Screenshot of GitHub workflow file."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you check the status of the GitHub action Job you will see the status of the current job and its progress.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AIe5DB6yZmIhKIxilyirSBQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AIe5DB6yZmIhKIxilyirSBQ.png" alt="Screenshot of the GitHub Action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Coming back to backstage UI, here you will see that your catalog has been created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3074%2F1%2Agf1j1bkEPGeJsSeNCSETgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3074%2F1%2Agf1j1bkEPGeJsSeNCSETgA.png" alt="Screenshot of the output window."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once done you can click on the catalog link. It will take you to the newly created catalog window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aa88LF58Tue6SrUj0ZYWj8w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2Aa88LF58Tue6SrUj0ZYWj8w.png" alt="Screenshot of the Catalog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here you will see a CI-CD option under that option you can check the status/progress of the GitHub workflow job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2270%2F1%2Aa1MssDTrU66f18AS2DpddQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2270%2F1%2Aa1MssDTrU66f18AS2DpddQ.png" alt="Screenshot of the CI-CD option."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the pipeline is completed your ec2 instance will be up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Summary&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In this blog post, we have seen how we can use the backstage template to create an AWS EC2 instance. You can also use the template to spin Infra anywhere, to create a CI-CD Pipeline to deploy your application etc.&lt;/p&gt;

&lt;p&gt;I hope you found this post informative and engaging. I would love to hear your thoughts on this post, so do start a conversation on &lt;a href="https://twitter.com/sagarrajput27" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;** or &lt;a href="https://www.linkedin.com/in/sagar-parmar-834403a6/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/integration-of-opentelemetry-auto-instrumentation-with-jaeger-4de147a64f38" rel="noopener noreferrer"&gt;&lt;strong&gt;Integration of Opentelemetry (Auto Instrumentation) with Jaeger&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/vcluster-architecture-overview-and-installation-d41b6262b2f8" rel="noopener noreferrer"&gt;&lt;strong&gt;Vcluster — Architecture Overview and Installation&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/backup-restore-and-migrate-kubernetes-cluster-resources-using-velero-a9b6997e4b54" rel="noopener noreferrer"&gt;&lt;strong&gt;Backup, Restore and Migrate Kubernetes Cluster resources using Velero.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/sealed-secret-in-kubernetes-d10fed2da964" rel="noopener noreferrer"&gt;&lt;strong&gt;Sealed Secret in Kubernetes&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>platformenginnering</category>
      <category>backstage</category>
      <category>aws</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Monitoring of AWS EKS using AWS Distro for OpenTelemetry (ADOT) and Amazon Managed Service for Prometheus (AMP)</title>
      <dc:creator>Sagar Parmar</dc:creator>
      <pubDate>Sat, 08 Jul 2023 08:41:54 +0000</pubDate>
      <link>https://forem.com/sagar0419/monitoring-of-aws-eks-using-aws-distro-for-opentelemetry-adot-and-amazon-managed-service-for-prometheus-amp-41d</link>
      <guid>https://forem.com/sagar0419/monitoring-of-aws-eks-using-aws-distro-for-opentelemetry-adot-and-amazon-managed-service-for-prometheus-amp-41d</guid>
      <description>&lt;p&gt;In this tutorial, we will be using &lt;strong&gt;AWS Distro for OpenTelemetry&lt;/strong&gt; to capture the metrics from AWS EKS and send them to &lt;strong&gt;Amazon managed service for Prometheus&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Distro for OpenTelemetry(ADOT): -&lt;/strong&gt; It is an AWS-supported version of the upstream OpenTelemetry Collector and is distributed by Amazon. It supports the selected components from the OpenTelemetry community. It is fully compatible with AWS computing platforms including EC2, ECS, and EKS. It enables users to send telemetry data to AWS CloudWatch Metrics, Traces, and Logs backends as well as the other supported backends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon Managed Service for Prometheus(AMP): -&lt;/strong&gt; It is Prometheus-compatible monitoring and alerting service offered by AWS that makes it easy to monitor containerized applications and infrastructure at scale. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisite: -&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cert manager is installed and running. If it is not installed follow this &lt;strong&gt;&lt;a href="https://cert-manager.io/docs/installation/#default-static-install" rel="noopener noreferrer"&gt;URL&lt;/a&gt;&lt;/strong&gt; to install it.&lt;/li&gt;
&lt;li&gt;An AMP workspace is created. Guides for this can be found &lt;a href="https://docs.aws.amazon.com/prometheus/latest/userguide/what-is-Amazon-Managed-Service-Prometheus.html" rel="noopener noreferrer"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you are setting up the ADOT Collector of AWS EKS, you will need to set up &lt;a href="https://docs.aws.amazon.com/prometheus/latest/userguide/set-up-irsa.html#set-up-irsa-ingest" rel="noopener noreferrer"&gt;&lt;strong&gt;IAM roles for service accounts for the ingestion&lt;/strong&gt;&lt;/a&gt; of metrics from Amazon EKS clusters. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;3.1. Open the IAM &lt;a href="https://console.aws.amazon.com/iam/" rel="noopener noreferrer"&gt;&lt;strong&gt;Console&lt;/strong&gt;&lt;/a&gt; and edit the trust policy.&lt;br&gt;
3.2. In the left navigation pane, choose Roles and find the amp-iamproxy-ingest-role that you created in Step 3.&lt;br&gt;
3.3. Choose the Trust Relationships tab and choose Edit trust relationship.&lt;br&gt;
3.4. In the trust relationship policy JSON, replace aws-amp with adot-col and choose Update Trust Policy. Your resulting trust policy should look like the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::account-id:oidc-provider/oidc.eks.aws_region.amazonaws.com/id/openid"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.aws_region.amazonaws.com/id/openid:sub": "system:serviceaccount:adot-col:amp-iamproxy-ingest-service-account"
        }
      }
    }
  ]
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;3.5. Choose the Permissions tab and make sure that the following permissions policy is attached to the role.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "aps:RemoteWrite",
                "aps:GetSeries",
                "aps:GetLabels",
                "aps:GetMetricMetadata"
            ],
            "Resource": "*"
        }
    ]
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h3&gt;
  
  
  ADOT Installation
&lt;/h3&gt;

&lt;p&gt;Assuming that you have all the prerequisites installed or created and you are ready to deploy the ADOT on your cluster.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before installing ADOT, we need to make sure that ADOT is configured in a way that it can send its metrics data to Amazon Managed Prometheus(AMP) and for this purpose, you have to first download the Prometheus file by running the following command. &lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

wget https://raw.githubusercontent.com/aws-observability/aws-otel-collector/main/examples/eks/aws-prometheus/prometheus-sample-app.yaml


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once you downloaded this file. Now you need to change a few parameters in the file. These are mentioned below: -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;remote_write&lt;/strong&gt; endpoint for your Amazon Managed Service for Prometheus workspace for &lt;strong&gt;YOUR_ENDPOINT&lt;/strong&gt; and your Region for &lt;strong&gt;YOUR_REGION&lt;/strong&gt;. You can get the remote_write URL from the AMP workspace which you have just created. Below is the screenshot of configmap, where you need to add your details.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrnxlsrj3q05b202yx11.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcrnxlsrj3q05b202yx11.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above screenshot, we are using adot as the namespace. So when you check the metrics exported by your ADOT it will show your metrics name starting with “adot” Below is the screenshot which shows how your metrics will look.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3v16xjy6x36bjzf52tb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3v16xjy6x36bjzf52tb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, for the metrics like this, you have to create your own custom dashboard on grafana. And if you want to use the already available dashboard then keep the namespace name empty like this “namespace: "”. Now it will not add any name in front of your metrics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You'll also need to change YOUR_ACCOUNT_ID in the service account section of the Kubernetes configuration to your AWS account ID.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztn88foigc8l7cxngfwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fztn88foigc8l7cxngfwr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As the ADOT Prometheus Receiver supports the full set of Prometheus scraping and re-labelling configurations described in the &lt;a href="https://prometheus.io/docs/prometheus/latest/configuration/configuration/" rel="noopener noreferrer"&gt;&lt;strong&gt;Configuration&lt;/strong&gt;&lt;/a&gt; section in the Prometheus documentation. You can paste these configurations directly into your ADOT Collector configurations. The configuration for the Prometheus Receiver includes your service discovery, scraping configurations, and re-labelling configurations. The receiver configurations look like the following.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

receivers:
  prometheus:
    config:
      [Your Prometheus configuration]


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can download the file which we have used for this demo by using below mentioned command. &lt;br&gt;
&lt;code&gt;You can customise this file or you can use your own file.&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

wget https://raw.githubusercontent.com/sagar0419/Adot-Configuration/master/adot.yaml


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create a namespace in the kubernetes where you are goin to deploy the downloaded file.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 create ns adot-col

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the namespace is created you can deploy your prometheus configuration.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 apply -f adot.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can verify the configuration once it is deployed on the cluster with the following command: -&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  get all -n adot-col

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If the configuration is deployed successfully, then you will get an output like this: -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnsnwhviugyvs0sybzj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnsnwhviugyvs0sybzj8.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Now your ADOT is deployed on the cluster. To check if it sending telemetric data to AMP or not, run the below command. But before running this command change the required parameters first. &lt;strong&gt;AMP_ENDPOINT&lt;/strong&gt;, &lt;strong&gt;AMP_REGION&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(Note AWS AMP is a different AWS service which is not running on EKS so we cannot check it by running the kubectl commands)&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

awscurl --service="aps" --region="AMP_REGION" "https://AMP_ENDPOINT/api/v1/query?query=adot_test_gauge0"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You will get output similar to this.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;{"status":"success","data":{"resultType":"vector","result":[{"metric":{"&lt;strong&gt;name&lt;/strong&gt;":"adot_test_gauge0"},"value":[1606512592.493,"16.87214000011479"]}]}}&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Grafana for ADOT visualisation&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Now we need to install Grafana on our Kubernetes cluster. You can deploy it anywhere or you can choose Grafana cloud also. For this tutorial we are going to deploy it on kubernetes.&lt;/p&gt;

&lt;p&gt;To deploy grafana on your cluster you can use this &lt;strong&gt;&lt;a href="https://github.com/grafana/helm-charts/tree/main/charts/grafana" rel="noopener noreferrer"&gt;helm chart&lt;/a&gt;&lt;/strong&gt;. Please follow this &lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/prometheus/latest/userguide/AMP-onboard-query-grafana-7.3.html" rel="noopener noreferrer"&gt;document&lt;/a&gt;&lt;/strong&gt; to enable sigv4 and IRSA in your grafana helm chart.&lt;/p&gt;

&lt;p&gt;Once grafana is deployed login to the grafana console. Navigate to setting and select data source to add AWS Managed Prometheus as datasource.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkt9pnp4fgmwvm2eaecs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkt9pnp4fgmwvm2eaecs.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select Add data source, then Prometheus from the list as shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6t37iqe7v2uj71xzyezf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6t37iqe7v2uj71xzyezf.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we paste the AMP Endpoint query URL (find this under the Summary tab on the AMP workspace) leaving out the api/v1/query portion (for example, &lt;a href="https://aps-workspaces.us-west-2.amazonaws.com/workspaces/ws-3aa5f57b-yy11-xx00-12ab-ea86005d6dd7/" rel="noopener noreferrer"&gt;https://aps-workspaces.us-west-2.amazonaws.com/workspaces/ws-3aa5f57b-yy11-xx00-12ab-ea86005d6dd7/&lt;/a&gt;) in the URL field under HTTP. We need to enable SigV4 auth in the Auth section.&lt;/p&gt;

&lt;p&gt;We also need to ensure that AWS SDK Default is selected in Authentication Provider under the Sigv4 Auth Details section, then select the AWS Region in which the AMP workspace was created earlier in the Default Region drop-down. See the following screenshot for details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjhdeo54ds0gvzfhnjhd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmjhdeo54ds0gvzfhnjhd.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we can choose Save &amp;amp; Test. We should see a green banner that says “Data source is working” as shown in the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs4hdecklvjjt1ltfn0h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgs4hdecklvjjt1ltfn0h.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Query the metrics from AMP to verify the setup
&lt;/h3&gt;

&lt;p&gt;Next, we’ll create a new Dashboard from the left navigation bar by choosing the + sign.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dea3xew1fzkwu2vyfe8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dea3xew1fzkwu2vyfe8.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We then add a new panel and select the new AMP data source configured previously.&lt;/p&gt;

&lt;p&gt;We can write a simple PromQL query in the Metrics textbox, and we should see the metrics in the panel as shown in the screenshot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt64q2wdv1dlsz4pc0bd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flt64q2wdv1dlsz4pc0bd.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also create or upload a custom dashboard. In this demo we are using &lt;strong&gt;Node Exporter for Prometheus&lt;/strong&gt; Dashboard. Below is the screenshot of the dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F354swiyztvydme5pvnyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F354swiyztvydme5pvnyy.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
Now your cluster metrics are available on the grafana dashboard collected using ADOT and AMP.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this blog post, we saw that how we can monitor our EKS cluster using AWS ADOT and AMP. We also saw that how we can export the metrics generated by EKS in Grafana.&lt;/p&gt;

&lt;p&gt;I hope you found this post informative and engaging. I would love to hear your thoughts on this post, so do start a conversation on &lt;strong&gt;&lt;a href="https://twitter.com/sagarrajput27" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/sagar-parmar-834403a6/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; .&lt;/p&gt;

&lt;p&gt;Here are some of my other articles that you may find interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.devgenius.io/integration-of-opentelemetry-auto-instrumentation-with-jaeger-4de147a64f38" rel="noopener noreferrer"&gt;Monitoring your application using OpenTelemetry and Jaeger.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.devgenius.io/vcluster-architecture-overview-and-installation-d41b6262b2f8" rel="noopener noreferrer"&gt;Multitenancy in Kubernetes cluster using vCluster.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://medium.com/dev-genius/backup-restore-and-migrate-kubernetes-cluster-resources-using-velero-a9b6997e4b54" rel="noopener noreferrer"&gt;Backup and Restore Kubernetes Cluster.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until Next time....&lt;/p&gt;

</description>
      <category>aws</category>
      <category>opentelemetry</category>
      <category>kubernetes</category>
      <category>prometheus</category>
    </item>
    <item>
      <title>AWS Patch Management</title>
      <dc:creator>Sagar Parmar</dc:creator>
      <pubDate>Thu, 02 Mar 2023 08:44:12 +0000</pubDate>
      <link>https://forem.com/sagar0419/aws-patch-management-28g</link>
      <guid>https://forem.com/sagar0419/aws-patch-management-28g</guid>
      <description>&lt;p&gt;&lt;strong&gt;Introduction: -&lt;/strong&gt;&lt;br&gt;
AWS Patch Manager automates the patching process for AWS-managed Linux and Windows instances. It patches the instances with security and non-security updates. By using patch manager, we can scan instances for missing patches, or we can use patch manager to scan and install all missing patches on our AWS-managed VMs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites:-&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS VM is up and running (In our scenario, we are using CentOs). All the OS which are supported for installation of the patch manager can be checked on this link.&lt;/li&gt;
&lt;li&gt;You have SSH access to VM.&lt;/li&gt;
&lt;li&gt;You have AWS access to create S3 Bucket, IAM role and Policies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Assuming that you have all the prerequisites, we can now move forward with installing Patch Manager on our machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation: -&lt;/strong&gt;&lt;br&gt;
To install the AWS System Manager Agent on our machine, we need to run the SSM agent install command on our machine. If you are using CentOS 7, then you can download the below-mentioned command and run it on your machine. Otherwise, you can get your command from this link.&lt;br&gt;
You can use the below-mentioned command if you are using a CentOS 7 VM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo yum install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the command is installed run the following commands: -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl daemon-reload &amp;amp;&amp;amp; sudo systemctl restart amazon-ssm-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you will get an output like this: -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ny3LetVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd8tjuskbae5uydval8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ny3LetVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wd8tjuskbae5uydval8x.png" alt="SSM-Agent-Service" width="669" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you get an output like the service is inactive: -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;● amazon-ssm-agent.service - amazon-ssm-agent
 Loaded: loaded (/etc/systemd/system/amazon-ssm-agent.service; enabled; vendor preset: disabled)
 Active: inactive (dead) since Tue 2022–04–19 15:58:44 UTC; 2s ago
 - truncated -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To activate the agent run the below-mentioned command: -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable amazon-ssm-agent
sudo systemctl daemon-reload &amp;amp;&amp;amp; sudo systemctl restart amazon-ssm-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IAM Instance Role:-&lt;/strong&gt;&lt;br&gt;
Assuming that your SSM agent is up and running. Now we need to create an IAM Instance Profile so that our machine can communicate with the patch manager.&lt;/p&gt;

&lt;p&gt;To communicate the IAM role, log in to your AWS console and navigate to the IAM section. Once you reach there, click on "Roles" under "Access Management".&lt;/p&gt;

&lt;p&gt;Click on "Create role", A window will appear to select "Select the trusted entity". Select the trusted entity type &lt;strong&gt;"AWS Service"&lt;/strong&gt; and under the use case, select &lt;strong&gt;"EC2."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you are done with the selection, click on "Next."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YCTF7Z9V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2erbwzuvpw4f5fpj1vi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YCTF7Z9V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2erbwzuvpw4f5fpj1vi.png" alt="Adding trust entity" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now a new window will appear; from this window, you can add permission to your role. Here, search for &lt;strong&gt;"AmazonEC2RoleforSSM".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--33iarzh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqp9t775jjn1b4weha29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--33iarzh3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqp9t775jjn1b4weha29.png" alt="Adding Permission" width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the policy and click &lt;strong&gt;"Next"&lt;/strong&gt; then give your role a name. In our scenario, we are using the "demo-Patch-manager" name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XSFHUzOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t91i40zurf70t4ye2ck6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XSFHUzOb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t91i40zurf70t4ye2ck6.png" alt="Role Name" width="776" height="748"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down and click on &lt;strong&gt;"Create Role"&lt;/strong&gt; and your role will be created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_G8J01Ch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtsbmvexafv5er1tv7w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_G8J01Ch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jtsbmvexafv5er1tv7w6.png" alt="Create Role" width="800" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to attach the newly created role to the instance. For this, navigate to the EC2 Console and select the instance that you want to add to your patch manager.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uq5OdK6M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cleut9g6b8htwzdgtd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uq5OdK6M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cleut9g6b8htwzdgtd5.png" alt="Instance which needs to be patched" width="800" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the instance, click on "Action" and then navigate to "Security", Under the security option, select &lt;strong&gt;"Modify IAM role".&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the new window, select the IAM role that you have created in the previous step, and then click on "Update IAM Role" and your IAM role will get attached to the machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s8F9DQaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hl7vvcl924lxj0gdh6l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s8F9DQaU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1hl7vvcl924lxj0gdh6l.png" alt="Attaching IAM Role to the instance" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patching:-&lt;/strong&gt;&lt;br&gt;
To patch, your instance goes to the &lt;strong&gt;"AWS Systems Manager"&lt;/strong&gt; on the AWS console. Then click on &lt;strong&gt;"Patch Manager"&lt;/strong&gt; under &lt;strong&gt;"Node Management."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--raOQLgIJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypp8g7p7dbplj42ymrrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--raOQLgIJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypp8g7p7dbplj42ymrrr.png" alt="Patch Manager" width="766" height="901"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under Patch Manager, select &lt;strong&gt;"Configure patching"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bAyLXfQ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbcajgfxz2hgmmwuw4aj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bAyLXfQ9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbcajgfxz2hgmmwuw4aj.png" alt="Patch Management Window" width="800" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new window will open, Here you need to select the instance that you want to patch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_2X3yviI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vft4ilnd7ckhbnh0imjm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_2X3yviI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vft4ilnd7ckhbnh0imjm.png" alt="Configuring Patch" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our scenario, our instance is "demo-patch," so we have selected that instance.&lt;/p&gt;

&lt;p&gt;In the next option, we need to select the patching window and whether we want to install the patch or just scan the machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZuemfP-t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xm4kquncej5x0pbxkqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZuemfP-t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7xm4kquncej5x0pbxkqc.png" alt="Patching Schedule" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our scenario, we are using the option "&lt;strong&gt;Skip scheduling and patch instance now&lt;/strong&gt;". You can schedule the patch according to your requirements.&lt;/p&gt;

&lt;p&gt;Under "&lt;strong&gt;Patching Operation&lt;/strong&gt;," click on "Scan and Install" so that it can scan the machine and update the patches. If you only want to scan the machine and generate a list of patches that are available for installation, then select "Scan only."&lt;/p&gt;

&lt;p&gt;Once you have selected all the requirements, click on "&lt;strong&gt;Configure Patching&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verification: -&lt;/strong&gt;&lt;br&gt;
To verify the status of your patch command. Navigate to &lt;strong&gt;"Run Command"&lt;/strong&gt; under &lt;strong&gt;"Node Management"&lt;/strong&gt;, in the &lt;strong&gt;"AWS Systems Manager"&lt;/strong&gt; window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zITAGoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zc1whviddflk6v0ed39p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zITAGoR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zc1whviddflk6v0ed39p.png" alt="Node Management" width="270" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the command and click on "View details."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--euOQ4QMs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93j0wc8m50u91wfh744n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--euOQ4QMs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93j0wc8m50u91wfh744n.png" alt="Command Details" width="800" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this window, you can check the status of the patch command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--odo_yRly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n96ez300xfsjbcuegtgt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--odo_yRly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n96ez300xfsjbcuegtgt.png" alt="Patch Command status" width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, our command was successful, which means our instance was patched successfully.&lt;/p&gt;

&lt;p&gt;I hope you found this post informative and engaging. I would love to hear your thoughts on this post, so do start a conversation on &lt;strong&gt;&lt;a href="https://twitter.com/sagarrajput27"&gt;Twitter&lt;/a&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/sagar-parmar-834403a6/"&gt;LinkedIn&lt;/a&gt;&lt;/strong&gt; :)&lt;/p&gt;

&lt;p&gt;Here are some of my other articles that you may find interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.devgenius.io/integration-of-opentelemetry-auto-instrumentation-with-jaeger-4de147a64f38"&gt;OpenTelemetry Auto Instrumentation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.devgenius.io/vcluster-architecture-overview-and-installation-d41b6262b2f8"&gt;vCluster&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until Next time...&lt;/p&gt;

</description>
      <category>aws</category>
      <category>security</category>
      <category>patchmanagement</category>
    </item>
    <item>
      <title>OpenTelemetry auto-instrumentation with Jaeger</title>
      <dc:creator>Sagar Parmar</dc:creator>
      <pubDate>Tue, 14 Feb 2023 06:40:42 +0000</pubDate>
      <link>https://forem.com/infracloud/opentelemetry-auto-instrumentation-with-jaeger-27eb</link>
      <guid>https://forem.com/infracloud/opentelemetry-auto-instrumentation-with-jaeger-27eb</guid>
      <description>&lt;p&gt;In earlier days, it was easy to deduct and debug a problem in monolithic applications because there was only one service running in the backend and front end. Now, we are moving towards the microservices architecture, where applications are divided into multiple independently deployable services. These services have their own goal and logic to serve. In this kind of application architecture, it becomes difficult to observe how one service depends on or affects other services.&lt;/p&gt;

&lt;p&gt;To make the system observable, some logs, metrics, or traces must be emitted from the code, and this data must be sent to an observability backend. This is where OpenTelemetry and Jaeger come into the picture.&lt;/p&gt;

&lt;p&gt;In this blog post, we will see how to monitor application trace data (Traces and Spans) with the help of OpenTelemetry and Jaeger. Trace is used to observe the requests as they propagate through the services in a distributed system and Spans is a basic unit of the trace; it represents a single event within the trace, and a trace can have one or multiple spans. A span consists of log messages, time-related data, and other attributes to provide information about the operation it tracks.&lt;/p&gt;

&lt;p&gt;We will use the distributed tracing method to observe requests moving across microservices, generating data about the request and making it available for analysis. The produced data will have a record of the flow of requests in our microservices, and it will help us understand our application's performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;Telemetry is the collection and transmission of data using agents and protocols from the source in observability. The telemetry data includes logs, metrics, and traces, which help us understand what is happening in our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/"&gt;OpenTelemetry&lt;/a&gt; (also known as OTel) is an open source framework comprising a collection of tools, APIs, and SDKs. OpenTelemetry makes generating, instrumenting, collecting, and exporting telemetry data easy. The data collected from OpenTelemetry is vendor-agnostic and can be exported in many formats. OpenTelemetry is formed after merging two projects &lt;a href="https://opensource.googleblog.com/2019/05/opentelemetry-merger-of-opencensus-and.html"&gt;OpenCensus and OpenTracing&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Instrumenting
&lt;/h3&gt;

&lt;p&gt;The process of adding observability code to your application is known as instrumentation. Instrumentation helps make our application observable, meaning the code must produce some metrics, traces, and logs.&lt;br&gt;
OpenTelemetry provides two ways to instrument our code:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Manual Instrumentation&lt;/li&gt;
&lt;li&gt;Auto Instrumentation&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  1. Manual Instrumentation
&lt;/h4&gt;

&lt;p&gt;The user needs to add an OpenTelemetry code to the application. The manual instrumentation provides more options for customization in spans and traces. Languages supported for manual instrumentations are - C++, .NET, Go,  Java, Python, etc. &lt;/p&gt;
&lt;h4&gt;
  
  
  2. Automatic Instrumentation
&lt;/h4&gt;

&lt;p&gt;It is the easiest way of instrumentation as it requires no code changes and no need to recompile the application. It uses an intelligent agent that gets attached to an application, reads its activity, and extracts the traces. Automatic instrumentation supports Java, NodeJS, Python, etc.&lt;/p&gt;
&lt;h3&gt;
  
  
  Difference between Manual and Automatic Instrumentation.
&lt;/h3&gt;

&lt;p&gt;Both manual and automatic instrumentation have advantages and disadvantages that you might consider while writing your code. A few of them are listed below: &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Manual Instrumentation&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Automatic Instrumentation&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code Changes are required.&lt;/td&gt;
&lt;td&gt;Code Changes are not required.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It supports maximum programming languages.&lt;/td&gt;
&lt;td&gt;Currently, .Net, Java, NodeJS and Python are supported.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;It consumes a lot of time as code changes are required.&lt;/td&gt;
&lt;td&gt;Easy to implement as we do not need to touch the code.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provide more options for the customization of spans and traces. As you have more control over the telemetry data generated by your application.&lt;/td&gt;
&lt;td&gt;Fewer options for customization.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Possibilities of error are high as manual changes are required.&lt;/td&gt;
&lt;td&gt;No error possibilities. As we don't have to touch our application code.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To make the instrumentation process hassle-free, use automatic instrumentation as it does not require any modification in the code and reduces the possibility of errors. Automatic instrumentation is done by an agent which reads your application's telemetry data, so no manual changes are required.&lt;/p&gt;

&lt;p&gt;For the scope of this post, we will see how you can use automatic instrumentation in a Kubernetes-based microservices environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Jaeger
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jaegertracing.io/"&gt;Jaeger&lt;/a&gt; is a distributed tracing tool initially built by Uber and released as open source in 2015. Jaeger is also a Cloud Native Computing Foundation graduate project and was influenced by Dapper and OpenZipkin. It is used for monitoring and troubleshooting microservices-based distributed systems. &lt;/p&gt;

&lt;p&gt;The Jaeger components which we have used for this blog are: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Jaeger Collector&lt;/li&gt;
&lt;li&gt;Jaeger Query&lt;/li&gt;
&lt;li&gt;Jaeger UI / Console&lt;/li&gt;
&lt;li&gt;Storage Backend&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Jaeger Collector:&lt;/strong&gt; The Jaeger distributed tracing system includes the Jaeger collector. It is in charge of gathering and keeping the information. After receiving spans, the collector adds them to a processing queue. Collectors need a persistent storage backend, hence Jaeger also provides a pluggable span storage mechanism.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jaeger Query:&lt;/strong&gt; Is a service used to get traces out of storage. The web-based user interface for the Jaeger distributed tracing system is called Jaeger Query.  It provides various features and tools to help you understand the performance and behaviour of your distributed application and enables you to search, filter, and visualise the data gathered by Jaeger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jaeger UI / Console:&lt;/strong&gt; Jaeger UI lets you view and analyse traces generated by your application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage Backend:&lt;/strong&gt; Is used to store the traces generated by an application for the long term. In this post, we are going to use Elasticsearch to store the traces.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Trn1izX6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4su4xws4l5pcswrrt0z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Trn1izX6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4su4xws4l5pcswrrt0z.png" alt="Architecture of OpenTelemetry" width="880" height="488"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What is the need for integrating OpenTelemetry with Jaeger?
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry and Jaeger are the tools that help us in &lt;a href="https://dev.to/observability-consulting/"&gt;setting the observability in microservices-based distributed systems&lt;/a&gt;, but they are intended to address different issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenTelemetry&lt;/strong&gt; provides an instrumentation layer for the application, which helps us generate, collect and export the telemetry data for analysis. In contrast, &lt;strong&gt;Jaeger&lt;/strong&gt; is used to store and visualize telemetry data.&lt;/p&gt;

&lt;p&gt;OpenTelemetry can only generate and collect the data. It does not have a UI for the visualization. So we need to integrate Jaeger with OpenTelemetry as it has a storage backend and a web UI for the visualization of the telemetry data. With the help of Jaeger UI, we can quickly troubleshoot microservices-based distributed systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: OpenTelemetry can generate logs, metrics, and traces. Jaeger does not support logs and metrics.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you have an idea about OpenTelemetry and Jaeger. Let's see how we can Integrate them with each other to visualize the traces and spans generated by our application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Implementing OpenTelemetry auto-instrumentation
&lt;/h2&gt;

&lt;p&gt;We will integrate OpenTelemetry with Jaeger, where OpenTelemetry will act as an instrumentation layer for our application, and Jaeger will act as the backend analysis tool to visualize the trace data.&lt;/p&gt;

&lt;p&gt;Jaeger will get the telemetry data from the OpenTelemetry agent. It will store the data in the storage backend, from where we will query the stored data and visualize it in the Jaeger UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites for this blog are:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The target Kubernetes cluster is up and running.&lt;/li&gt;
&lt;li&gt;You have access to run the &lt;code&gt;kubectl&lt;/code&gt; command against the Kubernetes cluster to deploy resources.&lt;/li&gt;
&lt;li&gt;Cert manager is installed and running. You can install it from the website &lt;a href="https://cert-manager.io/docs/installation/#default-static-install"&gt;cert-manager.io&lt;/a&gt; if it is not installed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We assume that you have all the prerequisites and now you are ready for the installation. The files we have used for this post are available in this &lt;a href="https://github.com/infracloudio/Opentelemertrywithjaeger"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;The Installation part contains 3 Steps: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Elasticsearch Installation&lt;/li&gt;
&lt;li&gt;Jaeger Installation&lt;/li&gt;
&lt;li&gt;OpenTelemetry Installation&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Elasticsearch
&lt;/h3&gt;

&lt;p&gt;By default, Jaeger uses in-memory storage to store spans, which is not a recommended approach for the production environment. There are various tools available to use as a storage backend in Jaeger; you can read about them in the official documentation of &lt;a href="https://www.jaegertracing.io/docs/1.40/deployment/#span-storage-backends"&gt;Jaeger span storage backend&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In this blog post, we will use Elasticsearch as a storage backend. You can deploy Elasticsearch in your Kubernetes cluster using the &lt;a href="https://artifacthub.io/packages/helm/elastic/elasticsearch"&gt;Elasticsearch Helm chart&lt;/a&gt;. While deploying Elasticsearch, ensure you have enabled the password-based authentication and deploy that Elasticsearch in &lt;strong&gt;observability&lt;/strong&gt; namespaces.&lt;/p&gt;

&lt;p&gt;Elasticsearch is deployed in our Kubernetes cluster, and you can see the output by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; observability

NAME                            READY   STATUS    RESTARTS   AGE
pod/elasticsearch-0             1/1     Running   0          17m

NAME                            TYPE           CLUSTER-IP       EXTERNAL-IP          PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;           AGE
service/elasticsearch         ClusterIP          None            &amp;lt;none&amp;gt;         9200/TCP,9300/TCP      17m

NAME                             READY   AGE
statefulset.apps/elasticsearch   1/1     17m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Jaeger Installation
&lt;/h2&gt;

&lt;p&gt;We are going to use Jaeger to visualize the trace data. Let's deploy the Jaeger Operator on our cluster.&lt;/p&gt;

&lt;p&gt;Before proceeding with the installation, we will deploy a &lt;code&gt;ConfigMap&lt;/code&gt; in the observability namespace. In this ConfigMap, we will pass the username and password of the Elasticsearch which we have deployed in the previous step. Replace the credentials based on your setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; observability apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: v1
kind: ConfigMap
metadata:
  name: jaeger-configuration
  labels:
    app: jaeger
    app.kubernetes.io/name: jaeger
data:
  span-storage-type: elasticsearch
  collector: |
    es:
      server-urls: http://elasticsearch:9200
      username: elastic
      password: changeme
    collector:
      zipkin:
        http-port: 9411
  query: |
    es:
      server-urls: http://elasticsearch:9200
      username: elastic
      password: changeme
  agent: |
    collector:
      host-port: "jaeger-collector:14267"
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are going to deploy the Jaeger in another namespace and you have changed the Jaeger collector service name, then you need to change the values of the host-port value under the agent collector.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jaeger Operator
&lt;/h3&gt;

&lt;p&gt;The Jaeger Operator is a Kubernetes operator for deploying and managing Jaeger, an open source, distributed tracing system. It works by automating the deployment, scaling, and management of Jaeger components on a Kubernetes cluster. The Jaeger Operator uses custom resources and custom controllers to extend the Kubernetes API with Jaeger-specific functionality. It manages the creation, update, and deletion of Jaeger components, such as the Jaeger collector, query, and agent components. When a Jaeger instance is created, the Jaeger Operator deploys the necessary components and sets up the required services and configurations.&lt;/p&gt;

&lt;p&gt;We are going to deploy the Jaeger Operator in the observability namespace. Use the below-mentioned command to deploy the operator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; https://github.com/jaegertracing/jaeger-operator/releases/download/v1.38.0/jaeger-operator.yaml &lt;span class="nt"&gt;-n&lt;/span&gt; observability
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are using the latest version of Jaeger, which is &lt;strong&gt;1.38.0&lt;/strong&gt; at the time of writing this article.&lt;/p&gt;

&lt;p&gt;By default, the Jaeger script is provided for cluster-wide mode. Suppose you want to watch only a particular namespace. In that case, you need to change the &lt;code&gt;ClusterRole&lt;/code&gt; to &lt;code&gt;Role&lt;/code&gt; and &lt;code&gt;ClusterBindingRole&lt;/code&gt; to &lt;code&gt;RoleBinding&lt;/code&gt; in the operator manifest and set the &lt;code&gt;WATCH_NAMESPACE&lt;/code&gt; env variable on the Jaeger Operator deployment. &lt;/p&gt;

&lt;p&gt;To verify whether Jaeger is deployed successfully or not, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; observability

NAME                                    READY   STATUS    RESTARTS   AGE
pod/elasticsearch-0                     1/1     Running   0          17m
pod/jaeger-operator-5597f99c79-hd9pw    2/2     Running   0          11m

NAME                                      TYPE           CLUSTER-IP       EXTERNAL-IP             PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;                  AGE
service/elasticsearch                     ClusterIP      None             &amp;lt;none&amp;gt;              9200/TCP,9300/TCP            17m
service/jaeger-operator-metrics           ClusterIP      172.20.220.212   &amp;lt;none&amp;gt;                 8443/TCP                  11m
service/jaeger-operator-webhook-service   ClusterIP      172.20.224.23    &amp;lt;none&amp;gt;                 443/TCP                   11m


NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/jaeger-operator     1/1        1            1       11m

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/jaeger-operator-5597f99c79       1         1        1     11m

NAME                             READY   AGE
statefulset.apps/elasticsearch   1/1     17m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see in the above output, our Jaeger Operator is deployed successfully, and all of its pods are up and running; this means Jaeger Operator is ready to install the Jaeger instances (CRs). The Jaeger instance will contain Jaeger components (Query, Collector, Agent ); later, we will use these components to query OpenTelemetry metrics.    &lt;/p&gt;

&lt;h3&gt;
  
  
  Jaeger Instance
&lt;/h3&gt;

&lt;p&gt;A Jaeger Instance is a deployment of the Jaeger distributed tracing system. It is used to collect and store trace data from microservices or distributed applications, and provide a UI to visualize and analyze the trace data. To deploy the Jaeger instance, use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/infracloudio/Opentelemertrywithjaeger/master/jaeger-production-template.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the status of the Jaeger instance, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; observability

NAME                                    READY   STATUS    RESTARTS   AGE
pod/elasticsearch-0                     1/1     Running   0          17m
pod/jaeger-agent-27fcp                  1/1     Running   0          14s
pod/jaeger-agent-6lvp2                  1/1     Running   0          15s
pod/jaeger-collector-69d7cd5df9-t6nz9   1/1     Running   0          19s
pod/jaeger-operator-5597f99c79-hd9pw    2/2     Running   0          11m
pod/jaeger-query-6c975459b6-8xlwc       1/1     Running   0          16s

NAME                                      TYPE           CLUSTER-IP       EXTERNAL-IP             PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;                                AGE
service/elasticsearch                     ClusterIP      None             &amp;lt;none&amp;gt;              9200/TCP,9300/TCP                          17m
service/jaeger-collector                  ClusterIP      172.20.24.132    &amp;lt;none&amp;gt;             14267/TCP,14268/TCP,9411/TCP,14250/TCP      19s
service/jaeger-operator-metrics           ClusterIP      172.20.220.212   &amp;lt;none&amp;gt;                    8443/TCP                             11m
service/jaeger-operator-webhook-service   ClusterIP      172.20.224.23    &amp;lt;none&amp;gt;                    443/TCP                              11m
service/jaeger-query                      LoadBalancer   172.20.74.114    a567a8de8fd5149409c7edeb54bd39ef-365075103.us-west-2.elb.amazonaws.com   80:32406/TCP                   16s
service/zipkin                            ClusterIP      172.20.61.72     &amp;lt;none&amp;gt;                 9411/TCP                                 18s

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/jaeger-agent      2         2         2       2            2           &amp;lt;none&amp;gt;       16s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/jaeger-collector    1/1     1            1          21s
deployment.apps/jaeger-operator     1/1     1            1          11m
deployment.apps/jaeger-query        1/1     1            1          18s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/jaeger-collector-69d7cd5df9     1         1         1     21s
replicaset.apps/jaeger-operator-5597f99c79      1         1         1     11m
replicaset.apps/jaeger-query-6c975459b6         1         1         1     18s

NAME                             READY   AGE
statefulset.apps/elasticsearch    1/1    17m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see in the above screenshot our Jaeger instance is up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTelemetry
&lt;/h2&gt;

&lt;p&gt;To install the OpenTelemetry, we need to install the OpenTelemetry Operator. The OpenTelemetry Operator uses custom resources and custom controllers to extend the Kubernetes API with OpenTelemetry-specific functionality, making it easier to deploy and manage the OpenTelemetry observability stack in a Kubernetes environment.&lt;/p&gt;

&lt;p&gt;The operator manages two things: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Collectors:&lt;/strong&gt; It offers a vendor-agnostic implementation of how to receive, process and export telemetry data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-instrumentation&lt;/strong&gt; of the workload using OpenTelemetry instrumentation libraries. It does not require the end-user to modify the application source code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  OpenTelemetry operator
&lt;/h3&gt;

&lt;p&gt;To implement the auto-instrumentation, we need to deploy the OpenTelemetry operator on our Kubernetes cluster. To deploy the k8s operator for OpenTelemetry, follow the &lt;a href="https://opentelemetry.io/docs/k8s-operator/"&gt;K8s operator documentation&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;You can verify the deployment of the OpenTelemetry operator by running the below-mentioned command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt;  opentelemetry-operator-system

NAME                                                             READY   STATUS    RESTARTS    AGE
pod/opentelemetry-operator-controller-manager-7f479c786d-zzfd8    2/2    Running      0        30s

NAME                                                                TYPE        CLUSTER-IP       EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;    AGE
service/opentelemetry-operator-controller-manager-metrics-service   ClusterIP   172.20.70.244    &amp;lt;none&amp;gt;        8443/TCP   32s
service/opentelemetry-operator-webhook-service                      ClusterIP   172.20.150.120   &amp;lt;none&amp;gt;        443/TCP    31s

NAME                                                        READY   UP-TO-DATE   AVAILABLE      AGE
deployment.apps/opentelemetry-operator-controller-manager    1/1        1            1          31s

NAME                                                                   DESIRED   CURRENT   READY    AGE
replicaset.apps/opentelemetry-operator-controller-manager-7f479c786d      1         1        1      31s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see in the above output, the opentelemetry-operator-controller-manager deployment is running in the opentelemetry-operator-system namespace.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenTelemetry Collector
&lt;/h3&gt;

&lt;p&gt;The OpenTelemetry facilitates the collection of telemetry data via the OpenTelemetry Collector. Collector offers a vendor-agnostic implementation on how to receive, process, and export the telemetry data.&lt;/p&gt;

&lt;p&gt;The collector is made up of the following components: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Receivers:&lt;/strong&gt; It manages how to get data into the collector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Processors:&lt;/strong&gt; It manages the processing of data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exporters:&lt;/strong&gt; Responsible for sending the received data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also need to export the telemetry data to the Jaeger instance. Use the following manifest to deploy the collector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: otel
spec:
  config: |
    receivers:
      otlp:
        protocols:
          grpc:
          http:

    processors:

    exporters:
      logging:
      jaeger:
        endpoint: "jaeger-collector.observability.svc.cluster.local:14250"
        tls:
          insecure: true
    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [logging, jaeger]
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In above code Jaeger endpoint is the address of the Jaeger service which is running inside the observability namespace.&lt;/p&gt;

&lt;p&gt;We need to deploy this manifest in the same namespace where our application is deployed, so that it can fetch the traces from the application and export them to Jaeger.&lt;/p&gt;

&lt;p&gt;To verify the deployment of the collector run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get deploy otel-collector

NAME              READY    UP-TO-DATE   AVAILABLE      AGE
otel-collector     1/1         1            1          41s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  OpenTelemetry auto-instrumentation injection
&lt;/h3&gt;

&lt;p&gt;The above-deployed operator can inject and configure the auto-instrumentation libraries of OpenTelemetry into an application's codebase as it runs. To enable the auto-instrumentation on our cluster, we need to configure an instrumentation resource with the configuration for the SDK and instrumentation.&lt;/p&gt;

&lt;p&gt;Use the below-given manifest to create the auto-instrumentation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:
  name: my-instrumentation
spec:
  exporter:
    endpoint: http://otel-collector:4317
  propagators:
    - tracecontext
    - baggage
    - b3
  sampler:
    type: parentbased_traceidratio
    argument: "0.25"
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above manifest, we have used three things: &lt;code&gt;exporter, propagator, and sampler&lt;/code&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exporter&lt;/strong&gt;: It is used to send data to OpenTelemetry collector at the specified endpoint. In our scenario, it is "&lt;a href="http://otel-collector:4317"&gt;http://otel-collector:4317&lt;/a&gt;". &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Propagators&lt;/strong&gt;: - It carry traces, context and baggage data between distributed tracing systems. It have three propagation mechanism:- &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;tracecontext&lt;/strong&gt;: This refers to the W3C Trace Context specification, which defines a standard way to propagate trace context information between services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;baggage&lt;/strong&gt;: This refers to the OpenTelemetry baggage mechanism, which allows for the propagation of arbitrary key-value pairs along with the trace context information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;b3&lt;/strong&gt;: This refers to the B3 header format, which is a popular trace context propagation format used by the Zipkin tracing system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sampler&lt;/strong&gt;: - It uses a "parent-based trace ID ratio" strategy with a sample rate of 0.25 (25%). This means that when tracing a request, if any of its parent requests has already been sampled (with a probability of 0.25), then this request will also be sampled, otherwise it will not be traced.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To verify that our custom resource is created or not, we can use the below-mentioned command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get otelinst

NAME                   AGE          ENDPOINT                          SAMPLER                 SAMPLER ARG
my-instrumentation      6s     http://otel-collector:4317       parentbased_traceidratio          0.25
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means our custom resource is created successfully.&lt;/p&gt;

&lt;p&gt;We are using the OpenTelemetry auto-instrumented method, so we don’t need to write instrumentation code in our application. All we need to do is, add an annotation in the pod of our application for auto-instrumentation. Below are the annotations which we need to add to the deployment manifest.  &lt;/p&gt;

&lt;p&gt;As we are going to demo a Java application, the annotation which we will have to use here is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;instrumentation.opentelemetry.io/inject-java: &lt;span class="s2"&gt;"true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note: The annotation can be added to a namespace as well so that all pods within that namespace will get instrumentation, or by adding the annotation to individual PodSpec objects, available as part of Deployment, Statefulset, and other resources.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Below is an example of how your manifest will look after adding the annotations. In the below example, we are using annotation for a Java application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-sagar&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
 &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-sagar&lt;/span&gt;
 &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;demo-sagar&lt;/span&gt;
     &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;instrumentation.opentelemetry.io/inject-java&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
       &lt;span class="na"&gt;instrumentation.opentelemetry.io/container-names&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spring"&lt;/span&gt;
   &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring&lt;/span&gt;
       &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sagar27/petclinic-demo&lt;/span&gt;
       &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have added instrumentation “inject-java” and “container-name” under annotations. If you have multiple container pods, you can add them in the same “container-names” annotation, separated by a comma. For example, “container-name1,container-name-2,container-name-3” etc.&lt;/p&gt;

&lt;p&gt;After adding the annotations, deploy your application, and access it on the browser. Here in our scenario,  we are using port-forward to access the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl port-forward service/demo-sagar  8080:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H6hXxkkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7egjhqty78k6q4ql0rrj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H6hXxkkv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7egjhqty78k6q4ql0rrj.png" alt="Demo Application" width="880" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To generate traces either you can navigate through all the pages of this website or you can use the following Bash script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do
  &lt;/span&gt;curl http://localhost:8080/
  curl http://localhost:8080/owners/find
  curl http://localhost:8080/owners?lastName&lt;span class="o"&gt;=&lt;/span&gt;
  curl http://localhost:8080/vets.html
  curl http://localhost:8080/oups
  curl http://localhost:8080/oups
  &lt;span class="nb"&gt;sleep &lt;/span&gt;0.01
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above-given script will make a curl request to all the pages of the website, and we will see the traces of the request on the Jaeger UI. We are making curl requests to  &lt;a href="https://localhost:8080"&gt;https://localhost:8080&lt;/a&gt; because we use the port-forwarding technique to access the application.&lt;br&gt;
You can make changes in the Bash script according to your scenario.&lt;/p&gt;

&lt;p&gt;Now let’s access the Jaeger UI, as our service jaeger-query uses service type &lt;code&gt;LoadBalancer&lt;/code&gt;,  we can access the Jaeger UI on the browser by using the load balancer domain/IP. &lt;/p&gt;

&lt;p&gt;Paste the load balancer domain / IP on the browser and you will see the Jaeger UI there. We have to select our app from the service list and it will show us the traces it generates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NIbWPO1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/84de3fm8t2uds4jt9p4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NIbWPO1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/84de3fm8t2uds4jt9p4q.png" alt="Jaeger UI" width="880" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the above screenshot, we have selected our app name “demo-sagar” under the services option and its traces are visible on Jaeger UI. We can further click on the traces to get more details about it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TrsQhVZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqnhcdcue1m2emgx3o6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TrsQhVZt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rqnhcdcue1m2emgx3o6p.png" alt="Jaeger UI with Trace Details" width="880" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this blog post, we have gone through how you can easily instrument your application using the OpenTelemetry auto-instrumentation method. We also learned how this telemetric data could be exported to the Elasticsearch backend and visualized it using Jaeger. &lt;/p&gt;

&lt;p&gt;Integrating OpenTelemerty with Jaeger will help you in monitoring and troubleshooting. It also helps perform root cause analysis of any bug/issues in your microservice-based distributed systems, performance/latency optimization, service dependency analysis, etc.&lt;/p&gt;

&lt;p&gt;We hope you found this post informative and engaging. We would love to hear your thoughts on this post, so do start a conversation on &lt;a href="https://twitter.com/sagarrajput27"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/sagar-parmar-834403a6/"&gt;LinkedIn&lt;/a&gt; :).&lt;/p&gt;

&lt;p&gt;If you want to implement observability in your microservices, talk to our &lt;a href="https://dev.to/observability-consulting/"&gt;observability consulting and implementation experts&lt;/a&gt;, and for more posts like this one, do visit our &lt;a href="https://dev.to/blogs/"&gt;blogs section&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/"&gt;OpenTelemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jaegertracing.io/"&gt;Jaeger Tracing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>opentelemetry</category>
      <category>jaeger</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
