<?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: Kimi Huang</title>
    <description>The latest articles on Forem by Kimi Huang (@kimihuang).</description>
    <link>https://forem.com/kimihuang</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%2F1027871%2F10034d06-2e6a-478a-8dff-93503cceb27d.jpg</url>
      <title>Forem: Kimi Huang</title>
      <link>https://forem.com/kimihuang</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kimihuang"/>
    <language>en</language>
    <item>
      <title>KRO: A new generation tool to manage Kubernetes manifests and deployment</title>
      <dc:creator>Kimi Huang</dc:creator>
      <pubDate>Thu, 22 May 2025 07:09:41 +0000</pubDate>
      <link>https://forem.com/aws-builders/kro-a-new-generation-tool-to-manage-kubernetes-manifests-and-deployment-55dm</link>
      <guid>https://forem.com/aws-builders/kro-a-new-generation-tool-to-manage-kubernetes-manifests-and-deployment-55dm</guid>
      <description>&lt;h1&gt;
  
  
  About KRO
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://kro.run/" rel="noopener noreferrer"&gt;KRO&lt;/a&gt; (Kube Resource Orchestrator) is an open-source, Kubernetes-native project that allows you to define custom Kubernetes APIs using simple and straightforward configuration.&lt;/p&gt;

&lt;p&gt;KRO is currently governed by a small group of maintainers - from Google, Amazon, and Microsoft - who are responsible for the overall direction and management of the project, as well as for the technical decisions that affect the project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview
&lt;/h1&gt;

&lt;p&gt;When you mention manifest and deployment management tools on Kubernetes, the first things that come to mind are &lt;a href="https://helm.sh/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; or &lt;a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/" rel="noopener noreferrer"&gt;Kustomization&lt;/a&gt;. Later, there was even a project in CNCF called &lt;a href="https://www.crossplane.io/" rel="noopener noreferrer"&gt;Crossplane&lt;/a&gt; that allows you to implement IaC through YAML files, making it very convenient for you to deploy infrastructure on Cloud Service Providers.&lt;/p&gt;

&lt;p&gt;KRO proposed a brand new approach, allowing you to manage manifests and deployments on Kubernetes through very intuitive YAML file writing, and also enabling infrastructure deployment like Crossplane.&lt;/p&gt;

&lt;p&gt;Since KRO is still in a very early stage, some features are not yet complete. This article will use a very simple example to introduce how KRO performs manifest and deployment management.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Installing KRO
&lt;/h2&gt;

&lt;p&gt;Before you begin, ensure you have the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Helm 3.x installed&lt;/li&gt;
&lt;li&gt;kubectl installed and configured to interact with your Kubernetes cluster
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export KRO_VERSION=$(curl -sL \
    https://api.github.com/repos/kro-run/kro/releases/latest | \
    jq -r '.tag_name | ltrimstr("v")'
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm install kro oci://ghcr.io/kro-run/kro/kro \
  --namespace kro \
  --create-namespace \
  --version=${KRO_VERSION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Check KRO Readiness
&lt;/h2&gt;



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

NAME                       READY   STATUS    RESTARTS      AGE
pod/kro-69b4b67b67-xhvht   1/1     Running   0             1d

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kro   1/1     1            1           1d

NAME                             DESIRED   CURRENT   READY   AGE
replicaset.apps/kro-69b4b67b67   1         1         1       1d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





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

NAME                               CREATED AT
applications.kro.run               2025-05-22T07:23:13Z
resourcegraphdefinitions.kro.run   2025-05-22T07:10:25Z
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Resource Graph Definitions
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://kro.run/docs/concepts/resource-group-definitions" rel="noopener noreferrer"&gt;Resource Graph Definitions&lt;/a&gt;  are a very important concept in KRO. You can think of Resource Graph Definitions as a blueprint drawn by an architect for a house in real life, which specifies the specifications for each part. Anyone who gets this blueprint can build an identical house. In some flexible areas, you can even make small modifications, such as the paint color or the style of the pendant light.&lt;/p&gt;

&lt;h1&gt;
  
  
  Deep Dive Into Resource Graph Definitions
&lt;/h1&gt;

&lt;p&gt;Let's explain with a simple Resource Graph Definition example. After KRO is installed, it will create two &lt;a href="https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/" rel="noopener noreferrer"&gt;Custom Resource Definition&lt;/a&gt; (CRD) on your Kubernetes cluster: &lt;code&gt;applications.kro.run&lt;/code&gt; and &lt;code&gt;resourcegraphdefinitions.kro.run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lines 6 to 16: We will declare a scheme that includes some fields that can be adjusted by the user, just like the paint color or the style of the pendant light mentioned in the previous section. You can assign a default value to these fields or specify their type, such as string or integer.&lt;/p&gt;

&lt;p&gt;Lines 17 to 44: A common Kubernetes deployment is declared here. Some field values within it will reference the values defined in the schema. Referencing values is very simple; you just need to use the $ sign and {} brackets to specify the Key location of the field inside.　&lt;/p&gt;

&lt;p&gt;This completes a simple Resource Graph Definition. In the next section, we will gradually explain how to construct the application we want on Kubernetes using this Resource Graph Definition.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;rgd.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1  apiVersion: kro.run/v1alpha1
2  kind: ResourceGraphDefinition
3  metadata:
4    name: my-color-application
5  spec:
6    schema:
7      apiVersion: v1alpha1
8      kind: Application
9      spec:
10       name: string
11       image: string | default="pj3677/color-app:latest"
12       color: string | default="red"
13       commonlabel: string | default="color-application"
14     status:
15       deploymentConditions: ${deployment.status.conditions}
16       availableReplicas: ${deployment.status.availableReplicas}
17   resources:
18     - id: deployment
19       template:
20         apiVersion: apps/v1
21         kind: Deployment
22         metadata:
23           name: ${schema.spec.name} 
24           labels:
25             purpose: ${schema.spec.commonlabel}
26         spec:
27           replicas: 2
28           selector:
29             matchLabels:
30               app: ${schema.spec.name}
31           template:
32             metadata:
33               labels:
34                 app: ${schema.spec.name}
35                 purpose: ${schema.spec.commonlabel}
36             spec:
37               containers:
38                 - name: ${schema.spec.name}
39                   image: ${schema.spec.image} 
40                   ports:
41                     - containerPort: 3000
42                   env:
43                     - name: BG_COLOR
44                       value: ${schema.spec.color}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Deploy Applications with Instances
&lt;/h1&gt;

&lt;p&gt;An instance represents your deployed application. When you create an instance, you're telling KRO controller "I want to create this set of resources running in my Kubernetes cluster via the Resource Graph Definition".&lt;/p&gt;

&lt;p&gt;Below is an example of an Instance. From this example, we can see there is a field called color and specified to &lt;code&gt;lightgreen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;instance.yaml&lt;/code&gt; is deployed to Kubernetes, the KRO controller will receive the request and refer to the Resource Graph Definition specified in instance.yaml to generate the corresponding set of resources, which is the Application we want to construct.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;instance.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: kro.run/v1alpha1
kind: Application
metadata:
  name: color-lightgreen
spec:
  name: color-lightgreen-app
  color: "lightgreen"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Demonstration
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Deploy Resource Graph Definition
&lt;/h2&gt;

&lt;p&gt;In this complete Resource Graph Definition example, we defined three fields:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An &lt;code&gt;image&lt;/code&gt; field that defaults to using the image &lt;code&gt;pj3677/color-app:latest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A string field named &lt;code&gt;color&lt;/code&gt; with a default value of &lt;code&gt;red&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A string field named &lt;code&gt;commonlabel&lt;/code&gt; with a default value of &lt;code&gt;color-application&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This Resource Graph Definition includes both Kubernetes &lt;code&gt;Deployment&lt;/code&gt; and &lt;code&gt;Service&lt;/code&gt; resources. Some fields within it will reference the values defined in the &lt;code&gt;schema&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;resource-definition.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: kro.run/v1alpha1
kind: ResourceGraphDefinition
metadata:
  name: my-color-application
spec:
  schema:
    apiVersion: v1alpha1
    kind: Application
    spec:
      name: string
      image: string | default="pj3677/color-app:latest"
      color: string | default="red"
      commonlabel: string | default="color-application"
    status:
      deploymentConditions: ${deployment.status.conditions}
      availableReplicas: ${deployment.status.availableReplicas}
  resources:
    - id: deployment
      template:
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: ${schema.spec.name} 
          labels:
            purpose: ${schema.spec.commonlabel}
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: ${schema.spec.name}
          template:
            metadata:
              labels:
                app: ${schema.spec.name}
                purpose: ${schema.spec.commonlabel}
            spec:
              containers:
                - name: ${schema.spec.name}
                  image: ${schema.spec.image} 
                  ports:
                    - containerPort: 3000
                  env:
                    - name: BG_COLOR
                      value: ${schema.spec.color}
    - id: service
      template:
        apiVersion: v1
        kind: Service
        metadata:
          name: ${schema.spec.name}-service
          labels:
            purpose: ${schema.spec.commonlabel}
        spec:
          selector: ${deployment.spec.selector.matchLabels}
          ports:
            - protocol: TCP
              port: 3000
              targetPort: 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's deploy this Resource Graph Definition to our Kubernetes cluster.&lt;br&gt;
&lt;/p&gt;

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

resourcegraphdefinition.kro.run/my-color-application created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the Resource Graph Definition readiness.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get resourcegraphdefinition.kro.run -o wide

NAME                   APIVERSION   KIND          STATE    TOPOLOGICALORDER           AGE
my-color-application   v1alpha1     Application   Active   ["deployment","service"]   59s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see our &lt;code&gt;my-color-application&lt;/code&gt; Resource Graph Definition has been deployed to Kubernetes cluster and it contains two Kubernetes resources &lt;code&gt;deployment&lt;/code&gt; and &lt;code&gt;service&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Deploy Instances
&lt;/h2&gt;

&lt;p&gt;Next, we constructed two Instances. The purpose is to generate two different Applications using the same Resource Graph Definition.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;color-lightgreen.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: kro.run/v1alpha1
kind: Application
metadata:
  name: color-lightgreen
spec:
  name: color-lightgreen-app
  color: "lightgreen"
  commonlabel: "lightgreen-application"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy &lt;code&gt;color-lightgreen.yaml&lt;/code&gt; instance.&lt;br&gt;
&lt;/p&gt;

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

application.kro.run/color-lightgreen created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;color-skyblue.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: kro.run/v1alpha1
kind: Application
metadata:
  name: color-skyblue
spec:
  name: color-skyblue-app
  color: "skyblue"
  commonlabel: "skyblue-application"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy &lt;code&gt;color-skyblue&lt;/code&gt; instance.&lt;br&gt;
&lt;/p&gt;

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

application.kro.run/color-skyblue created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Check Application Readiness
&lt;/h2&gt;



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

NAME                                        READY   STATUS    RESTARTS   AGE
pod/color-lightgreen-app-6f58f87b75-7l5p9   1/1     Running   0          4m
pod/color-lightgreen-app-6f58f87b75-v62mf   1/1     Running   0          4m
pod/color-skyblue-app-5fdcd5fbbc-gwpw7      1/1     Running   0          10s
pod/color-skyblue-app-5fdcd5fbbc-psv2m      1/1     Running   0          10s

NAME                                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/color-lightgreen-app-service   ClusterIP   10.96.181.168   &amp;lt;none&amp;gt;        3000/TCP   3m32s
service/color-skyblue-app-service      ClusterIP   10.96.236.33    &amp;lt;none&amp;gt;        3000/TCP   1s
service/kubernetes                     ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP    5m2s

NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/color-lightgreen-app   2/2     2            2           4m
deployment.apps/color-skyblue-app      2/2     2            2           11s

NAME                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/color-lightgreen-app-6f58f87b75   2         2         2       4m
replicaset.apps/color-skyblue-app-5fdcd5fbbc      2         2         2       10s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's use &lt;code&gt;kubectl port-forward&lt;/code&gt; to check the application's behavior as we expected.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the &lt;code&gt;color-lightgreen&lt;/code&gt; Instance
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl port-forward service/color-lightgreen-app-service 3000:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;color-lightgreen&lt;/code&gt; via &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&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%2Fhd2msi6f8afwcy4d4vxo.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%2Fhd2msi6f8afwcy4d4vxo.png" alt=" " width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the &lt;code&gt;color-skyblue&lt;/code&gt; Instance
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl port-forward service/color-skyblue-app-service 3000:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visit &lt;code&gt;color-skyblue&lt;/code&gt; via &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&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%2F9ryw86fji2hys2qojfqy.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%2F9ryw86fji2hys2qojfqy.png" alt=" " width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfect the result as we expected. The two applications have different background colors: &lt;code&gt;lightgreen&lt;/code&gt; and &lt;code&gt;skyblue&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Behavior Analyze&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason for having different background colors is because we provided different parameters in the two instances: &lt;code&gt;color: "lightgreen"&lt;/code&gt; and &lt;code&gt;color: "skyblue"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And this parameter will be passed into this snippet within the &lt;code&gt;Kubernetes Deployment&lt;/code&gt; defined in the Resource Graph Definition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env:
  - name: BG_COLOR
    value: ${schema.spec.color}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application will generate the specified background color through this environment variable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cleanup
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Remove color-skyblue instance:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl delete -f color-skyblue.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Remove color-lightgreen instance:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl delete -f color-lightgreen.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Remove Resource Graph Definition:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl delete -f resource-definition.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Uninstall KRO:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm delete kro -n kro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;KRO provides an easier way to write and manage Kubernetes manifests and deployments compared to Helm or Kustomization. It also enables the currently popular Infrastructure as Code architectural design.&lt;/p&gt;

&lt;p&gt;This means that by learning just one tool, you can accomplish both Kubernetes deployment management and Infrastructure as Code.&lt;/p&gt;

&lt;p&gt;It must be noted that KRO is currently in the Alpha stage and is not yet suitable for your production environment. You can continue to follow this project, and when it matures, it may be able to replace your current complex toolchain.&lt;/p&gt;

</description>
      <category>eks</category>
      <category>kubernetes</category>
      <category>iac</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Vector: A lightweight tool for collecting EKS application logs with long-term storage capabilities</title>
      <dc:creator>Kimi Huang</dc:creator>
      <pubDate>Wed, 30 Apr 2025 17:44:22 +0000</pubDate>
      <link>https://forem.com/aws-builders/vector-a-lightweight-tool-for-collecting-eks-application-logs-with-long-term-storage-capabilities-44j4</link>
      <guid>https://forem.com/aws-builders/vector-a-lightweight-tool-for-collecting-eks-application-logs-with-long-term-storage-capabilities-44j4</guid>
      <description>&lt;h1&gt;
  
  
  About Vector
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://vector.dev/" rel="noopener noreferrer"&gt;Vector&lt;/a&gt; is a high-performance observability data pipeline tool developed by &lt;a href="https://www.datadoghq.com/" rel="noopener noreferrer"&gt;Datadog&lt;/a&gt; that puts organizations in control of their observability data. Collect, transform, and route all your logs, metrics, and traces to any vendors you want today and any other vendors you may want tomorrow. Vector enables dramatic cost reduction, novel data enrichment, and data security where you need it, not where is most convenient for your vendors. Open source and up to 10x faster than every alternative.&lt;/p&gt;

&lt;h1&gt;
  
  
  AWS Architecture
&lt;/h1&gt;

&lt;p&gt;In this article, we present an architecture that demonstrates how to collect application logs from Amazon Elastic Kubernetes Service (&lt;a href="https://aws.amazon.com/eks/" rel="noopener noreferrer"&gt;Amazon EKS&lt;/a&gt;) via Vector, store them in Amazon Simple Storage Service (&lt;a href="https://aws.amazon.com/s3/" rel="noopener noreferrer"&gt;Amazon S3&lt;/a&gt;) for long-term retention, and finally query these logs using &lt;a href="https://aws.amazon.com/glue/" rel="noopener noreferrer"&gt;AWS Glue&lt;/a&gt; and &lt;a href="https://aws.amazon.com/athena/" rel="noopener noreferrer"&gt;Amazon Athena&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;The architecture diagram is as below&lt;/u&gt;&lt;/strong&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%2Fipphj98oxxkg2t5hfqe6.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%2Fipphj98oxxkg2t5hfqe6.png" alt=" " width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's build this Step by Step!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Create an S3 bucket for long-term log retention
&lt;/h2&gt;

&lt;p&gt;Make sure &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; is installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3api create-bucket --bucket my-vector-demo --region ap-northeast-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;[Note]: Replace &lt;code&gt;my-vector-demo&lt;/code&gt; with your own S3 bucket name.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create IAM Policy for Vector Agent
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iam create-policy \
    --policy-name vector-s3-access \
    --policy-document file://vector-iam-policy.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;vector-iam-policy.json&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "S3PutObject",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::my-vector-demo/*"
        },
        {
            "Sid": "S3ListBucket",
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::my-vector-demo"
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;[Note]: Replace &lt;code&gt;my-vector-demo&lt;/code&gt; with S3 bucket name same as Step 1.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Create EKS Cluster
&lt;/h2&gt;

&lt;p&gt;Create ESK cluster via &lt;a href="https://eksctl.io/" rel="noopener noreferrer"&gt;eksctl&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl create cluster -f cluster.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;cluster.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: my-vector-cluster
  region: ap-northeast-1
  version: "1.32"

vpc:
  cidr: "192.168.0.0/16"

addons:
- name: vpc-cni
  attachPolicyARNs:
    - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
  resolveConflicts: overwrite
- name: eks-pod-identity-agent

iam:
  withOIDC: true
  podIdentityAssociations:
  - namespace: vector
    serviceAccountName: vector-sa
    roleName: pod-identity-role-vector
    createServiceAccount: true
    permissionPolicyARNs: ["arn:aws:iam::115789992589:policy/vector-s3-access"]

managedNodeGroups:
  - name: application-ng
    instanceType: t3a.small
    desiredCapacity: 2
    minSize: 2
    maxSize: 3
    amiFamily: Bottlerocket
    ssh:
      allow: false
    volumeSize: 20
    volumeEncrypted: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will take approximately 10-15 minutes for your Cluster to be created. Once it's created, you can interact with your EKS cluster using &lt;a href="https://kubernetes.io/docs/tasks/tools/#kubectl" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[Note]: Replace &lt;code&gt;115789992589&lt;/code&gt; with your own 12-digit AWS Account Number.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Deploy a Log Generator Application
&lt;/h2&gt;

&lt;p&gt;Apply YAML file to EKS cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f log-generator.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;log-generator.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Namespace
metadata:
  name: log-generator
  labels:
    app: flog
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: flog
  namespace: log-generator
spec:
  replicas: 2
  selector:
    matchLabels:
      app: flog
  template:
    metadata:
      labels:
        app: flog
    spec:
      containers:
        - name: flog
          image: mingrammer/flog:0.4.3
          args: ["-f", "json", "-d", "5s", "-t", "stdout", "-l"]
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: flog
  namespace: log-generator
spec:
  selector:
    app: flog
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This log generator application will generate a JSON format log payload every 5 seconds and print it out using stdout.&lt;/p&gt;

&lt;p&gt;Check log generator application readiness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get all -n log-generator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see two pods running in the log-generator namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                        READY   STATUS    RESTARTS   AGE
pod/flog-6776c79fc5-9mnqh   1/1     Running   0          10s
pod/flog-6776c79fc5-rp7sp   1/1     Running   0          10s

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/flog   ClusterIP   10.100.217.73   &amp;lt;none&amp;gt;        80/TCP    10s

NAME                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/flog   2/2     2            2           11s

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/flog-6776c79fc5   2         2         2       11s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The log generator application log payloads are as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"host":"82.43.196.160", "user-identifier":"-", "datetime":"29/Apr/2025:06:15:41 +0000", "method": "GET", "request": "/expedite/target/disintermediate", "protocol":"HTTP/1.1", "status":304, "bytes":11362, "referer": "https://www.corporatedeliver.io/transform"}
{"host":"83.122.146.62", "user-identifier":"-", "datetime":"29/Apr/2025:06:15:46 +0000", "method": "GET", "request": "/ubiquitous", "protocol":"HTTP/1.0", "status":304, "bytes":8663, "referer": "https://www.dynamicvortals.com/incubate/interfaces/grow/leverage"}
{"host":"55.206.219.132", "user-identifier":"grimes1800", "datetime":"29/Apr/2025:06:15:51 +0000", "method": "POST", "request": "/strategic/global/exploit", "protocol":"HTTP/1.1", "status":504, "bytes":24205, "referer": "https://www.nationale-markets.net/mesh"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Deploy Vector Agent
&lt;/h2&gt;

&lt;p&gt;Make sure &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt; is installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add vector https://helm.vector.dev
helm repo update

helm install vector vector/vector --namespace vector --create-namespace --values values.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;values.yaml&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Each role is created with the following workloads:
# Agent = DaemonSet
# Aggregator = StatefulSet
# Stateless-Aggregator = Deployment
role: "Agent"

serviceAccount:
  create: false
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::115789992589:role/pod-identity-role-vector
  name: vector-sa
  automountToken: true

containerPorts:
  - containerPort: 80
    name: http

service:
  enabled: true
  type: "ClusterIP"
  ports:
    - port: 80
      name: http

# customConfig -- Override Vector's default configs, if used **all** options need to be specified. This section supports
# using helm templates to populate dynamic values. See Vector's [configuration documentation](https://vector.dev/docs/reference/configuration/)
# for all options.
customConfig:
  data_dir: /vector-data-dir
  api:
    enabled: false
  sources:
    my_eks_cluster_logs:
      type: kubernetes_logs
      exclude_paths_glob_patterns:
        - "/var/log/pods/kube-system_*/**"
  transforms:
    modify:
      type: remap
      inputs:
        - my_eks_cluster_logs
      source: |
        del(.file)
        del(.kubernetes.pod_ip)
        del(.kubernetes.pod_ips)
        del(.kubernetes.pod_owner)
        del(.kubernetes.pod_uid)
        del(.kubernetes.source_type)
        del(.kubernetes.stream)
        del(.kubernetes.node_labels)
        del(.kubernetes.pod_labels)
        del(.kubernetes.pod_node_name)
        del(.kubernetes.namespace_labels)
        del(.kubernetes.container_id)
        del(.kubernetes.container_image_id)
        del(.stream)
        del(.source_type)
        .timestamp = now()
        .message = parse_json!(string!(.message))
        .message.user_identifier = .message."user-identifier"
        del(.message.bytes)
        del(.message.datetime)
        del(.message."user-identifier")
  sinks:
    s3:
      inputs:
        - modify 
      type: aws_s3
      region: ap-northeast-1
      bucket: my-vector-demo
      key_prefix: date=%Y-%m-%d/
      framing:
        method: newline_delimited
      compression: none           
      encoding:
        codec: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check Vector Agent readiness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get all -n vector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see two pods running as daemonset in the vector namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME               READY   STATUS    RESTARTS   AGE
pod/vector-gkd5j   1/1     Running   0          3s
pod/vector-lwj85   1/1     Running   0          3s

NAME                      TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
service/vector            ClusterIP   10.100.2.99   &amp;lt;none&amp;gt;        80/TCP    3s
service/vector-headless   ClusterIP   None          &amp;lt;none&amp;gt;        80/TCP    3s

NAME                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/vector   2         2         2       2            2           &amp;lt;none&amp;gt;          3s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait around 3-5 minutes you will see your log placed in the S3 bucket.&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%2F2m4vjlg7osxjwb7jctyy.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%2F2m4vjlg7osxjwb7jctyy.png" alt=" " width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's deep dive into the three parts of Helm Chart &lt;code&gt;values.yaml&lt;/code&gt; file: &lt;code&gt;customConfig.source, customConfig.transforms, and customConfig.sinks&lt;/code&gt; before forward to the next step.&lt;/p&gt;




&lt;p&gt;Vector provides a lot of observability data sources:&lt;br&gt;
&lt;a href="https://vector.dev/docs/reference/configuration/sources/" rel="noopener noreferrer"&gt;https://vector.dev/docs/reference/configuration/sources/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;kubernetes_logs&lt;/code&gt; (Line 3) data source type in this demonstration. Then ignore all of the application logs in &lt;code&gt;kube-system&lt;/code&gt; (Line 4-5) namespace. We just need our log generator application logs.&lt;/p&gt;

&lt;p&gt;For more detailed configurations for &lt;code&gt;kubernetes_logs&lt;/code&gt; data source type please refer to:&lt;br&gt;
&lt;a href="https://vector.dev/docs/reference/configuration/sources/kubernetes_logs/" rel="noopener noreferrer"&gt;https://vector.dev/docs/reference/configuration/sources/kubernetes_logs/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;customConfig.source&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1  sources:
2    my_eks_cluster_logs:
3      type: kubernetes_logs
4      exclude_paths_glob_patterns:
5        - "/var/log/pods/kube-system_*/**"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;After completing the previous step, the log pattern you obtained will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"file":"/var/log/pods/log-generator_flog-6776c79fc5-r9npr_5eaef748-8dfa-4159-8095-1f072bbe56f7/flog/0.log","kubernetes":{"container_id":"containerd://c9e33cff88b3ddc9d76f78afc9c1def2f90818d490d92e648e4aa72c68c52f6e","container_image":"mingrammer/flog:0.4.3","container_image_id":"docker.io/mingrammer/flog@sha256:44180f8610fab7d4c29ff233a79e19cf28bd425c1737aa59c72c1f66613fdf41","container_name":"flog","namespace_labels":{"app":"flog","kubernetes.io/metadata.name":"log-generator"},"node_labels":{"alpha.eksctl.io/cluster-name":"my-vector-cluster","alpha.eksctl.io/nodegroup-name":"application-ng","beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/instance-type":"t3a.small","beta.kubernetes.io/os":"linux","eks.amazonaws.com/capacityType":"ON_DEMAND","eks.amazonaws.com/nodegroup":"application-ng","eks.amazonaws.com/nodegroup-image":"ami-0c584e04243563b1d","eks.amazonaws.com/sourceLaunchTemplateId":"lt-0de21881415806411","eks.amazonaws.com/sourceLaunchTemplateVersion":"1","failure-domain.beta.kubernetes.io/region":"ap-northeast-1","failure-domain.beta.kubernetes.io/zone":"ap-northeast-1a","k8s.io/cloud-provider-aws":"d856828657925fb2e15850b3e197f9d7","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"ip-192-168-4-74.ap-northeast-1.compute.internal","kubernetes.io/os":"linux","node.kubernetes.io/instance-type":"t3a.small","topology.k8s.aws/zone-id":"apne1-az4","topology.kubernetes.io/region":"ap-northeast-1","topology.kubernetes.io/zone":"ap-northeast-1a"},"pod_ip":"192.168.7.43","pod_ips":["192.168.7.43"],"pod_labels":{"app":"flog","pod-template-hash":"6776c79fc5"},"pod_name":"flog-6776c79fc5-r9npr","pod_namespace":"log-generator","pod_node_name":"ip-192-168-4-74.ap-northeast-1.compute.internal","pod_owner":"ReplicaSet/flog-6776c79fc5","pod_uid":"5eaef748-8dfa-4159-8095-1f072bbe56f7"},"message":"{\"host\":\"192.53.77.232\", \"user-identifier\":\"-\", \"datetime\":\"30/Apr/2025:02:26:18 +0000\", \"method\": \"PUT\", \"request\": \"/web-readiness/networks/interfaces\", \"protocol\":\"HTTP/1.0\", \"status\":416, \"bytes\":10254, \"referer\": \"https://www.humanmatrix.info/evolve/wireless/enhance/engage\"}","source_type":"kubernetes_logs","stream":"stdout","timestamp":"2025-04-30T02:26:23.090690200Z"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to the logs generated by the log generator application itself, you will find that a lot of Kubernetes-related information (e.g., namespace_labels, instance-type, or region) has been added.&lt;br&gt;
Our log generator application log has been added with a lot of &lt;code&gt;\&lt;/code&gt; symbols.&lt;br&gt;&lt;br&gt;
Here we will demonstrate how to remove some information that we don't need, remove &lt;code&gt;\&lt;/code&gt; symbols, and add timestamps to our logs payload.&lt;/p&gt;

&lt;p&gt;Vector provides a feature called &lt;a href="https://vector.dev/docs/reference/vrl/" rel="noopener noreferrer"&gt;Vector Remap Language (VRL)&lt;/a&gt;, which is an expression-oriented language designed for transforming observability data (logs and metrics) in a safe and performant manner.&lt;/p&gt;

&lt;p&gt;You can use &lt;a href="https://playground.vrl.dev/" rel="noopener noreferrer"&gt;VRL Playground&lt;/a&gt; to test your Remap Language with your log payload.&lt;/p&gt;

&lt;p&gt;(1) &lt;code&gt;del()&lt;/code&gt; (Lines 7-21 and 25-27): is used to delete the Key/Value of your log payload.&lt;br&gt;
(2) &lt;code&gt;.timestamp = now()&lt;/code&gt; (Line 22): Add a timestamp to your log payload.&lt;br&gt;
(3) &lt;code&gt;.message = parse_json!(string!(.message))&lt;/code&gt; (Line 23): Convert message string to JSON object, this action will remove the &lt;code&gt;\&lt;/code&gt; symbols at the same time.&lt;br&gt;
(4) &lt;code&gt;.message.user_identifier = .message."user-identifier"&lt;/code&gt; (Line 24): Situations with hyphens often require many exceptions, so we convert them to underscores for representation.&lt;/p&gt;

&lt;p&gt;Here's also the &lt;a href="https://playground.vrl.dev/?state=eyJwcm9ncmFtIjoiZGVsKC5maWxlKVxuZGVsKC5rdWJlcm5ldGVzLnBvZF9pcClcbmRlbCgua3ViZXJuZXRlcy5wb2RfaXBzKVxuZGVsKC5rdWJlcm5ldGVzLnBvZF9vd25lcilcbmRlbCgua3ViZXJuZXRlcy5wb2RfdWlkKVxuZGVsKC5rdWJlcm5ldGVzLnNvdXJjZV90eXBlKVxuZGVsKC5rdWJlcm5ldGVzLnN0cmVhbSlcbmRlbCgua3ViZXJuZXRlcy5ub2RlX2xhYmVscylcbmRlbCgua3ViZXJuZXRlcy5wb2RfbGFiZWxzKVxuZGVsKC5rdWJlcm5ldGVzLnBvZF9ub2RlX25hbWUpXG5kZWwoLmt1YmVybmV0ZXMubmFtZXNwYWNlX2xhYmVscylcbmRlbCgua3ViZXJuZXRlcy5jb250YWluZXJfaWQpXG5kZWwoLmt1YmVybmV0ZXMuY29udGFpbmVyX2ltYWdlX2lkKVxuZGVsKC5zdHJlYW0pXG5kZWwoLnNvdXJjZV90eXBlKVxuLnRpbWVzdGFtcCA9IG5vdygpXG4ubWVzc2FnZSA9IHBhcnNlX2pzb24hKHN0cmluZyEoLm1lc3NhZ2UpKVxuLm1lc3NhZ2UudXNlcl9pZGVudGlmaWVyID0gLm1lc3NhZ2UuXCJ1c2VyLWlkZW50aWZpZXJcIlxuZGVsKC5tZXNzYWdlLmJ5dGVzKVxuZGVsKC5tZXNzYWdlLmRhdGV0aW1lKVxuZGVsKC5tZXNzYWdlLlwidXNlci1pZGVudGlmaWVyXCIpIiwiZXZlbnQiOnsiZmlsZSI6Ii92YXIvbG9nL3BvZHMvbG9nLWdlbmVyYXRvcl9mbG9nLTY3NzZjNzlmYzUtcjlucHJfNWVhZWY3NDgtOGRmYS00MTU5LTgwOTUtMWYwNzJiYmU1NmY3L2Zsb2cvMC5sb2ciLCJrdWJlcm5ldGVzIjp7ImNvbnRhaW5lcl9pZCI6ImNvbnRhaW5lcmQ6Ly9jOWUzM2NmZjg4YjNkZGM5ZDc2Zjc4YWZjOWMxZGVmMmY5MDgxOGQ0OTBkOTJlNjQ4ZTRhYTcyYzY4YzUyZjZlIiwiY29udGFpbmVyX2ltYWdlIjoibWluZ3JhbW1lci9mbG9nOjAuNC4zIiwiY29udGFpbmVyX2ltYWdlX2lkIjoiZG9ja2VyLmlvL21pbmdyYW1tZXIvZmxvZ0BzaGEyNTY6NDQxODBmODYxMGZhYjdkNGMyOWZmMjMzYTc5ZTE5Y2YyOGJkNDI1YzE3MzdhYTU5YzcyYzFmNjY2MTNmZGY0MSIsImNvbnRhaW5lcl9uYW1lIjoiZmxvZyIsIm5hbWVzcGFjZV9sYWJlbHMiOnsiYXBwIjoiZmxvZyIsImt1YmVybmV0ZXMuaW8vbWV0YWRhdGEubmFtZSI6ImxvZy1nZW5lcmF0b3IifSwibm9kZV9sYWJlbHMiOnsiYWxwaGEuZWtzY3RsLmlvL2NsdXN0ZXItbmFtZSI6Im15LXZlY3Rvci1jbHVzdGVyIiwiYWxwaGEuZWtzY3RsLmlvL25vZGVncm91cC1uYW1lIjoiYXBwbGljYXRpb24tbmciLCJiZXRhLmt1YmVybmV0ZXMuaW8vYXJjaCI6ImFtZDY0IiwiYmV0YS5rdWJlcm5ldGVzLmlvL2luc3RhbmNlLXR5cGUiOiJ0M2Euc21hbGwiLCJiZXRhLmt1YmVybmV0ZXMuaW8vb3MiOiJsaW51eCIsImVrcy5hbWF6b25hd3MuY29tL2NhcGFjaXR5VHlwZSI6Ik9OX0RFTUFORCIsImVrcy5hbWF6b25hd3MuY29tL25vZGVncm91cCI6ImFwcGxpY2F0aW9uLW5nIiwiZWtzLmFtYXpvbmF3cy5jb20vbm9kZWdyb3VwLWltYWdlIjoiYW1pLTBjNTg0ZTA0MjQzNTYzYjFkIiwiZWtzLmFtYXpvbmF3cy5jb20vc291cmNlTGF1bmNoVGVtcGxhdGVJZCI6Imx0LTBkZTIxODgxNDE1ODA2NDExIiwiZWtzLmFtYXpvbmF3cy5jb20vc291cmNlTGF1bmNoVGVtcGxhdGVWZXJzaW9uIjoiMSIsImZhaWx1cmUtZG9tYWluLmJldGEua3ViZXJuZXRlcy5pby9yZWdpb24iOiJhcC1ub3J0aGVhc3QtMSIsImZhaWx1cmUtZG9tYWluLmJldGEua3ViZXJuZXRlcy5pby96b25lIjoiYXAtbm9ydGhlYXN0LTFhIiwiazhzLmlvL2Nsb3VkLXByb3ZpZGVyLWF3cyI6ImQ4NTY4Mjg2NTc5MjVmYjJlMTU4NTBiM2UxOTdmOWQ3Iiwia3ViZXJuZXRlcy5pby9hcmNoIjoiYW1kNjQiLCJrdWJlcm5ldGVzLmlvL2hvc3RuYW1lIjoiaXAtMTkyLTE2OC00LTc0LmFwLW5vcnRoZWFzdC0xLmNvbXB1dGUuaW50ZXJuYWwiLCJrdWJlcm5ldGVzLmlvL29zIjoibGludXgiLCJub2RlLmt1YmVybmV0ZXMuaW8vaW5zdGFuY2UtdHlwZSI6InQzYS5zbWFsbCIsInRvcG9sb2d5Lms4cy5hd3Mvem9uZS1pZCI6ImFwbmUxLWF6NCIsInRvcG9sb2d5Lmt1YmVybmV0ZXMuaW8vcmVnaW9uIjoiYXAtbm9ydGhlYXN0LTEiLCJ0b3BvbG9neS5rdWJlcm5ldGVzLmlvL3pvbmUiOiJhcC1ub3J0aGVhc3QtMWEifSwicG9kX2lwIjoiMTkyLjE2OC43LjQzIiwicG9kX2lwcyI6WyIxOTIuMTY4LjcuNDMiXSwicG9kX2xhYmVscyI6eyJhcHAiOiJmbG9nIiwicG9kLXRlbXBsYXRlLWhhc2giOiI2Nzc2Yzc5ZmM1In0sInBvZF9uYW1lIjoiZmxvZy02Nzc2Yzc5ZmM1LXI5bnByIiwicG9kX25hbWVzcGFjZSI6ImxvZy1nZW5lcmF0b3IiLCJwb2Rfbm9kZV9uYW1lIjoiaXAtMTkyLTE2OC00LTc0LmFwLW5vcnRoZWFzdC0xLmNvbXB1dGUuaW50ZXJuYWwiLCJwb2Rfb3duZXIiOiJSZXBsaWNhU2V0L2Zsb2ctNjc3NmM3OWZjNSIsInBvZF91aWQiOiI1ZWFlZjc0OC04ZGZhLTQxNTktODA5NS0xZjA3MmJiZTU2ZjcifSwibWVzc2FnZSI6IntcImhvc3RcIjpcIjE5Mi41My43Ny4yMzJcIiwgXCJ1c2VyLWlkZW50aWZpZXJcIjpcIi1cIiwgXCJkYXRldGltZVwiOlwiMzAvQXByLzIwMjU6MDI6MjY6MTggKzAwMDBcIiwgXCJtZXRob2RcIjogXCJQVVRcIiwgXCJyZXF1ZXN0XCI6IFwiL3dlYi1yZWFkaW5lc3MvbmV0d29ya3MvaW50ZXJmYWNlc1wiLCBcInByb3RvY29sXCI6XCJIVFRQLzEuMFwiLCBcInN0YXR1c1wiOjQxNiwgXCJieXRlc1wiOjEwMjU0LCBcInJlZmVyZXJcIjogXCJodHRwczovL3d3dy5odW1hbm1hdHJpeC5pbmZvL2V2b2x2ZS93aXJlbGVzcy9lbmhhbmNlL2VuZ2FnZVwifSIsInNvdXJjZV90eXBlIjoia3ViZXJuZXRlc19sb2dzIiwic3RyZWFtIjoic3Rkb3V0IiwidGltZXN0YW1wIjoiMjAyNS0wNC0zMFQwMjoyNjoyMy4wOTA2OTAyMDBaIn0sImlzX2pzb25sIjpmYWxzZSwiZXJyb3IiOm51bGx9" rel="noopener noreferrer"&gt;playground&lt;/a&gt; for these transforms. You can experiment with it to better understand the entire Vector Remap Language transformation process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;customConfig.transforms&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1   transforms:
2     modify:
3       type: remap
4       inputs:
5         - my_eks_cluster_logs
6       source: |
7         del(.file)
8         del(.kubernetes.pod_ip)
9         del(.kubernetes.pod_ips)
10        del(.kubernetes.pod_owner)
11        del(.kubernetes.pod_uid)
12        del(.kubernetes.source_type)
13        del(.kubernetes.stream)
14        del(.kubernetes.node_labels)
15        del(.kubernetes.pod_labels)
16        del(.kubernetes.pod_node_name)
17        del(.kubernetes.namespace_labels)
18        del(.kubernetes.container_id)
19        del(.kubernetes.container_image_id)
20        del(.stream)
21        del(.source_type)
22        .timestamp = now()
23        .message = parse_json!(string!(.message))
24        .message.user_identifier = .message."user-identifier"
25        del(.message.bytes)
26        del(.message.datetime)
27        del(.message."user-identifier")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transformed result as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "kubernetes": {
        "container_image": "mingrammer/flog:0.4.3",
        "container_name": "flog",
        "pod_name": "flog-6776c79fc5-r9npr",
        "pod_namespace": "log-generator"
    },
    "message": {
        "host": "192.53.77.232",
        "method": "PUT",
        "protocol": "HTTP/1.0",
        "referer": "https://www.humanmatrix.info/evolve/wireless/enhance/engage",
        "request": "/web-readiness/networks/interfaces",
        "status": 416,
        "user_identifier": "-"
    },
    "timestamp": "2025-04-30T02:51:38.078Z"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Vector provides a variety of destinations to deliver your observability data.&lt;br&gt;
&lt;a href="https://vector.dev/docs/reference/configuration/sinks/" rel="noopener noreferrer"&gt;https://vector.dev/docs/reference/configuration/sinks/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use AWS S3 as our destination in this demonstration.&lt;br&gt;
For more detailed configurations for &lt;code&gt;AWS S3&lt;/code&gt; destination please refer to:&lt;br&gt;
&lt;a href="https://vector.dev/docs/reference/configuration/sinks/aws_s3/" rel="noopener noreferrer"&gt;https://vector.dev/docs/reference/configuration/sinks/aws_s3/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important things to note are these three settings：&lt;br&gt;
(1) Set destination type as &lt;code&gt;aws_s3&lt;/code&gt; (Line 5).&lt;br&gt;
(2) Set &lt;code&gt;region name&lt;/code&gt; and &lt;code&gt;bucket name&lt;/code&gt; (Lines 6-7).&lt;br&gt;
(3) Set encoding codec as &lt;code&gt;JSON&lt;/code&gt; format (Line 13).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;customConfig.sinks&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1   sinks:
2     s3:
3       inputs:
4         - modify 
5       type: aws_s3
6       region: ap-northeast-1
7       bucket: my-vector-demo
8       key_prefix: date=%Y-%m-%d/
9       framing:
10        method: newline_delimited
11      compression: none           
12      encoding:
13        codec: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Crawler logs from AWS S3 to AWS Glue - Data Catalog Tables
&lt;/h2&gt;

&lt;p&gt;Move to AWS Glue console and click &lt;code&gt;Add tables using crawler&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;Create a database:&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%2F8haeh69jhjepnafqik7e.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%2F8haeh69jhjepnafqik7e.png" alt=" " width="800" height="125"&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%2Fwvbej6dw90z32ddjxv1y.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%2Fwvbej6dw90z32ddjxv1y.png" alt=" " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Move to Tables and click &lt;code&gt;Add tables using crawler&lt;/code&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%2Fljjeltwdz38m1n93vmr5.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%2Fljjeltwdz38m1n93vmr5.png" alt=" " width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the crawler properties:&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%2F9pctl7th4vi9kbb8vj7n.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%2F9pctl7th4vi9kbb8vj7n.png" alt=" " width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a data source:&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%2F5ka9dhc0fddj04quve0k.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%2F5ka9dhc0fddj04quve0k.png" alt=" " width="800" height="402"&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%2F66w6ceqd3ez39p2z04cg.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%2F66w6ceqd3ez39p2z04cg.png" alt=" " width="800" height="1075"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a Custom classifiers:&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%2Febbgvqa5o6uyq47ujy0s.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%2Febbgvqa5o6uyq47ujy0s.png" alt=" " width="800" height="195"&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%2Fv06ddz8psuyljiy5rrgt.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%2Fv06ddz8psuyljiy5rrgt.png" alt=" " width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data source and Custom classifiers are all set, move to the next step.&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%2Fx0zanng5a1j9zfm5pqp5.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%2Fx0zanng5a1j9zfm5pqp5.png" alt=" " width="800" height="590"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select an IAM Role:&lt;br&gt;
You can click the `Create new IAM Role' button to create a new IAM Role if you don't have an IAM Role.&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%2Fwiliezpi6gsw9lkeab8u.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%2Fwiliezpi6gsw9lkeab8u.png" alt=" " width="800" height="469"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set output and scheduling:&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%2Fjhyq8ureosrltkzzmdev.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%2Fjhyq8ureosrltkzzmdev.png" alt=" " width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Double-check all of the configurations then click &lt;code&gt;Create crawler&lt;/code&gt; button:&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%2Flaqcyz4cbewxrdkitzqe.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%2Flaqcyz4cbewxrdkitzqe.png" alt=" " width="800" height="525"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click `Run crawler' button:&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%2Frx38jy57m7jbsci7q7a2.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%2Frx38jy57m7jbsci7q7a2.png" alt=" " width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for around 3-5 minutes till the Crawler job is completed.&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%2Fb6v8xq73mfd5ltgnq0eg.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%2Fb6v8xq73mfd5ltgnq0eg.png" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to Table overview. You can see table schema has been created automatically.&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%2Fddt81adoy0x7idcsb8ok.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%2Fddt81adoy0x7idcsb8ok.png" alt=" " width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Query log via Amazon Athena
&lt;/h2&gt;

&lt;p&gt;Let's move to Amazon Athena console to query our application logs.&lt;/p&gt;

&lt;p&gt;Copy and paste the below SQL statement to Athena SQL editor then run this query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT timestamp,
    kubernetes.container_image,
    kubernetes.container_name,
    kubernetes.pod_name,
    kubernetes.pod_namespace,
    message.host,
    message.method,
    message.protocol,
    message.referer,
    message.request,
    message.status,
    message.user_identifier,
    date
FROM "AwsDataCatalog"."eks_log_db"."my_vector_demo"
ORDER BY timestamp DESC
LIMIT 500;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the query is completed, the 500 logs are sorted by timestamp in descending order and every JSON Key/Value also maps to an independent column:&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%2Fz3jbsx1ryozhmuqgtigg.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%2Fz3jbsx1ryozhmuqgtigg.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can further set some conditions to find the logs you want, such as the host's IP address or the request's URI.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Cleanup
&lt;/h2&gt;

&lt;p&gt;Use eksctl to delete all of the EKS cluster stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl delete cluster --name my-vector-cluster --region ap-northeast-1 --disable-nodegroup-eviction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Conclusion
&lt;/h2&gt;

&lt;p&gt;In this demonstration, we showed how to:&lt;br&gt;
Use Vector, an open-source tool, to collect Application Logs on Amazon Elastic Kubernetes Service (Amazon EKS).&lt;br&gt;
Store the Application Logs using Amazon Simple Storage Service (Amazon S3) to meet long-term retention requirements.&lt;br&gt;
Finally, analyze the Application Logs through the powerful search capabilities brought by the integration of AWS Glue and Amazon Athena.&lt;/p&gt;

&lt;p&gt;If you are looking for a solution to collect Application Logs on Kubernetes, you might consider using Vector.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>observability</category>
      <category>monitoring</category>
      <category>eks</category>
    </item>
  </channel>
</rss>
