Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Version published after converting to the new editor

Note
titleNote!

You need to have a proper EKS cluster setup in order to proceed with these steps. Refer to Set Up Kubernetes Cluster - AWS (4.1) to create the EKS cluster first.

By default Usage Engine deployed in Kubernetes outputs logging to disk and console output. If persistent disk storage is enabled, the logs end up on the mounted shared disk. But persistent disk is not always the desired log target, especially in a cloud environment where persistent data is typically accessed through services and APIs rather than as files. The console logs can be accessed through the "kubectl logs" command or from a Kubernetes dashboard. The buffer for storing the Kubernetes console logs is stored in memory only though and thus will be lost when a Pod terminates.

To get a production ready log configuration you can use tools from the Kubernetes ecosystem and AWS CloudWatch. In this guide we show you how to set up:

  • Fluent-bit for log collection and log forwarding
  • Elasticsearch for log storage
  • Kibana for log visualization
  • AWS CloudWatch for monitoring

Thesetools give you powerful and flexible log collection, storage, monitoring and visualization. The Elasticsearch database storage also provides powerful tools to perform analytics on the log data. The AWS CloudWatch is a monitoring service built for DevOps engineers, developers, site reliability engineers (SREs), IT managers, and product owners. This guide doesn't describe these tools' functionality in details as it is outside the scope of this guide.

Prerequisite

Before setting up log collection, make sure your Usage Engine Private Edition was installed with JSON formatted logging enabled.


Code Block
linenumberstrue
log:
  # Format can be "json" or "raw". Default is "raw"
  format: json


Setup AWS IAM OIDC Provider

To use AWS Identity and Access Management (IAM) roles for service accounts, an IAM OIDC provider must exist for your cluster's OIDC issuer URL. Prior to creating AWS policy and role, user needs to setup Identity Provider using EKS cluster's OpenID Connect Provider URL.

  1. Login to AWS Management Console, go to EKS > Clusters > Your Cluster Name
  2. On Overview tab, section Details, click on OpenID Connect Provider URL to copy URL to clipboard
  3. Go to IAM > Identity Providers
  4. Add an Identity Provider and select OpenID Connect
  5. Paste the copied URL as Provider URL 
  6. Key in "sts.amazonaws.com" as Audience
  7. Click Add Provider and proceed to complete the Identity Providers creation 

Setup AWS IAM Policy and Role

In order for the Fluent-bit to send logs to AWS CloudWatch, user needs to setup AWS access policy to access the AWS CloudWatch and attach this policy to an AWS Role. 

  1. Login to AWS Management Console, go to IAM > Policies
  2. Create new policy using Policy Editor's JSON Tab. Enter permission statement in JSON format


    Code Block
    linenumberstrue
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "logs:DescribeLogGroups",
                    "logs:DescribeLogStreams",
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }


  3. Click Next and proceed to create the policy
  4. Back to IAM Dashboard. Go to IAM > Roles
  5. Create new role and select Web Identity
  6. Choose the OpenID Connect Provider Id as Identity Provider
  7. Click Next and proceed to create the role

Once the new role created, user needs to edit the role's trust relationship to associate it to the Fluent-bit's Service Account.

  1. Go to IAM > Roles > Your Role Name
  2. On Trust relationship tab, edit trust policy
  3. Edit "StringEquals" field to use Fluent-bit's namespace and Service Account Name


    Code Block
    linenumberstrue
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "Federated": "arn:aws:iam::211006581866:oidc-provider/oidc.eks.ap-southeast-2.amazonaws.com/id/360F8C7227656FC5627D5DA70F181583"
                },
                "Action": "sts:AssumeRoleWithWebIdentity",
                "Condition": {
                    "StringEquals": {
                        "oidc.eks.ap-southeast-2.amazonaws.com/id/360F8C7227656FC5627D5DA70F181583:sub": "system:serviceaccount:<Fluent-bit namespace>:<fluent-bit Service Account Name>"
                    }
                }
            }
        ]
    }
      


Install Fluent-bit

To stream containers logs to CloudWatch Logs, install AWS for Fluent Bit using these steps:

  1. Create a namespace called amazon-cloudwatch.


    Code Block
    linenumberstrue
    kubectl create namespace amazon-cloudwatch


  2. Create a ConfigMap called fluent-bit-cluster-info. Replace my-cluster-name and my-cluster-region with your cluster's name and Region.


    Code Block
    linenumberstrue
    ClusterName=<my-cluster-name>
    RegionName=<my-cluster-region>
    FluentBitHttpPort='2020'
    FluentBitReadFromHead='Off'
    [[ ${FluentBitReadFromHead} = 'On' ]] && FluentBitReadFromTail='Off'|| FluentBitReadFromTail='On'
    [[ -z ${FluentBitHttpPort} ]] && FluentBitHttpServer='Off' || FluentBitHttpServer='On'
    kubectl create configmap fluent-bit-cluster-info \
    --from-literal=cluster.name=${ClusterName} \
    --from-literal=http.server=${FluentBitHttpServer} \
    --from-literal=http.port=${FluentBitHttpPort} \
    --from-literal=read.head=${FluentBitReadFromHead} \
    --from-literal=read.tail=${FluentBitReadFromTail} \
    --from-literal=logs.region=${RegionName} -n amazon-cloudwatch


  3. Deploy the Fluent Bit DaemonSet to the cluster.


    Code Block
    linenumberstrue
    kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/fluent-bit/fluent-bit.yaml


  4. Associate the IAM role to cloudwatch-agent and fluent-bit service accounts. Replace ACCOUNT_ID and IAM_ROLE_NAME with AWS Account ID and the IAM role used for service accounts.


    Code Block
    linenumberstrue
    kubectl annotate serviceaccounts fluent-bit -n amazon-cloudwatch "eks.amazonaws.com/role-arn=arn:aws:iam::ACCOUNT_ID:role/IAM_ROLE_NAME"


  5. Go to CloudWatch > View logs. Verify the following log groups are created.


    Code Block
    linenumberstrue
    /aws/containerinsights/Your Cluster Name/application
    /aws/containerinsights/Your Cluster Name/dataplane
    /aws/containerinsights/Your Cluster Name/host


  6. For each log group, verify there are log streams available on Log stream Tab


Install Elastic Search

Elastic search will be installed to the same namespace as Fluent-bit, i.e., amazon-cloudwatch. 

  1. Add Elastic Search repository to Helm and update repository to retrieve the latest version


    Code Block
    linenumberstrue
    helm repo add elastic https://helm.elastic.co
    helm repo update


  2. Install Elastic Search. 

    Note
    titleNote!

    For simplicity this example installs Elasticsearch without persistent storage. Refer to Elasticsearch Helm chart documentation for help to enable persistent storage:

    https://github.com/elastic/helm-charts/tree/master/elasticsearch


    Code Block
    linenumberstrue
    helm install elasticsearch elastic/elasticsearch -n amazon-cloudwatch --set=persistence.enabled=false


Install Kibana

Kibana will be installed to the same namespace as Fluent-bit, i.e., amazon-cloudwatch. 

  1. Download the Kibana helm chart and unpack it in local directory.

    Code Block
    linenumberstrue
    helm fetch elastic/kibana --untar


  2. Change directory to kibana. Edit values.yaml. Add service annotation to create Internet-facing, Network type Load Balancer .


    Code Block
    linenumberstrue
    service:
      type: ClusterIP
      loadBalancerIP: ""
      port: 5601
      nodePort: ""
      labels: {}
      annotations:
        service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing


  3. Install Kibana by path to an unpacked local directory


    Code Block
    linenumberstrue
    helm install kibana kibana -n amazon-cloudwatch --set=service.type=LoadBalancer --set=service.port=80


Configure Fluent-bit to send logs to Elastic Search 

These are additional steps to configure fluent-bit ConfigMap named fluent-bit-config.

  1. Get service name of Elastic Search pods. This service name is the value set to Host in [OUTPUT] directive. 


    Code Block
    linenumberstrue
    kubectl get svc -n amazon-cloudwatch


  2. Get username and password credential for Elastic X-Pack access. The decrypted username and password are the value set to HTTP_User and HTTP_Passwd in [OUTPUT] directive.


    Code Block
    linenumberstrue
    kubectl get secrets --namespace=amazon-cloudwatch elasticsearch-master-credentials -ojsonpath='{.data.username}' | base64 -d
    kubectl get secrets --namespace=amazon-cloudwatch elasticsearch-master-credentials -ojsonpath='{.data.password}' | base64 -d


  3. Download fluent-bit deamonset yaml file in local directory


    Code Block
    linenumberstrue
    curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/fluent-bit/fluent-bit.yaml > fluent-bit.yaml


  4. Edit fluent-bit.yaml. Go to ConfigMap named fluent-bit-config. For each config file, add output directive to send logs to Elastic Search


    Code Block
    titleapplication-log.conf
    linenumberstrue
        [OUTPUT]
            Name                es
            Match               application.*
            Host                elasticsearch-master
            tls                 on
            tls.verify          off
            HTTP_User           elastic
            HTTP_Passwd         DbrfdbnzCNYympQZ
            Suppress_Type_Name  On
            Index               fluentbit.app



  5. Code Block
    titledataplane-log.conf
    linenumberstrue
        [OUTPUT]
            Name                es
            Match               dataplane.*
            Host                elasticsearch-master
            tls                 on
            tls.verify          off
            HTTP_User           elastic
            HTTP_Passwd         DbrfdbnzCNYympQZ
            Suppress_Type_Name  On
            Index               fluentbit.dataplane



  6. Code Block
    titlehost-log.conf
    linenumberstrue
        [OUTPUT]
            Name                es
            Match               host.*
            Host                elasticsearch-master
            tls                 on
            tls.verify          off
            HTTP_User           elastic
            HTTP_Passwd         DbrfdbnzCNYympQZ
            Suppress_Type_Name  On
            Index               fluentbit.host


  7. Delete existing fluent-bit pods, config map.


    Code Block
    linenumberstrue
    kubectl delete -f fluent-bit.yaml


  8. Install and apply new configuration to fluent-bit pods, config map  


    Code Block
    linenumberstrue
    kubectl apply -f fluent-bit.yaml


  9. Re-associate the IAM role to cloudwatch-agent and fluent-bit service accounts. Replace ACCOUNT_ID and IAM_ROLE_NAME with AWS Account ID and the IAM role used for service accounts.


    Code Block
    linenumberstrue
    kubectl annotate serviceaccounts fluent-bit -n amazon-cloudwatch "eks.amazonaws.com/role-arn=arn:aws:iam::ACCOUNT_ID:role/IAM_ROLE_NAME"


  10. Verify every Fluent-bit pod's log. Should not see any error or exception if connection to Elastic Search is established successfully.


    Code Block
    linenumberstrue
    kubectl logs <fluent-bit pod name> -n amazon-cloudwatch


...

  1. Retrieve the public access hostname of the Kibana dashboard.


    Code Block
    linenumberstrue
    kubectl get service -n amazon-cloudwatch kibana-kibana -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'


  2. Login to Kibana dashboard web UI with username password same as HTTP_User and HTTP_Passwd configured in previous section
  3. Go to Management > Stack Management > Index Management. Create the Index Template with Index Pattern matching the indexes configured in previous sectionImage Modified
  4. If Fluent-bit connection to Elastic Search established successfully, the Indices is created automatically  Image Modified
  5. Go to Management > Stack Management > Kibana. Create Data view matching the index patternImage Modified
  6. Go to Analytics > Discover to search for logs belong to each index pattern respectively. Image Modified
  7. User can filter logs using KQL syntax. For instance, enter "kubernetes.pod_name:platform-0" in the KQL filter input fieldImage Modified
  8. Log record in json format is parsed into fields


    Code Block
    {
      "_p": [
        "F"
      ],
      "_p.keyword": [
        "F"
      ],
      "@timestamp": [
        "2024-02-21T09:14:49.079Z"
      ],
      "kubernetes.container_hash": [
        "ghcr.io/digitalroute-public/usage-engine-private-edition@sha256:fceb32e07cfae86db58d9a83328e4539eb5f42455cd6a0463e9ac955b3642848"
      ],
      "kubernetes.container_hash.keyword": [
        "ghcr.io/digitalroute-public/usage-engine-private-edition@sha256:fceb32e07cfae86db58d9a83328e4539eb5f42455cd6a0463e9ac955b3642848"
      ],
      "kubernetes.container_image": [
        "ghcr.io/digitalroute-public/usage-engine-private-edition:4.0.0-operator"
      ],
      "kubernetes.container_image.keyword": [
        "ghcr.io/digitalroute-public/usage-engine-private-edition:4.0.0-operator"
      ],
      "kubernetes.container_name": [
        "manager"
      ],
      "kubernetes.container_name.keyword": [
        "manager"
      ],
      "kubernetes.docker_id": [
        "9af8ba62db2aacbb39435ed8894bc078013ea1126a561a85a1d486ee8e12367d"
      ],
      "kubernetes.docker_id.keyword": [
        "9af8ba62db2aacbb39435ed8894bc078013ea1126a561a85a1d486ee8e12367d"
      ],
      "kubernetes.host": [
        "ip-192-168-34-51.ap-southeast-2.compute.internal"
      ],
      "kubernetes.host.keyword": [
        "ip-192-168-34-51.ap-southeast-2.compute.internal"
      ],
      "kubernetes.namespace_name": [
        "uepe"
      ],
      "kubernetes.namespace_name.keyword": [
        "uepe"
      ],
      "kubernetes.pod_id": [
        "5a911c45-d2b0-4f53-b474-ae8aee304d4a"
      ],
      "kubernetes.pod_id.keyword": [
        "5a911c45-d2b0-4f53-b474-ae8aee304d4a"
      ],
      "kubernetes.pod_name": [
        "uepe-operator-controller-manager-6fdc476cb5-9282q"
      ],
      "kubernetes.pod_name.keyword": [
        "uepe-operator-controller-manager-6fdc476cb5-9282q"
      ],
      "log": [
        "{\"level\":\"info\",\"ts\":\"2024-02-21T09:14:49Z\",\"logger\":\"controllers.ECDeployment\",\"msg\":\"Reconciling\",\"ECDeployment\":\"uepe/http2\"}"
      ],
      "log_processed.ECDeployment": [
        "uepe/http2"
      ],
      "log_processed.ECDeployment.keyword": [
        "uepe/http2"
      ],
      "log_processed.level": [
        "info"
      ],
      "log_processed.level.keyword": [
        "info"
      ],
      "log_processed.logger": [
        "controllers.ECDeployment"
      ],
      "log_processed.logger.keyword": [
        "controllers.ECDeployment"
      ],
      "log_processed.msg": [
        "Reconciling"
      ],
      "log_processed.msg.keyword": [
        "Reconciling"
      ],
      "log_processed.ts": [
        "2024-02-21T09:14:49.000Z"
      ],
      "log.keyword": [
        "{\"level\":\"info\",\"ts\":\"2024-02-21T09:14:49Z\",\"logger\":\"controllers.ECDeployment\",\"msg\":\"Reconciling\",\"ECDeployment\":\"uepe/http2\"}"
      ],
      "stream": [
        "stderr"
      ],
      "stream.keyword": [
        "stderr"
      ],
      "time": [
        "2024-02-21T09:14:49.079Z"
      ],
      "_id": "ijvyyo0B9xu2H_IDTAqi",
      "_index": "fluentbit.app",
      "_score": null
    }


...