<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CloudWatch &#8211; Blog of Kliment Andreev &#8211; A place so I won&#039;t forget things</title>
	<atom:link href="https://blog.andreev.it/tag/cloudwatch/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.andreev.it</link>
	<description></description>
	<lastBuildDate>Tue, 04 Oct 2022 13:39:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>AWS: EKS monitoring and logging</title>
		<link>https://blog.andreev.it/2022/10/aws-eks-monitoring-and-logging/</link>
					<comments>https://blog.andreev.it/2022/10/aws-eks-monitoring-and-logging/#respond</comments>
		
		<dc:creator><![CDATA[Kliment Andreev]]></dc:creator>
		<pubDate>Mon, 03 Oct 2022 23:09:44 +0000</pubDate>
				<category><![CDATA[AWS]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[CloudWatch]]></category>
		<category><![CDATA[EKS]]></category>
		<category><![CDATA[fluentbit]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[monitoring]]></category>
		<category><![CDATA[prometheus]]></category>
		<guid isPermaLink="false">https://blog.andreev.it/?p=9214</guid>

					<description><![CDATA[In this post I&#8217;ll explain several things related to EKS monitoring and logging. &#8211;&#8230;]]></description>
										<content:encoded><![CDATA[<div id="bsf_rt_marker"></div><p>In this post I&#8217;ll explain several things related to EKS monitoring and logging. </p>
<ol>
&#8211; How to create an EKS cluster<br />
&#8211; Enable the EKS control plane logs and send them to CloudWatch<br />
&#8211; Send these logs from CloudWatch to OpenSearch cluster<br />
&#8211; Install Container Insights and FluentBit and send logs to CloudWatch<br />
&#8211; Install Prometheus and Grafana to monitor and visualize EKS cluster metrics<br />
&#8211; WordPress and CloudWatch log group
</ol>
<p>In order to do that, we&#8217;ll need the following CLI tools. </p>
<ol>
&#8211; eksctl<br />
&#8211; kubectl<br />
&#8211; helm<br />
&#8211; aws cli</ol>
<p>You can easily find how to install and configure these tools for various OSes. </p>
<h1>Create the EKS cluster</h1>
<p>I&#8217;ll create a managed cluster called <strong>eksWordPress </strong>in <strong>us-east-2</strong> region with <strong>two </strong><strong>t3.medium</strong> nodes. </p>
<pre class="brush: bash; title: ; notranslate">
eksctl create cluster --name eksWordPress --region us-east-2 --instance-types t3.medium --nodes 2 --managed --version 1.22
</pre>
<p>If you get an error that the last supported version is 1.21, update eksctl tool. The cluster creation took about 20 mins for me. </p>
<h1>Send EKS logs to CloudWatch</h1>
<p>Once the cluster was created and up and running, enabling the EKS control plane logs is easy. There are 5 log types (API server, Audit, Authenticator, Controller Manager and Scheduler logs). The logged info is a lot, so it&#8217;s up to you what you want to log. There is no way to choose what to log, e.g. info, warning, errors. Everything is logged. To enable logging from the console, go to the EKS cluster, select it, click the <strong>Logging</strong> tab and then click on the <strong>Manage logging</strong> button.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-01.png"><img fetchpriority="high" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-1024x278.png" alt="" width="1024" height="278" class="aligncenter size-large wp-image-9230" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-1024x278.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-300x81.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-768x208.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-1536x416.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-2048x555.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-1920x521.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-1170x317.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-01-585x159.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
If you want to do it from a CLI, type this command and specify what types of logs you want sent to CloudWatch. Specify the region and the cluster name.</p>
<pre class="brush: bash; title: ; notranslate">
aws eks update-cluster-config \
    --region &lt;REGION&gt; \
    --name &lt;CLUSTER_NAME&gt; \
    --logging &#039;{&quot;clusterLogging&quot;:&#x5B;{&quot;types&quot;:&#x5B;&quot;api&quot;,&quot;audit&quot;,&quot;authenticator&quot;,&quot;controllerManager&quot;,&quot;scheduler&quot;],&quot;enabled&quot;:true}]}&#039;
</pre>
<p>In addition, because we provisioned the cluster with the <strong>eksctl</strong> tool, we can also enable the logs using <strong>eksctl</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
eksctl utils update-cluster-logging --enable-types all --cluster &lt;CLUSTER_NAME&gt; --approve
</pre>
<p>Or for certain types, use&#8230; </p>
<pre class="brush: bash; title: ; notranslate">
eksctl utils update-cluster-logging --enable-types &lt;LOG_TYPE&gt; --cluster &lt;CLUSTER_NAME&gt; --approve
</pre>
<p>You can use the same types as in the AWS CLI command above (api, audit, scheduler&#8230;).<br />
If you go to CloudWatch and then the <strong>Log groups</strong>, you&#8217;ll see the log group with the name of the EKS cluster (<em>/aws/eks/eksWordPress/cluster</em>).<br />
Make sure you change the retention from <strong>Never</strong> to some value. You probably don&#8217;t want to keep these logs indefinitely. If you look at the logs streams, you&#8217;ll see that there is a lot of info there. Most of the stuff is useless. </p>
<h1>Send the logs to OpenSearch cluster</h1>
<p>Let&#8217;s create a public OpenSearch cluster with anonymous access that only you can access. Replace the IP at the end of the statement with your IP address. It takes less than 10 mins for the OpenSearch cluster to be provisioned. </p>
<pre class="brush: bash; title: ; notranslate">
aws opensearch create-domain --domain-name oswordpress --engine-version OpenSearch_1.3 \
    --auto-tune-options DesiredState=&quot;ENABLED&quot; --cluster-config InstanceType=t3.small.search,InstanceCount=2 \
    --ebs-options EBSEnabled=true,VolumeType=gp3,VolumeSize=10,Iops=3000 \
    --access-policies &#039;{&quot;Version&quot;: &quot;2012-10-17&quot;, &quot;Statement&quot;: &#x5B;{&quot;Action&quot;: &quot;es:*&quot;, &quot;Principal&quot;:&quot;*&quot;,&quot;Effect&quot;: &quot;Allow&quot;, &quot;Condition&quot;: {&quot;IpAddress&quot;:{&quot;aws:SourceIp&quot;:&#x5B;&quot;2.18.2.19/32&quot;]}}}]}&#039;
</pre>
<p>Once the cluster is provisioned you can get the public URL with:</p>
<pre class="brush: bash; title: ; notranslate">
echo `aws es describe-elasticsearch-domain --domain-name oswordpress --output text --query &quot;DomainStatus.Endpoint&quot;`\\_dashboards
</pre>
<p>You can also get the dashboard URL from the cluster settings as well.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-02.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-1024x269.png" alt="" width="1024" height="269" class="aligncenter size-large wp-image-9240" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-1024x269.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-300x79.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-768x201.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-1536x403.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-2048x537.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-1920x504.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-1170x307.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-02-585x153.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
Create the following IAM policy. Save the policy below as <strong>policy-file.json</strong> but change the <strong>account_no</strong> in line 9 to match your AWS account.</p>
<pre class="brush: xml; highlight: [9]; title: ; notranslate">
{
    &quot;Version&quot;: &quot;2012-10-17&quot;,
    &quot;Statement&quot;: &#x5B;
        {
            &quot;Action&quot;: &#x5B;
                &quot;es:*&quot;
            ],
            &quot;Effect&quot;: &quot;Allow&quot;,
            &quot;Resource&quot;: &quot;arn:aws:es:us-east-2:&lt;account_no&gt;:domain/oswordpress/*&quot;
        }
    ]
}
</pre>
<p>And then create the IAM policy.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam create-policy --policy-name polOpenSearch --policy-document file://policy-file.json
</pre>
<p>Create the role. Save the policy below as <strong>policy-trust.json</strong>.</p>
<pre class="brush: xml; title: ; notranslate">
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: &#x5B;
    {
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Principal&quot;: {
        &quot;Service&quot;: &quot;lambda.amazonaws.com&quot;
      },
      &quot;Action&quot;: &quot;sts:AssumeRole&quot;
    }
  ]
}
</pre>
<p>And then create the role.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam create-role --role-name rolOpenSearch --assume-role-policy file://policy-trust.json
</pre>
<p>Finally, attach the policy to the role.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam put-role-policy --role-name rolOpenSearch --policy-name polOpenSearch --policy-document file://policy-file.json 
</pre>
<p>Go to <strong>CloudWatch</strong>, select the <strong>Log group</strong>, from the <strong>Actions</strong> button select <strong>Subscription filters</strong> and then <strong>Create Amazon OpenSearch service subscription filter</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-03.png"><img decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-1024x355.png" alt="" width="1024" height="355" class="aligncenter size-large wp-image-9242" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-1024x355.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-300x104.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-768x266.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-1536x533.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-2048x711.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-1920x666.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-1170x406.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-03-585x203.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
Choose the OpenSearch cluster that we created, the log format is <strong>JSON</strong>, subscription filter pattern is <strong>&#8221; &#8220;</strong> for all events and type <strong>all</strong> subscription filter name or whatever you want to name this pattern. Click <strong>Start streaming</strong> button.<br />
Now, go to OpenSearch dashboard and from the hamburger menu in the upper left corner, click on <strong>Visualize</strong>. In the middle of the screen, you&#8217;ll be prompted to create an index pattern. Type <strong>cwl*</strong> and click <strong>Next step</strong>.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-04.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-1024x438.png" alt="" width="1024" height="438" class="aligncenter size-large wp-image-9249" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-1024x438.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-300x128.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-768x329.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-1536x657.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-2048x877.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-1920x822.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-1170x501.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-04-585x250.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
Select <strong>@timestamp</strong> from the drop down menu and click on <strong>Create index pattern</strong>. You&#8217;ll see the fields and the index.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-05.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-1024x659.png" alt="" width="1024" height="659" class="aligncenter size-large wp-image-9251" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-1024x659.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-300x193.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-768x494.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-1536x989.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-2048x1319.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-1920x1236.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-1170x753.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-05-585x377.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
Click on the <strong>Discover</strong> from the hamburger menu and you&#8217;ll see your data there. You can use queries to search your data, but that&#8217;s out of the scope of this post.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/09/P160-06.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-1024x400.png" alt="" width="1024" height="400" class="aligncenter size-large wp-image-9252" srcset="https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-1024x400.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-300x117.png 300w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-768x300.png 768w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-1536x600.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-2048x800.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-1920x750.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-1170x457.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/09/P160-06-585x228.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Container Insights and FluentBit</h1>
<p>Container Insights is a CloudWatch agent that we&#8217;ll install on the EKS cluster. It will collect all kinds of metrics and then FluentBit as a log forwarder will ship those logs to CloudWatch. See this link for more <a href="https://aws.amazon.com/blogs/containers/fluent-bit-integration-in-cloudwatch-container-insights-for-eks/" rel="noopener" target="_blank">info</a>.<br />
Let&#8217;s do the prerequisites work first.<br />
Get the nodes. Type the first line only, the rest is my output.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
kubectl get nodes                                                                                                                                                               
NAME                                           STATUS   ROLES    AGE     VERSION
ip-192-168-56-250.us-east-2.compute.internal   Ready    &lt;none&gt;   3h39m   v1.22.12-eks-ba74326
ip-192-168-66-251.us-east-2.compute.internal   Ready    &lt;none&gt;   3h39m   v1.22.12-eks-ba74326
</pre>
<p>Get the instance ID from any of the instances, it doesn&#8217;t matter. Replace the name accordingly after <strong>Values=</strong>.</p>
<pre class="brush: bash; highlight: [1,2]; title: ; notranslate">
aws ec2 describe-instances --filters &#039;Name=private-dns-name,Values=ip-192-168-56-250.us-east-2.compute.internal&#039; \
    --output text --query &#039;Reservations&#x5B;*].Instances&#x5B;*].InstanceId&#039;
i-05adaa0a823a8549a
</pre>
<p>Once you have the instance ID of any node, get the Arn of the IAM role that&#8217;s the attached to that node.</p>
<pre class="brush: bash; highlight: [1,5]; title: ; notranslate">
aws ec2 describe-instances --region us-east-2 --instance-ids i-05adaa0a823a8549a --query &#039;Reservations&#x5B;*].Instances&#x5B;*].IamInstanceProfile.Id&#039;
&#x5B;
    &#x5B;
        &quot;AIPAXFRN6SYD75I5N4BUN&quot;
    ]
]
</pre>
<p>Get the role name. Replace the ID (<strong>AIPAX</strong>&#8230;) with your value above.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
aws iam list-instance-profiles --query &#039;InstanceProfiles&#x5B;?InstanceProfileId==`AIPAXFRN6SYD75I5N4BUN`].Roles&#x5B;*].RoleName&#039; 
&#x5B;
    &#x5B;
        &quot;eksctl-eksWordPress-nodegroup-ng-NodeInstanceRole-LWJZESQ468Y2&quot;
    ]
]
</pre>
<p>We want to add a policy that allows nodes to write to CloudWatch logs group. Replace the <strong>&#8211;role-name </strong>with the value that you got above.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy --role-name eksctl-eksWordPress-nodegroup-ng-NodeInstanceRole-LWJZESQ468Y2
</pre>
<pre class="brush: bash; title: ; notranslate">
oidc_id=$(aws eks describe-cluster --name eksWordPress --query &quot;cluster.identity.oidc.issuer&quot; --output text | cut -d &#039;/&#039; -f 5)
</pre>
<p>Type this line and see if there is any output. If no output, execute the command after. If yes-output, then do nothing.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam list-open-id-connect-providers | grep $oidc_id
</pre>
<p>If no output, type this.</p>
<pre class="brush: bash; title: ; notranslate">
eksctl utils associate-iam-oidc-provider --cluster eksWordPress --approve
</pre>
<p>Then install CloudWatch Container Insights and FluentBit. Change the <strong>CLUSTER_NAME</strong> and <strong>REGION</strong> in lines 1 and 2.</p>
<pre class="brush: bash; highlight: [1,2]; title: ; notranslate">
ClusterName=&lt;CLUSTER_NAME&gt;
RegionName=&lt;REGION&gt;
FluentBitHttpPort=&#039;2020&#039;
FluentBitReadFromHead=&#039;Off&#039;
&#x5B;&#x5B; ${FluentBitReadFromHead} = &#039;On&#039; ]] &amp;&amp; FluentBitReadFromTail=&#039;Off&#039;|| FluentBitReadFromTail=&#039;On&#039;
&#x5B;&#x5B; -z ${FluentBitHttpPort} ]] &amp;&amp; FluentBitHttpServer=&#039;Off&#039; || FluentBitHttpServer=&#039;On&#039;
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed &#039;s/{{cluster_name}}/&#039;${ClusterName}&#039;/;s/{{region_name}}/&#039;${RegionName}&#039;/;s/{{http_server_toggle}}/&quot;&#039;${FluentBitHttpServer}&#039;&quot;/;s/{{http_server_port}}/&quot;&#039;${FluentBitHttpPort}&#039;&quot;/;s/{{read_from_head}}/&quot;&#039;${FluentBitReadFromHead}&#039;&quot;/;s/{{read_from_tail}}/&quot;&#039;${FluentBitReadFromTail}&#039;&quot;/&#039; | kubectl apply -f - 
</pre>
<p>Download a config map and edit it the file called <em>cwagent-configmap.yaml</em>.</p>
<pre class="brush: bash; title: ; notranslate">
curl -O https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/cwagent/cwagent-configmap.yaml
</pre>
<p>In line 11, change the variable so it points to your cluster. In my case it looks like this.</p>
<pre class="brush: bash; title: ; notranslate">
&quot;cluster_name&quot;: &quot;{{eksWordPress}}&quot;,
</pre>
<p>Save the changes and apply the config.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl apply -f cwagent-configmap.yaml
</pre>
<p>Then deploy it as a DaemonSet.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl apply -f https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/cwagent/cwagent-daemonset.yaml
</pre>
<p>Verify that it&#8217;s running. Type the first line only. The rest is my output.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
kubectl get pods -n amazon-cloudwatch
NAME                     READY   STATUS    RESTARTS   AGE
cloudwatch-agent-dfkzv   1/1     Running   0          18m
cloudwatch-agent-nfnf7   1/1     Running   0          18m
fluent-bit-8vd2n         1/1     Running   0          18m
fluent-bit-tvtpv         1/1     Running   0          18m
</pre>
<p>Check the logs.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl logs &lt;POD_NAME&gt;  -n amazon-cloudwatch
</pre>
<p>Or in my case&#8230;</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
kubectl logs cloudwatch-agent-dfkzv -n amazon-cloudwatch
&#x5B;2022/10/03 13:28:56] &#x5B; info] &#x5B;output:cloudwatch_logs:cloudwatch_logs.2] Created log stream ip-192-168-73-121.us-east-2.compute.internal.host.messages
&#x5B;2022/10/03 13:29:06] &#x5B; info] &#x5B;output:cloudwatch_logs:cloudwatch_logs.0] Creating log stream ip-192-168-73-121.us-east-2.compute.internal-application.var.log.containers.cloudwatch-agent-7fvxd_amazon-cloudwatch_cloudwatch-agent-5409bed9d4733a51602e4bc0cccde5e5580eb3e9282cd5cc4c1a4f2d2e28e8ea.log in log group /aws/containerinsights/eksWordPress/application
&#x5B;2022/10/03 13:29:06] &#x5B; info] &#x5B;output:cloudwatch_logs:cloudwatch_logs.0] Created log stream ip-192-168-73-121.us-east-2.compute.internal-application.var.log.containers.cloudwatch-agent-7fvxd_amazon-cloudwatch_cloudwatch-agent-5409bed9d4733a51602e4bc0cccde5e5580eb3e9282cd5cc4c1a4f2d2e28e8ea.log
</pre>
<p>If you go to CloudWatch now you&#8217;ll see 4 new log groups.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/10/P160-07.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-1024x287.png" alt="" width="1024" height="287" class="aligncenter size-large wp-image-9277" srcset="https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-1024x287.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-300x84.png 300w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-768x215.png 768w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-1536x430.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-2048x573.png 2048w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-1920x537.png 1920w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-1170x327.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-07-585x164.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<h1>Prometheus and Grafana</h1>
<p>The Kubernetes API can also be monitored using Prometheus. We&#8217;ll install it using helm.<br />
Create a namespace first.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl create namespace prometheus
</pre>
<p>Add the Prometheus repo. </p>
<pre class="brush: bash; title: ; notranslate">
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
</pre>
<p>Deploy Prometheus.</p>
<pre class="brush: bash; title: ; notranslate">
helm upgrade -i prometheus prometheus-community/prometheus --namespace prometheus --set alertmanager.persistentVolume.storageClass=&quot;gp2&quot;,server.persistentVolume.storageClass=&quot;gp2&quot;
</pre>
<p>Check if everything is OK.</p>
<pre class="brush: bash; highlight: [1]; title: ; notranslate">
kubectl get pods -n prometheus
NAME                                            READY   STATUS    RESTARTS   AGE
prometheus-alertmanager-5c57cc6945-v9lcb        2/2     Running   0          4m55s
prometheus-kube-state-metrics-77ddf69b4-jsgrp   1/1     Running   0          4m55s
prometheus-node-exporter-68dk9                  1/1     Running   0          4m55s
prometheus-node-exporter-m98xk                  1/1     Running   0          4m55s
prometheus-pushgateway-ff89cc976-4sfhl          1/1     Running   0          4m55s
prometheus-server-6c99667b9b-mpw97              2/2     Running   0          4m55s
</pre>
<p>Type this command and open up a browser and go to localhost:9090.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl --namespace=prometheus port-forward deploy/prometheus-server 9090
</pre>
<p>You can CTRL-C out of the command prompt once you verify it&#8217;s OK.<br />
Let&#8217;s add the Grafana repo first.</p>
<pre class="brush: bash; title: ; notranslate">
helm repo add grafana https://grafana.github.io/helm-charts
</pre>
<p>Copy, paste and save this as <em>grafana.yaml</em>.</p>
<pre class="brush: bash; title: ; notranslate">
datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
    - name: Prometheus
      type: prometheus
      url: http://prometheus-server.prometheus.svc.cluster.local
      access: proxy
      isDefault: true
</pre>
<p>Create a namespace for grafana.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl create namespace grafana
</pre>
<p>Deploy using helm. Look at the <strong>adminPassword</strong> parameter. Change it to something else. In my case it&#8217;s <em>admin123!</em>.</p>
<pre class="brush: bash; title: ; notranslate">
helm install grafana grafana/grafana --namespace grafana --set persistence.storageClassName=&quot;gp2&quot; --set persistence.enabled=true --set adminPassword=&#039;admin123!&#039; --values grafana.yaml --set service.type=LoadBalancer
</pre>
<p>Check if everything is OK.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl get all -n grafana
</pre>
<p>Get the URL of the classic LB that was just created.</p>
<pre class="brush: bash; title: ; notranslate">
export ELB=$(kubectl get svc -n grafana grafana -o jsonpath=&#039;{.status.loadBalancer.ingress&#x5B;0].hostname}&#039;)
echo &quot;http://$ELB&quot;
</pre>
<p>Go to that URL and you&#8217;ll see the Grafana URL.<br />
You should see the Grafana landing page. Log as admin and the password you specified when pods were deployed.<br />
In Grafana create a new dashboard and <strong>Import</strong> the dashboard with ID <strong>3119</strong>. Choose <strong>Prometheus</strong> as source.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/10/P160-08.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-1024x822.png" alt="" width="1024" height="822" class="aligncenter size-large wp-image-9279" srcset="https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-1024x822.png 1024w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-300x241.png 300w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-768x616.png 768w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-1536x1232.png 1536w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-1170x939.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08-585x469.png 585w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-08.png 1892w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><br />
For pods monitoring use the same method but this time specify <strong>6417</strong> as a dashboard ID. This is how it looks like under my account.<br />
<a href="https://blog.andreev.it/wp-content/uploads/2022/10/P160-09.png"><img loading="lazy" decoding="async" src="https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-976x1024.png" alt="" width="976" height="1024" class="aligncenter size-large wp-image-9281" srcset="https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-976x1024.png 976w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-286x300.png 286w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-768x806.png 768w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-1464x1536.png 1464w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-1170x1227.png 1170w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09-585x614.png 585w, https://blog.andreev.it/wp-content/uploads/2022/10/P160-09.png 1468w" sizes="(max-width: 976px) 100vw, 976px" /></a></p>
<h1>WordPress</h1>
<p>Let&#8217;s deploy WordPress.</p>
<pre class="brush: bash; title: ; notranslate">
kubectl create namespace wordpress
</pre>
<p>Add the Bitnami helm chart.</p>
<pre class="brush: bash; title: ; notranslate">
helm repo add bitnami https://charts.bitnami.com/bitnami
</pre>
<p>Deploy WordPress in its own namespace</p>
<pre class="brush: plain; title: ; notranslate">
helm -n wordpress install understood-zebu bitnami/wordpress
</pre>
<p>Wait for 3-4 mins and do this command. This is your ELB, get the URL, something like *zdasdfa*.elb.amazonaws.com</p>
<pre class="brush: bash; title: ; notranslate">
kubectl get svc --namespace wordpress -w understood-zebu-wordpress
</pre>
<p>The username is <strong>user</strong> and get the password with:</p>
<pre class="brush: bash; title: ; notranslate">
echo Password: $(kubectl get secret --namespace wordpress understood-zebu-wordpress -o jsonpath=&quot;{.data.wordpress-password}&quot; | base64 -d)
</pre>
<p>If you go to the ELB URL, you&#8217;ll hit WordPress main page, if you want to login, add <strong>/wp-login.php</strong> as suffix to the above URL.<br />
Go to CloudWatch and check the <strong>/aws/containerinsights/eksWordPress/application</strong> log group. You&#8217;ll see a bunch of references for WordPress. You can ship those to OpenSearch if you want and alert on errors or whatever you want to do.</p>
<h1>Delete EKS and OpenSearch cluster</h1>
<p>Detach the policy, delete the daemonset and delete the EKS cluster.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam detach-role-policy --policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy --role-name eksctl-eksWordPress-nodegroup-ng-NodeInstanceRole-LWJZESQ468Y2
ClusterName=&lt;CLUSTER_NAME&gt;
RegionName=&lt;REGION&gt;
FluentBitHttpPort=&#039;2020&#039;
FluentBitReadFromHead=&#039;Off&#039;
&#x5B;&#x5B; ${FluentBitReadFromHead} = &#039;On&#039; ]] &amp;&amp; FluentBitReadFromTail=&#039;Off&#039;|| FluentBitReadFromTail=&#039;On&#039;
&#x5B;&#x5B; -z ${FluentBitHttpPort} ]] &amp;&amp; FluentBitHttpServer=&#039;Off&#039; || FluentBitHttpServer=&#039;On&#039;
curl https://raw.githubusercontent.com/aws-samples/amazon-cloudwatch-container-insights/latest/k8s-deployment-manifest-templates/deployment-mode/daemonset/container-insights-monitoring/quickstart/cwagent-fluent-bit-quickstart.yaml | sed &#039;s/{{cluster_name}}/&#039;${ClusterName}&#039;/;s/{{region_name}}/&#039;${LogRegion}&#039;/;s/{{http_server_toggle}}/&quot;&#039;${FluentBitHttpServer}&#039;&quot;/;s/{{http_server_port}}/&quot;&#039;${FluentBitHttpPort}&#039;&quot;/;s/{{read_from_head}}/&quot;&#039;${FluentBitReadFromHead}&#039;&quot;/;s/{{read_from_tail}}/&quot;&#039;${FluentBitReadFromTail}&#039;&quot;/&#039; | kubectl delete -f -
eksctl delete cluster --name eksWordPress --region=us-east-2
</pre>
<p>Delete policy.</p>
<pre class="brush: bash; title: ; notranslate">
aws iam delete-policy --policy-arn arn:aws:iam::492943873543:policy/polOpenSearch
</pre>
<p>Delete CloudWatch log groups.</p>
<pre class="brush: bash; title: ; notranslate">
EKS_CLUSTER=eksWordPress
aws logs delete-log-group --log-group-name &quot;/aws/containerinsights/$EKS_CLUSTER/application&quot;
aws logs delete-log-group --log-group-name &quot;/aws/containerinsights/$EKS_CLUSTER/dataplane&quot;
aws logs delete-log-group --log-group-name &quot;/aws/containerinsights/$EKS_CLUSTER/host&quot;
aws logs delete-log-group --log-group-name &quot;/aws/containerinsights/$EKS_CLUSTER/performance&quot;
aws logs delete-log-group --log-group-name &quot;/aws/eks/$EKS_CLUSTER/cluster&quot;
</pre>
<p>Delete the OpenSearch cluster.</p>
<pre class="brush: bash; title: ; notranslate">
aws opensearch delete-domain --domain-name oswordpress
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.andreev.it/2022/10/aws-eks-monitoring-and-logging/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
