Keeping your Cloud Costs in Check: Automated AWS Cost Charts and Alerting
Tags: aws, blog, cloudcosts, cloudops
Published: 2023-04-13 22:41:07

---
title: Keeping your Cloud Costs in Check: Automated AWS Cost Charts and Alerting
published: true
date: 2023-03-20 16:03:51 UTC
tags: AWS,Blog,CloudCosts,CloudOps
canonical_url: https://unskript.com/keeping-your-cloud-costs-in-check-automated-aws-cost-charts-and-alerting/
---
<p>Building and deploying infrastructure in the cloud is (by design) a very simple process. If a team is not being careful in their deployments, it can also become an <strong>expensive</strong> process. The interplay between finance teams and cloud teams has led to a new job function – FinOps. What is FinOps? This team (or team member) works with developer teams to understand cloud needs, negotiates better prices with cloud operators, and can help translate cloud expenses and needs to the finance team.</p>
<p>However, many companies working in the could don’t have the luxury of allocating a team member to understanding cloud costs, and it is left to the dev teams to do their best to mitigate surprise bill.  Without a full-time FInOps professional, teams will need tooling to help them better understand and control their cloud bills.</p>
<p>The FinOps Institute has defined 6 domains for a FinOps tram:</p>
<p> </p>
<ul>
<li>Understanding Cloud Usage and Cost</li>
<li>Performance Tracking and Benchmarking</li>
<li>Real Time Decision Making</li>
<li>Cloud Rate Optimization</li>
<li>Cloud Usage Optimization</li>
<li>Organizational Alignment</li>
</ul>
<p> </p>
<p>In this post, we’ll describe a series of automated RunBooks that check the first three boxes (and help inform several others).  What we’ll do is build automated reporting around the AWS Cost and Usage Report (CUR).</p>
<p> </p>
<h2><strong>The AWS CUR</strong></h2>
<p>AWS’ Cost and Usage Report is a SQL report that breaks down your AWS spend in many different ways, and at a selected interval (hourly, daily, monthly).  When generating a CUR report, a SQL file is placed into a S3 bucket at regular intervals.  To set up a CUR report for your AWS Account, the AWS Documentation has a very <a href="https://docs.aws.amazon.com/cur/latest/userguide/cur-create.html">nice tutorial</a>.  In this post, our CUR is updated daily, but for larger projects, you may want hourly granularity.</p>
<p>We set our CUR report to be sent into AWS Redshift.  However, the daily updates are only added to the S3 file.  To update our Redshift table, we must regularly take the file in SQL and update the database in Redshift.</p>
<p>We accomplish this by building a RunBook using a few new Actions:</p>
<p><img decoding="async" src="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=694%2C654&amp;ssl=1" alt="RunBook to update table in Redshift" width="694" height="654" srcset="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=1024%2C965&amp;ssl=1 1024w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=300%2C283&amp;ssl=1 300w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=768%2C724&amp;ssl=1 768w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=1116%2C1052&amp;ssl=1 1116w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=806%2C760&amp;ssl=1 806w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=558%2C526&amp;ssl=1 558w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=655%2C617&amp;ssl=1 655w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?resize=24%2C24&amp;ssl=1 24w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-15-at-23.23.20.jpg?w=1290&amp;ssl=1 1290w" sizes="(max-width: 694px) 100vw, 694px" data-recalc-dims="1"></p>
<p> </p>
<p>When Making a RedShift Query, we need to know the Secret Manager ARN, the AWS Region, and the Redshift Cluster/database.</p>
<p>To get the Secret Arn, we use the <em>AWS GET Secrets Manager ARNAction.  </em>This takes a secret name, and provides the ARN.  (This does require Secrets Manager permission in your IAM credential.)</p>
<p>We then Create two SQL queries programatically.  The table in Redshift is named <em>awsbilling202303</em> (since it is currently March 2023). To ensure that the table name is always correct, we generate the query programmatically, so that the table name always has the format <em>awsbilling&lt;year&gt;&lt;month&gt;.</em></p>
<p>Next, we perform two SQL commands:</p>
<p>First, we TRUNCATE the table. This removes all of the rows, but keeps the columns:</p>
<pre>truncate table awsbilling202303</pre>
<p>Next, we COPY the rows from the SQL table in AWS:</p>
<pre>copy awsbilling202303 from 's3://unskript-billing-doug/all/unskript-billing-doug/20230301-20230401/unskript-billing-doug-RedshiftManifest.json' credentials 'aws_iam_role=arn:aws:iam::&lt;arn name&gt;' region 'us-west-2' GZIP CSV IGNOREHEADER 1 TIMEFORMAT 'auto' manifest;</pre>
<p>This query is provided in your S3 bucket.</p>
<p>With the RunBook created, we can schedule this RunBook to run daily, ensuring that the AWS table is always up to date.</p>
<p>NOTE:  I am not a database expert.  This is the “I have a hammer, so everything must be a nail” approach to updating the database.  There is probably a more nuanced query that could be run.</p>
<h2>Building Charts and Alerts</h2>
<p>Now that the data is being populated into Redshift daily, we can begin exploring our data.  In this second RunBook, we are going to extract the daily spent for each AWS service, plot the data, and create an alert for large changes in costs.</p>
<p>Our new RunBook begins the same way as our first RunBook – generating a SQL query and executing it at RedShift.  This time we are querying Redshift for usage costs for every AWS product:</p>
<pre>select lineitem_productcode, 
        date_part(day, cast(lineitem_usagestartdate as date)) as day, 
        SUM((lineitem_unblendedcost)::numeric(37,4)) as cost 
from awsbilling202303 
group by lineitem_productcode, day 
order by cost desc;

</pre>
<p>This query is then placed into a dataframe. Using this data, we can create a chart of our daily spend by AWS product:</p>
<p><img decoding="async" loading="lazy" src="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=945%2C496&amp;ssl=1" alt="AWS Product Cost by day" width="945" height="496" srcset="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=1024%2C538&amp;ssl=1 1024w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=300%2C157&amp;ssl=1 300w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=768%2C403&amp;ssl=1 768w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=1116%2C586&amp;ssl=1 1116w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=806%2C423&amp;ssl=1 806w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=558%2C293&amp;ssl=1 558w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=655%2C344&amp;ssl=1 655w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?resize=24%2C13&amp;ssl=1 24w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.39.jpg?w=1204&amp;ssl=1 1204w" sizes="(max-width: 945px) 100vw, 945px" data-recalc-dims="1"></p>
<p>Here is the same chart – just looking at the last seven days:</p>
<p><img decoding="async" loading="lazy" src="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=945%2C482&amp;ssl=1" alt="AWS costs over the last 7 days" width="945" height="482" srcset="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=1024%2C522&amp;ssl=1 1024w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=300%2C153&amp;ssl=1 300w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=768%2C392&amp;ssl=1 768w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=1116%2C569&amp;ssl=1 1116w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=806%2C411&amp;ssl=1 806w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=558%2C284&amp;ssl=1 558w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=655%2C334&amp;ssl=1 655w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?resize=24%2C12&amp;ssl=1 24w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.03.59.jpg?w=1228&amp;ssl=1 1228w" sizes="(max-width: 945px) 100vw, 945px" data-recalc-dims="1"></p>
<p>If we look back at the FinOps Institute bullet list, we are beginning the FinOps Institute bullets: <em>Understanding Cloud Usage and Cost</em>, as well as <em>Tracking our Performance</em>.</p>
<p>If we automate this RunBook to run daily (after the table is updated), we can generate this regular plot of our AWS Cloud Spend.  In general, a daily chart with no change is not of great interest.  But – if we can build an alert around our Cloud usage that finds significant increases in day to day cost – we can attach this chart to make the cost jump easy to identify.</p>
<h2>Building an Alert</h2>
<p>Every organization will have different thresholds for alerting. In the following code, we examine the 2 days previous (March 18 and 19) and look for increases of over 5%.  Since many of the services in this chart are at very low spend rates, we add the additional filter that the change must be over $1. Looping over each service with the following:</p>
<pre>if abs(todayCost-yesterdayCost) &gt;1: 
   if delta &gt;.05:
       #print( instance, delta,dfpivot.at[today, instance], dfpivot.at[yesterday, instance])
       bigchange[instance] = {"delta":delta, "todayCost":todayCost,"yesterdayCost":yesterdayCost}
       alertText = '@here There has been a large change in AWS Costs'
       alert = True
if date.today().weekday() == 0:
   alertText = 'Today is Monday, Here is the last week of AWS Costs'
   alert = True</pre>
<p>If any of the changes in cost trigger this alert, we send an image on Slack with a ‘@here, there’s been a large change in AWS Spending” message.  We also send the chart every day on Monday., so that there is a visual history of AWS spending.</p>
<p><img decoding="async" loading="lazy" src="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=945%2C510&amp;ssl=1" alt="Slack message with chart of AWS spending" width="945" height="510" srcset="https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=1024%2C553&amp;ssl=1 1024w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=300%2C162&amp;ssl=1 300w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=768%2C415&amp;ssl=1 768w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=806%2C435&amp;ssl=1 806w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=558%2C301&amp;ssl=1 558w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=655%2C354&amp;ssl=1 655w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?resize=24%2C13&amp;ssl=1 24w, https://i0.wp.com/unskript.com/wp-content/uploads/2023/03/Screenshot-2023-03-20-at-11.32.19.jpg?w=1026&amp;ssl=1 1026w" sizes="(max-width: 945px) 100vw, 945px" data-recalc-dims="1"></p>
<p>When beginning to study and alert on your Cloud Spending it is important to start with simple reports and altering. This use case of daily spend by product, is a great start into our journey into the FinOps Institute’s next bullet points: <em>Real Time Monitoring</em> and <em>Cloud Usage Optimization</em>.</p>
<p> </p>
<h2>Conclusion</h2>
<p>Many companies feel the monthly dread of “how big will my Cloud bill be <strong>this</strong> month?” By charting and alerting on your daily spend across all Cloud products, your team is less likely to be surprised by the beill at the end of the month. This data can also be used mitigate large changes that often result in bill “surprises.”</p>
<p>Using unSkript and the AWS Cost and Usage report, you can begin (or continue) your FinOps journey by better understanding where your costs are coming from and how they are changing day to day.  Watch our blog for more posts on Cloud CostOps and how you can monitor your AWS bill.</p>