<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sam J Drew]]></title><description><![CDATA[Sam J Drew]]></description><link>https://blog.samjdrew.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1722736896452/5994c1c1-69fd-4a38-8b7e-ad0f65e65958.png</url><title>Sam J Drew</title><link>https://blog.samjdrew.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 07 Jun 2026 17:42:36 GMT</lastBuildDate><atom:link href="https://blog.samjdrew.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[A Christmas Ramble]]></title><description><![CDATA[Let’s put a bow on this website-making project. We set out to create a website in Django and to host it in AWS. The primary goal was to learn the Django framework because that was what we did at my workplace at the time. These days, however, I no lon...]]></description><link>https://blog.samjdrew.com/a-christmas-ramble</link><guid isPermaLink="true">https://blog.samjdrew.com/a-christmas-ramble</guid><category><![CDATA[AWS]]></category><category><![CDATA[#AWSPricing #CloudCosts #AWSBudgeting #CostOptimization #PricingOptions #AWSBilling #SavingsPlans #ReservedInstances #SpotInstances #CloudFinance ]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[webhosting]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sat, 21 Dec 2024 08:49:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1734736796290/17fcc22d-0272-4e15-8073-3e1b7b7cd623.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let’s put a bow on this website-making project. We set out to create a website in Django and to host it in AWS. The primary goal was to learn the Django framework because that was what we did at my workplace at the time. These days, however, I no longer need to use Python/Django and my interests are focused generally in systems-level programming, and less-so in website development.<br />There’s a few outstanding items that I have to address in this post. So without further TODOs (I’m hilarious btw), lets take a look at what we did to bring down our aws billing to less than a quarter of our previous Elastic Beanstalk costs and how the website has handled the shift.</p>
<hr />
<h2 id="heading-measurable-indifference">Measurable Indifference</h2>
<p>Following on from <a target="_blank" href="https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin">my last post</a>, I mentioned that we would be looking to move from Elastic Beanstalk to EC2 spot requests. EB was useful. Initially, it was a great starting point. But after our foray into Elastic Beanstalk to get the website live, I've come to the following conclusion:<br />EB is for people with new projects that just want to get started and don't much care how anything works or how much it costs[^1].<br />I’m not pointing fingers because this was me <a target="_blank" href="https://blog.samjdrew.com/devlog-1-hosting-my-django-website">not too long ago</a>. Something I’ve learned since leaving full-time work is that it pays to know how to actually put it together yourself so that you can cut out the bits that you don't need and minimise the costs that you can.</p>
<p>Here’s what I did…</p>
<p>In my last post, we distilled the dizzying morass that was our AWS billing page into 3 distinct actions we can take to reduce our total spending on the website.</p>
<ul>
<li><p>Remove all static IPv4 addresses</p>
</li>
<li><p>Decommission the Network Load Balancer that was doing nothing but routing https to http and handling the SSL for us</p>
</li>
<li><p>Move from Elastic Beanstalk to a spot fleet to host the Django app</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734741746214/abdba55e-6486-45e7-9fd3-87ca9b01f971.png" alt class="image--center mx-auto" /></p>
<p><em>The last three months of AWS bills has felt like a warm hug from my wallet</em></p>
<p>Now you might be thinking, “well, yeah of course it costs less, we now have to do all the server management and scaling ourselves!” To which I say the short answer is yes… and no… twice…</p>
<p><strong>Yes, it’s a bit more work:</strong> we will need to manage the server configuration now. But that’s good! we want to know exactly what’s running on our instance (instead of vaguely knowing that Django is being used to handle http requests <em>somehow</em>).</p>
<p><strong>And “no”</strong>: The whole server configuration can be defined in a single script that gets run every time the server starts. No ongoing management required, just set and forget.</p>
<p><strong>Yes, scaling is something to manage</strong>: If we were managing any kind of load on my website, we would have to set up scaling rules.</p>
<p><strong>But “no” because</strong>: Until we start seeing the thousands of readers and clients that my mum says I deserve, we can stick to the smallest morsel of compute power that AWS can charge for.</p>
<h3 id="heading-server-configuration-in-one-file">Server Configuration in one file:</h3>
<p>First, we switched off the EB which removed all the resources in commissioned including the expensive Load Balancer and the unnesesary static IP addresses.</p>
<p>We then needed to define our own basic VPC. This can be just a standard public VPC with an internet gateway and 3 public subnets, one in each ap-southeast-2 availability zone (we have no backend database so public subnets will do just fine for our purposes).</p>
<p>Next, we moved the server to a spot fleet request (‘fleets’ can be configured to be 1 instance). The request uses a configuration object called a ‘launch template’ containing all our capacity and compute preferences and configuration information.</p>
<p>The spot request will look for the cheapest of any t2.micro, t2.small, t3.micro, or t3.small available in any AZ in ap-southeast-2 and assign it to the appropriate subnet in our VPC. The instance is then automatically given a public IP address by our VPC.</p>
<p>The launch template also includes a "user data" section that is executed every time the server instance starts up. If you’re more familiar with Docker, you can think of the ‘launch template’ as AWS lingo for a dockerfile and the confusingly named "user data" section is an entrypoint script that gets called in your image's dockerfile. The point is, all the code in “user data” gets run. <strong>First thing.</strong> As soon as our instance is running.<br />This is very important because spot instances will get interrupted semi-regularly by aws (I've found mine are replaced at least once per day).</p>
<p>Every time our EC2 instance changes, our “user data” should perform the following actions:</p>
<ol>
<li><p>Find the instance’s public IP address (These first three steps are required because we now have no load balancer and therefore no static IP address to always route traffic to. So whenever a new server is started, we have to directly edit the A record in our DNS settings to tell the internet that the website's host server is now <em>here</em>).</p>
</li>
<li><p>Change our Route53 A record to set <a target="_blank" href="http://samjdrew.com">samjdrew.com</a> to go to this new instance’s public IP.</p>
</li>
<li><p>Search our code packages S3 bucket for the latest version of the website and unzip it.</p>
</li>
<li><p>Install Python 3.11 and NGINX.</p>
</li>
<li><p>In the unzipped source code, activate Django's python venv and install requirements.</p>
</li>
<li><p>Configure gunicorn daemon workers to run the Django app.</p>
</li>
<li><p>Start gunicorn and NGINX.</p>
</li>
<li><p>use certbot-nginx to assign a free SSL certificate and set up https on nginx [²].</p>
</li>
</ol>
<p>The interested reader can check out the actual code over on <a target="_blank" href="https://github.com/MountainBean/Online/blob/master/.ec2config/userdata.sh">my website repo</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1734757788955/9ad3b0a6-8874-434e-b3ec-b1adddd4ca81.png" alt class="image--center mx-auto" /></p>
<p><em>Do diagrams help? In my head, it’s simpler than this makes it look.</em></p>
<p>This is everything we need. And that’s how I’ve left it for the past 3 months. Of course, now and again, I check in on the website as often as my ego prompts me to but it’s been up every time I’ve checked. I half expected there to be some disarray somehow manifesting from my negligence but it looks like we’ve written a good system.</p>
<h3 id="heading-lets-briefly-consider-scalability">Let’s briefly consider scalability</h3>
<p>The magic word of cloud platform engineering - scalability - is a term thrown around so much, you’d think it’s a requirement for any cloud-hosted solution. There’s a section in chapter one of Martin Kleppmann’s <em>Designing Data-Intensive Applications:</em></p>
<blockquote>
<p>[Scalability] is not a one-dimensional label that we can attach to a system: it is meaningless to say “X is scalable” or “Y doesn’t scale.” Rather, discussing scalability means considering questions like “If the system grows in a particular way, what are our options for coping with that growth?” and “How can we add computing resources to handle the additional load?” -</p>
</blockquote>
<p>The rest of the section goes on to point out that <em>before</em> we discus scalability, we need to have a way to measure load on the system and the performance of the system. We also need to know what our performance goals for the system are. Do we want the 99.9th percentile to experience webpage load times of less than 1 second? Is that doable? How much work will that take? What about the 99.99th percentile?</p>
<p>In a commercial setting, this makes a lot of sense. Having a way to reduce your cloud spending when traffic is low and only increase when demand for your service goes up is the Great Cloud Dream™. Scaling up and/or out at peak volume periods and scaling back down/in when traffic usually dies down is a neat, effective way to minimise wasted resources and is one of the major selling points of Cloud resources over on-prem. Autoscaling is the sledgehammer approach and is only really appropriate when you’re dealing with unpredictable loads.</p>
<p>Scalability is a tool - or maybe a power-tool, to present a more visual analogy. It can and should be used but only AFTER:</p>
<ol>
<li><p>Defining <em>how</em> you’ll measure performance and load</p>
</li>
<li><p>Using those definitions to define your Service Level Objectives (SLO and SLA if you’re working with a client)</p>
</li>
<li><p>Setting up billing alerts (which should be done as soon as you set up any cloud hosting account that’s tied to your wallet)</p>
</li>
</ol>
<p>For this website, there’s no sense in implementing an autoscaling group with a maximum instance count greater than 1 because our 1 instance should be able to handle <a target="_blank" href="https://docs.gunicorn.org/en/latest/design.html#how-many-workers">hundreds of requests per second</a>.<br />As far as we’re concerned, we can be content in the knowledge that the small handful of clients or employers who bother to click on our website are getting our website.</p>
<h3 id="heading-the-left-overs">The left-overs</h3>
<p>There were some issues beneath the surface that I haven’t addressed:</p>
<ul>
<li><p><s>Github actions were broken since moving away from Elastic Beanstalk meant we had to come up with a way of getting my source code onto the server (this was particularly embarrassing for me to ignore for so long as someone who once had </s> <em><s>DevOps</s></em> <s>in his job title).</s></p>
<ul>
<li>This is fixed now. After merging to master, github actions sends a zipped package of the code to an S3 bucket, removes the “-latest” suffix from the old package and appends it to the new one, temporarily scales the spot fleet to 2 instances and then terminates the old instance after 3 minutes. The new instance handles all the server set up and domain redirection as described above and a new version of our website is live about 4 minutes after we merge to master.</li>
</ul>
</li>
<li><p>The pages on certifications and experience still haven’t been implemented, which is hilarious for a website that’s supposed to be a portfolio landing page</p>
</li>
<li><p>we don’t talk about the photography website.</p>
</li>
</ul>
<p>Jumping back into this project after three months, after not thinking about or working on anything Python/Django, I found it daunting trying to remember how Django organises itself. Python/Django has taken a sharp nose-dive in my list of priorities and unfortunately, the website has been in limbo because of that.</p>
<p>I’ll always be intrigued by cloud platforms and automating build systems. However, in my spare time, I’ve been trying to expand into a few new areas that I’m not familiar enough with.</p>
<p>In the past 3 months, I've:</p>
<ul>
<li><p>learned to use Cmake/ninja to build large C projects</p>
</li>
<li><p>been <em>re</em>-learning C/C++ and assembly</p>
</li>
<li><p>Learned to draw a triangle in OpenGL</p>
</li>
<li><p>reading:</p>
<ul>
<li><p>Martin Kleppmann's <em>Designing Data-Intensive systems</em> and</p>
</li>
<li><p>Thorsten Ball’s <em>Writing an Interpreter in Go</em></p>
</li>
</ul>
</li>
<li><p>Been working on my own indie game in Godot 4</p>
</li>
</ul>
<p>The point is, everything I learned about django/python and HTML/CSS while throwing this website together this year is buried under several dense layers of unrelated CS stuff that I had to sift through to write this. The Python/Django atrophy has begun and I don’t want to strain myself trying to strengthen those muscles again when it’s no longer a thing I need for my job and I have other priorities preceding it.</p>
<p>This isn’t the post for discussing learning goals and professional growth[³]. I just wanted to wrap up the last outstanding thing I said I’d write about with regards to creating and hosting a website.</p>
<p>Some day I may start measuring data from my nginx access logs and use that data to make a more informed decisions around scaling and traffic. But at the moment, I have other things I’m excited to learn about and the website is up so I’m not fussed.</p>
<p>Just one more thing, my old domain mountainbean.online expired this week and my domain registrar wanted me to pay $80 US to renew it which was never going to happen. Thus you may have noticed I’ve moved to samjdrew.com. If the savvy reader has any idea where I can get better domain registrars that don’t hold my domain to ransom every year, please write in and let me know. Feedback is also welcome.</p>
<hr />
<p>[^1]: I had a whole analogy here where you would ask your mate to by groceries and cook dinner for you but it turns out your mate got kickbacks from the grocery store so he buys you a bunch of stuff you don’t need to run up your grocery bill. It’s a bit cynical and the analogy was not exactly relatable so decided not to force my up-and-coming novella “Stretchy- Legume Steve” upon you.</p>
<p>[²]: It’s worth noting somewhere that I don’t have to ever worry about renewing my certificates. My servers are rebooted around every 2 days and a new certificate is generated each time. (Edit: turns out this is a problem because if I ever go over 5 certificates in a week, certbot stops giving me new certs that week. I’ll have to work in a way to store, access and renew my certs.</p>
<p>[³]: but if it were, it’d be inspirational af.</p>
]]></content:encoded></item><item><title><![CDATA[FinOps is a conspiracy by big Ops to make you use more Fin]]></title><description><![CDATA[There's an episode in season 2 of Community where Jeff, while doing his very best not to do anything, gets caught up in a comically layered conspiracy about the risks of trying to do nothing. Now I'm not trying to do nothing but right now I don't hav...]]></description><link>https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin</link><guid isPermaLink="true">https://blog.samjdrew.com/finops-is-a-conspiracy-by-big-ops-to-make-you-use-more-fin</guid><category><![CDATA[finops]]></category><category><![CDATA[AWS FinOps]]></category><category><![CDATA[AWS]]></category><category><![CDATA[ec2]]></category><category><![CDATA[Django]]></category><category><![CDATA[vpc]]></category><category><![CDATA[IPv4]]></category><category><![CDATA[ipv6]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Fri, 23 Aug 2024 13:06:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724737380328/71320c54-3e01-43a1-a87b-21b559117d14.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There's an episode in season 2 of Community where Jeff, while doing his very best not to do anything, gets caught up in a comically layered conspiracy about the risks of trying to do nothing. Now I'm not trying to do <em>nothing</em> but right now I don't have the time to do more than I need to. And the more I can do while <strong><em>not</em></strong> doing (and <strong><em>not paying</em></strong>), the better. This is where my website comes in.</p>
<p>In the act of procuring cloud infrastructure for my website, <a target="_blank" href="https://blog.mountainbean.online/devlog-1-hosting-my-django-website">I've taken some shortcuts</a> and I <em>thought</em> I'd carefully measured the price of those shortcuts and was willing to pay for them. Despite that, when my budget alerts went off a mere 10 days into the month, I was surprised and also kind of annoyed. How can this be?</p>
<p>So for this dev log, I've decided to have a look at my bills and see what we can do.</p>
<p>Oh boy. I don't know why I bothered spending so much time time tinkering my <a target="_blank" href="https://blog.mountainbean.online/devlog-2-getting-s3-connected-to-my-django-website">S3 media file hosting solution</a>. That and most of the other costs related to my website server are dwarfed by this huge, honking Load balancer bill!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724052986708/2fa9505d-5eb4-4579-ab02-abab19f45817.png" alt class="image--center mx-auto" /></p>
<p><em>Load balancer clearly costs more than any other service. However VPC is unusually High too...</em></p>
<p>So yeah what's all that for just a micro T3 EC2 box quietly running a Django app that no one but me uses? I see 3 chunky bars evoking my ire.</p>
<ul>
<li><p>Load Balancer</p>
</li>
<li><p>VPC</p>
</li>
<li><p>EC2 - Compute</p>
</li>
</ul>
<p>Let's address the Load balancer first.</p>
<h4 id="heading-balance-deez">Balance Deez</h4>
<p>I don't see myself as a conspiracy person, but there's a reason AWS tells you <a target="_blank" href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/configuring-https.html">"the simplest" way to enable https</a> on your server is by attaching a load balancer. You can see it here in their documentation on the <a target="_blank" href="https://aws.amazon.com/elasticloadbalancing/pricing/"><em>Load Balancer pricing</em></a> page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724053939900/066da88e-a4ca-4cfa-a960-d9f0989e4e67.png" alt class="image--center mx-auto" /></p>
<p>Straight out of the gate, we're spending upwards of $18 per month just to keep the load balancer on 24/7. That's not even considering the LCUs (Capacity units) used. $18/month is already too much and I'll need to take action to fix this (the action is me ripping it out like a weed, in case you were wondering).</p>
<p>Next up is the VPC. What's that charge for?</p>
<p>Well, dear reader, much like a decently priced rental in Brisbane City, public addresses on the internet are in short supply (that is, IPv4 addresses). This makes them valuable. Valuable enough that <a target="_blank" href="https://repost.aws/articles/ARknH_OR0cTvqoTfJrVGaB8A/why-am-i-seeing-charges-for-public-ipv4-addresses-when-i-am-under-the-aws-free-tier">as of February 2024, Amazon has been charging 0.5 cents per hour</a> for the pleasure of using one. Fast-forward to last month, when I asked Elastic Beanstalk to put my website online. It assumed I was a man of vastly more means than I really am and decided that I must want 3 availability zones each with a public IP address.</p>
<p>I was just a poor developer, trying to find a cheap way to host my website. Now look at me, I have a leak in my bank account of exactly 1.5 cents/hour and I get to think to myself, "boy am I glad my website is highly available".</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724070644186/f31fda92-dc9a-4bd1-9a9e-d817372b5bfc.png" alt class="image--center mx-auto" /></p>
<p><em>1.5 cents per hour makes Sam a poor boy</em></p>
<p>Finally EC2 pricing. There's not much to say.</p>
<p>EC2 charges based on the type of EC2 and data transferred in a given time period. Data transfer is negligible at this stage and the EC2 type is T3-micro, the 2nd cheapest on-demand instance AWS offers. However, there are still some neat little FinOps tricks I can explore here.</p>
<h4 id="heading-yes-finops-is-a-real-word">Yes, FinOps is a real word</h4>
<p>First off, the ALB has to go. There's no sense in my using a Load balancer anyway because my website traffic is featherweight. If that ever changes, I'll scale it up myself. For now paying $18 per month for a fancy server to route https traffic to my single node website is farcical. It's doing nothing but serving the SSL certificate which I can get Nginx to do on the instance for free.</p>
<p>While reconfiguring things, we could reduce our VPC costs by switching to IPv6. This would remove all the IPv4 tolls and our only charges will come from traffic (if we ever break out of free tier). Unfortunately, IPv6 presents a lot of it's own challenges. Namely that neither my home broadband service provider nor my mobile service provider support IPv6. The funny part is that even AWS has spotty IPv6 support! The <em>AWS Instance Connect</em> tool that AWS provides to connect to instances through your browser ALSO doesn't actually support IPv6. Why is any of that relevant? Because practically, yes I can configure and populate an IPv6-only VPC and subnets regardless of whether my ISP or Instance Connect supports IPv6. However, I won't be able to reach them for configuring or debugging my instances because I can't SSH in from home. It seems no one can actually handle the protocol that has been getting "adopted" since 2012.</p>
<p>Well okay. I can at least remove the 2 IPv4 addresses that I'm not using. That'll reduce the VPC costs by 1 cent/hour saving me up to $7.44/month (USD btw so that's actually around 14 dollaroos 🦘).</p>
<p>Finally we need to reduce EC2 costs. Savings plans are an option. According to AWS documentation, this would bring the hourly price of my instance down by 22%. However, I've been wanting to try out creating a spot fleet. It's essentially an autoscaling group but the instances are only ever spot instances. I can configure a spot fleet with a desired capacity of only 1 instance. Spot instances can get reclaimed by AWS at any time as other users are willing to pay the on-demand price. However if you have a spot fleet set up, the instance will be replaced automatically (if possible). Looks like this should bring my EC2 instance costs down around by 35%. If my website goes down for a few minutes or hours between spot instances, I'll live.</p>
<blockquote>
<h4 id="heading-and-a-very-familiar-feeling-is-starting-to-come-over-me-i-feel-like-someone-is-trying-to-teach-me-something-jeff-winger-community-episode-conspiracy-theories-and-interior-design">"...And a very familiar feeling is starting to come over me. I feel like someone is trying to teach me something." - Jeff Winger, Community Episode: Conspiracy Theories and Interior Design</h4>
</blockquote>
<p>To a seasoned Platform Engineer, I'm sure this is some kindergarten-level course-correction. It's not tricky to point out where I've taken shortcuts. I've done the cloud certification exams, I've heard of these issues before and I've been working in AWS for a few years. That's why I know that these are common problems and where to find the solutions. But I've never actually had to foot the bill for my shortcuts. That's what this little project is for (among other things). Unlike Jeff Winger, I'm here to learn and it's all part of the experience.</p>
<p>Keep an eye out for my next post where I'll go through implementing my cost-saving changes and how much my AWS bill actually changes.</p>
]]></content:encoded></item><item><title><![CDATA[Getting S3 Connected to my Django Website]]></title><description><![CDATA[In my last Devlog, I got my Django website hosted on Elastic Beanstalk by uploading a packaged zip of all the application code and the static files including my sample photos. While it was a success and it got the website live, it's not... comfortabl...]]></description><link>https://blog.samjdrew.com/devlog-2-getting-s3-connected-to-my-django-website</link><guid isPermaLink="true">https://blog.samjdrew.com/devlog-2-getting-s3-connected-to-my-django-website</guid><category><![CDATA[Django]]></category><category><![CDATA[AWS]]></category><category><![CDATA[S3-bucket]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 04 Aug 2024 11:45:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722838584920/3004ac30-5143-4d00-a757-c5b2b342e265.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my last Devlog, I got my Django website hosted on Elastic Beanstalk by uploading a packaged zip of all the application code and the static files including my sample photos. While it was a success and it got the website live, it's not... comfortable.<br />My code has to be manually zipped up (along with a handful of huge jpegs which bloat out my repo). Then they get pushed manually to Elastic beanstalk via the AWS console.</p>
<p>Now look... no one's saying you must only ever use Terminal to get around, but the thought of clicking my mouse that many times just to push to production makes my little DevOps tummy hurt.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722770540099/d1c2a6be-f9b6-4d3e-8b62-17b19037fba0.png" alt /></p>
<p><em>The Django tech stack ✨idea✨</em></p>
<h6 id="heading-configuring-prod-data-in-dev">Configuring prod data in dev</h6>
<p>So this is just so I don't have to muck around setting up and spending money on a DB. Photo details are all stored in SQLite. That gets uploaded with my code to the repo. I then have Github Actions push that to Elastic Beanstalk, as my manager says, "auto-magically". No dev DB/prod DB disparity. It's just my website. For this moment, the data can be the same.<br />Now what about the photos and any other static files? I should move those to S3.</p>
<p>Firstly, I've set up a bucket with public read access, uploaded my photos there, set up Django to map the media URLs to the s3 bucket. Then I'll sit back and use all the spare time I now have googling ways I could've done it better.</p>
<pre><code class="lang-python">MEDIA_URL = <span class="hljs-string">"/photo_files/"</span>
<span class="hljs-keyword">if</span> DJANGO_WEBSITE_ENVIRONMENT == <span class="hljs-string">"PROD"</span> <span class="hljs-keyword">or</span> DJANGO_WEBSITE_ENVIRONMENT == <span class="hljs-string">"BUILD"</span>:
    AWS_STORAGE_BUCKET_NAME = <span class="hljs-string">"mountainbean-photos-bucket-shepherds-pie"</span>
    AWS_S3_REGION_NAME = <span class="hljs-string">"ap-southeast-2"</span>
    AWS_ACCESS_KEY_ID = getenv(<span class="hljs-string">"S3_WRITE_USER_ACCESS_KEY"</span>)
    AWS_SECRET_ACCESS_KEY = getenv(<span class="hljs-string">"S3_WRITE_SECRET_ACCESS_KEY"</span>)

    AWS_S3_CUSTOM_DOMAIN = <span class="hljs-string">f"<span class="hljs-subst">{AWS_STORAGE_BUCKET_NAME}</span>.s3.amazonaws.com"</span>

    STORAGES = {
        <span class="hljs-string">"default"</span>: {
            <span class="hljs-string">"BACKEND"</span>: <span class="hljs-string">"storages.backends.s3.S3Storage"</span>,
            <span class="hljs-string">"OPTIONS"</span>: {
                <span class="hljs-string">"location"</span>: <span class="hljs-string">"media"</span>
            },
        },
        <span class="hljs-string">"staticfiles"</span>: {
            <span class="hljs-string">"BACKEND"</span>: <span class="hljs-string">"storages.backends.s3.S3Storage"</span>,
            <span class="hljs-string">"OPTIONS"</span>: {
                <span class="hljs-string">"location"</span>: <span class="hljs-string">"static"</span>
            }
        }
    }
</code></pre>
<p>Using the django_storages library, I've configured the public S3 bucket as a backend with a service role that has write-access permission on the bucket. An admin with access to post a new photo on the website (me) now has permissions to upload to the bucket from the website and that photo can be viewed by any visitor via a url to the photo location in the public bucket.</p>
<h6 id="heading-so-whats-with-the-if-statement">So what's with the if() statement?</h6>
<p>When the website is being hosted by elastic beanstalk, I want Django to give out the correct urls to the photos in the S3 bucket. Likewise, when Github actions is deploying the code (there the environment variable will be <em>BUILD</em>) and running collectstatic, I want django to send the static files to S3, not just collect them into a local directory. However, when I'm just working on this on my machine, I don't want those files going anywhere.</p>
<p>So I set: <code>MEDIA_ROOT = BASE_DIR / "uploads"</code> in my <a target="_blank" href="http://Settings.py">Settings.py</a> and:</p>
<pre><code class="lang-python"><span class="hljs-keyword">if</span> settings.DJANGO_WEBSITE_ENVIRONMENT != <span class="hljs-string">"PROD"</span>:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)
</code></pre>
<p>Map that directory to MEDIA_URL in my root <a target="_blank" href="http://urls.py">urls.py</a> so Django will send all my uploaded images there when I'm just in <a target="_blank" href="http://localhost">localhost</a>.</p>
<h6 id="heading-the-catch">The catch</h6>
<p>I have one manual step left. When I make a commit or merge to master (triggering my Github workflow) I have to remember to copy my <em>uploads</em> folder to the public S3 bucket under the <em>media</em> key.<br />Lastly, I should address the issue of uploading my full-size images to the web. I've just shifted the problem from my repo to the S3 bucket. I still have very large JPEGs in my public S3 bucket that I (and any other visitor) will be requesting every time I visit my site.<br />AWS gives you a free 100GB of data transfer out of S3 per month. But if I'm not careful, my big fat JPEGs might use that up quickly. I'll look at resizing uploads next...</p>
]]></content:encoded></item><item><title><![CDATA[Hosting my Django Website]]></title><description><![CDATA[Setting
I've been working on a photography website as a project to force myself to actually learn Django. I enjoy coding and I love taking shitty photos but I've never deigned to host my own work anywhere other than Instagram. By setting a project fo...]]></description><link>https://blog.samjdrew.com/devlog-1-hosting-my-django-website</link><guid isPermaLink="true">https://blog.samjdrew.com/devlog-1-hosting-my-django-website</guid><category><![CDATA[Django]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Elastic Beanstalk]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 28 Jul 2024 23:39:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1722209875937/7e3266f7-2f7a-4a8a-95aa-2e1b949b3970.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h6 id="heading-setting">Setting</h6>
<p>I've been working on a photography website as a project to force myself to actually learn Django. I enjoy coding and I love taking shitty photos but I've never deigned to host my own work anywhere other than Instagram. By setting a project for myself like this, not only do I hope I become less sucky at working with Django, a necessary skill in my particular role at my workplace, one ancillary outcome is that I get to host my photos somewhere more permanently.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722207261766/e0b2308b-ee31-4ad6-8729-451f7a75b54a.png" alt="The progenitor website starting page" /></p>
<p><em>The progenitor website starting page</em></p>
<p>It has three views.</p>
<ul>
<li><p>Starting page: Shows the three most recent photos</p>
</li>
<li><p>All photos: Shows all uploaded photos</p>
</li>
<li><p>Photo detail: Displays a single image with white margins</p>
</li>
</ul>
<p>That's all it does right now. The photos are currently placeholders, <strong>They are</strong> my photos and they will appear in the final product but these particular photos are jpegs that have undergone at least 2x rounds of edits (jpeg's lossy compression gets applied for every edit + save). To be honest, they look fine to me but I'll want make sure the final product looks as good as I can make it. All static files (like the photos) are hosted locally for now. The plan is to put them in an S3 and get Django or Nginx to fetch them.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722207354434/48691a1c-16fe-46fc-9275-6de27bdd4d5b.png" alt class="image--center mx-auto" /></p>
<p><em>Photo detail view</em></p>
<h6 id="heading-resourcing">Resourcing</h6>
<p>Deciding on hosting raises some conflicting feelings. I want to take advantage of my somewhat working knowledge of AWS systems... but I also don't want to over-engineer this site that will likely only be visited by myself, my wife and a handful of job recruiters that actually vet me. I've never actually done this before either. So I'm not taking any shortcuts, nor am I jumping into architectures I have absolutely no business using.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208467302/7855f6ff-2ffb-4093-8707-e48194e028b6.png" alt="Resourcing initial ✨idea✨" class="image--center mx-auto" /></p>
<p><em>Resourcing initial ✨idea✨</em></p>
<p>This is the basic plan. Chuck it on a tiny EC2. SQLite database to hold all the photo details including the S3 key (so it knows where to reach for it in the S3 bucket). The S3 bucket is just a regular bucket with public access blocked. I'll need to allow the server to access the photos on it via API key. Lets flesh this out a bit.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208549238/2efa9fa4-9ebf-4c1d-bdce-ef37694a17c2.png" alt="Resourcing ideal version 1" class="image--center mx-auto" /></p>
<p><em>Resourcing ideal version 1</em></p>
<p>So I'm just using SQLite. This is a file-base database system. No need for a dedicated server which simplifies deployment drastically. The drawback here is that it's not quite as fast as a dedicated DB server like Postgres or MySQL would be. So I might have some delays in fetch times as the website grows. However, at this scale I think this will be fine. Similarly, hosting my photos on an S3 bucket means no need to spin up an additional private server. S3 is by far the cheapest option for file storage (probably) and the drawbacks are outweighed at this stage by my chief desires to spend no money and do no work.</p>
<h6 id="heading-first-deployment">First Deployment</h6>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208583028/da4acee0-6b6e-449c-ae54-45cd984df1a6.png" alt="My Django website's Elastic Beanstalk environment overview" /></p>
<p><em>My Django website's Elastic Beanstalk environment overview</em></p>
<p>Alright, I'm cheating. I'm using a barebone Elastic beanstalk application to spin up my EC2 in an "autoscaling group" of 1 instance, no DB, no VPC, no security groups. Just what is needed. In defence of my laziness, this is all I need at this stage. I wanted it live. It's now live (almost)</p>
<h6 id="heading-deployment-woes">Deployment Woes</h6>
<p>Right off the bat I ran into some problems getting a response from the EC2 instance deployed by elastic beanstalk. After re-deploying 4 times, re-checking my configuration each time, I was fed up. I've been working in AWS too long to get stuck at first deployment. Let's diagnose.</p>
<p>Elastic beanstalk is telling me it's deployed the EC2, added an EIP and added the EC2 to the environment. Good... So what's wrong? The problem is that AWS is getting no responses from the instance. Not just from the Nginx server, but from the whole instance. That tells me it's not connected to the internet. Lets check the instance settings.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208642147/58037f25-2fc9-4d4b-824c-40fc562a2b69.png" alt /></p>
<p><em>Django website app EC2 instance Networking tab</em></p>
<p>Seeeeems fine... I didn't set any VPC settings so Elastic Beanstalk has taken care of all that for me. Let's look at the VPC and see if it has an Internet gateway.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208658547/58dcdef9-f716-4cb5-af28-d6363f75a1e1.png" alt /></p>
<p><em>Internet gateway generated by Elastic Beanstalk</em></p>
<p>Okay... is it routed?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208674410/074865d6-1d07-4f2f-b911-f8ce74ed9bad.png" alt /></p>
<p><em>Route table generated by Elastic Beanstalk</em></p>
<p>So that's weird right? There should be a route there for outbound packages (anything not going to 172.31.0.0/16). But there's not. Elastic Beanstalk generated everything I asked and then some, but stopped short of actually connecting the VPC to the internet. Let's add it in manually.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208681520/df2c95aa-1387-4a89-a482-cd44fb7cef53.png" alt /></p>
<p><em>Route table with added route out to the internet gateway</em></p>
<p>I'll cut to the chase. That solved the issue. With my instance now connected to the internet, Elastic Beanstalk is getting responses and I'm able to connect on the default domain it's given me.</p>
<h6 id="heading-ill-leave-it-there-for-today">I'll leave it there for today</h6>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1722208727031/1380f952-5d2e-4a8a-89f8-974917cdb671.png" alt /></p>
<p><em>Literally best website you've ever seen</em></p>
<p>After adding the DNS entries for my domain and sorting out SSL, my site is officially on the web. I'm putting out my dirty html for the world to see. Instead of S3 hosting the images, the Nginx server on the EC2 is currently serving the sample images I loaded in with the code. I have many tasks left to do, but for today, this is enough.</p>
]]></content:encoded></item><item><title><![CDATA[Oh *THAT* Extension, it's called "Emmet"]]></title><description><![CDATA[How to fix html boilerplate extension in vs code after installing Django extension for the Django Templating Language: A very specific help article
I'm looking for why something in my code editor broke. It's late, I have work tomorrow, and this can w...]]></description><link>https://blog.samjdrew.com/oh-that-extension-its-called-emmet</link><guid isPermaLink="true">https://blog.samjdrew.com/oh-that-extension-its-called-emmet</guid><category><![CDATA[#emmet #html #htmlelemnts #boilerplate ]]></category><category><![CDATA[vscode extensions]]></category><category><![CDATA[coding]]></category><category><![CDATA[Django]]></category><category><![CDATA[django rest framework]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 12 May 2024 12:09:30 GMT</pubDate><content:encoded><![CDATA[<h3 id="heading-how-to-fix-html-boilerplate-extension-in-vs-code-after-installing-django-extension-for-the-django-templating-language-a-very-specific-help-article">How to fix html boilerplate extension in vs code after installing Django extension for the Django Templating Language: A very specific help article</h3>
<p>I'm looking for why something in my code editor broke. It's late, I have work tomorrow, and this can wait until after then. So naturally I will not rest until I find a satisfactory answer. Sometimes I try to give these things a solid go of my own before I turn my brain off and ask google.</p>
<p>After banging my head against the screen for far too long, I finally gave up. I'll sacrifice this golden nugget of a learning opportunity for a few more moments of sleep. So I ask google, What is it? Why have my html scaffolds stopped working because I installed the <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=batisteo.vscode-django">Django extension</a> in VS Code?<br />This thing:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715988088784/734efb0b-9e4d-40ed-aaf8-1167088f9106.png" alt class="image--center mx-auto" /></p>
<p>I used to be able to just type "html" into an empty file and vs code, putting on it's best mother hen impression, would help the poor baby who's clearly about to hurt himself (yes I'm the poor baby). Anyway, this is the boilerplate:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Document<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Turns out vs code by default has an extension that is where that html boilerplate was coming from. If you're looking closely, you might've already spotted where this extension announces itself.</p>
<p>The Django extension makes Django templating language the default "language" used when working in html files and that breaks it.</p>
<p>But is there a solution (other than just pick which extension you want more)? Well let's look back at the extension details page. "instructions for Emmet"? I had skimmed this. must be irrelevant. never heard of it. Don't use it. those instructions aren't for me...</p>
<p>Emmet. It's called Emmet. Not "html scaffolding". Not "html-boilerplate". Friggin "Emmet". bro.</p>
<p>All this to say learning people's names is already hard. Don't drag tech into this by giving it people names! Give us a hint at least! In the settings, in your extension descriptions, give the project subtitle or something. A hint whatever.</p>
<p>For those wondering I'll add some instructions here:</p>
<h3 id="heading-the-recipe">The Recipe:</h3>
<p>After installing Django extension and finding your html boilerplate is no longer being generated:</p>
<ol>
<li><p>Go into your user or workspace settings and search for 'Emmet: Include languages'</p>
</li>
<li><p>Add an Item 'django-html' with Value of 'html' to the table like this:</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715990133448/9887d8f7-d9d4-4258-a46e-add492e56dc2.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>That's it. Try making a blank html again. Tell your friends.</p>
</li>
</ol>
<p>I get this is a niche issue that not many people will ever run into. No one is writing a html document from scratch. But just in case, there you go.</p>
<p>Anyway, many thanks to Baptiste Darthenay for the Django extension for vs code. Works great.</p>
]]></content:encoded></item><item><title><![CDATA[Its AWS Time Baby]]></title><description><![CDATA[I've been working in AWS for over 2 years now, and I've always put off acquiring my official AWS certification. I've known it's a worthwhile goal and ever since I started working with cloud applications, I've wanted to do it. Nevertheless, I fall bac...]]></description><link>https://blog.samjdrew.com/its-aws-time-baby</link><guid isPermaLink="true">https://blog.samjdrew.com/its-aws-time-baby</guid><category><![CDATA[AWS]]></category><category><![CDATA[AWS certification]]></category><category><![CDATA[Solutions architecture]]></category><dc:creator><![CDATA[Samuel Drew]]></dc:creator><pubDate>Sun, 17 Dec 2023 23:40:31 GMT</pubDate><content:encoded><![CDATA[<p>I've been working in AWS for over 2 years now, and I've always put off acquiring my official AWS certification. I've known it's a worthwhile goal and ever since I started working with cloud applications, I've <em>wanted</em> to do it. Nevertheless, I fall back to that famous sentiment, the well-worn axiom wielded by the slightly too busy: "I'll do it later".</p>
<p>Well, it's officially later, and I'm starting my AWS Solutions Architect exam prep today. I <em>was</em> going to schedule my AWS Cloud Practitioner exam but that's the foundational certification. It's aimed towards business/marketing majors and professionals from a "non-IT" background.</p>
<p>It's the base level of competency and I've already been operating in that capacity for the past 2+ years.</p>
<blockquote>
<p>Do you have 1-3 years of IT or STEM background? Start with: An Associate-level AWS Certification that aligns with your role or interests. Outcome: Validation of AWS Cloud knowledge and skills; confidence and credibility to build your cloud career.</p>
</blockquote>
<p>Looking at the <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs/AWS_certification_paths.pdf">Certification Paths</a> recommended by AWS, It's recommended that individuals in my position skip the cloud practitioner certification and go straight to an associate-level cert like <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs-dev-associate/AWS-Certified-Developer-Associate_Exam-Guide.pdf">Developer</a> or <a target="_blank" href="https://d1.awsstatic.com/training-and-certification/docs-sa-assoc/AWS-Certified-Solutions-Architect-Associate_Exam-Guide.pdf">Solutions Architect</a>. I'd like to get both and also go for the DevOps professional-level cert (What AWS calls the pathway of the "Application Architect") but I'm pretty sure associate-level and higher exams cost over 200AUD so we'll see. At the very least, I need to decide which one to go for right now.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1702854691685/fb0999e7-1653-43a2-b1e4-c613ec8cdd1f.png" alt class="image--center mx-auto" /></p>
<p>The Solutions Architect role looks to be almost exactly what I've been doing for the past 2 years. Just better. The Developer role, however, seems almost fundamental to getting a tech job but is also not quite as familiar to me.</p>
<p>For now, I'll begin the Solutions Architect exam prep. Solutions Architect will be the fastest to achieve and I can always do the developer one afterwards (if I have the time and funding). I'll be updating this blog as I go with my learnings and thoughts.</p>
]]></content:encoded></item></channel></rss>