<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CI\CD on Brian Braatz Blog</title><link>https://brianbraatz.github.io/categories/ci%5Ccd/</link><description>Recent content in CI\CD on Brian Braatz Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 18 Mar 2025 22:47:31 +0000</lastBuildDate><atom:link href="https://brianbraatz.github.io/categories/ci%5Ccd/index.xml" rel="self" type="application/rss+xml"/><item><title>Python + C# Microservices in AWS -Bitbucket, Bamboo and Octopus</title><link>https://brianbraatz.github.io/p/python-and-csharp-microservice-bitbucket-bamboo-octopus/</link><pubDate>Wed, 04 Dec 2019 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/python-and-csharp-microservice-bitbucket-bamboo-octopus/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/pythoncsharpmicroservicebamboooctopus.png" alt="Featured image of post Python + C# Microservices in AWS -Bitbucket, Bamboo and Octopus" />&lt;!--
# Full Example of Python and C# Microservice that Has a Method That Divides Numbers
## Introduction
So, you've got two numbers, and you want to divide them? Great! But instead of just using a calculator like a normal person, let’s over-engineer this into a full-blown **microservice** with **Python and C#**, deploy it to **AWS**, and automate the whole thing with **CI/CD pipelines using Bitbucket, Bamboo, and Octopus Deploy**. Because... why not? 🚀
-->
&lt;h2 id="python-microservice-in-aws-with-bitbucket--bamboo-and-octopus">Python Microservice in AWS with Bitbucket, Bamboo and Octopus
&lt;/h2>&lt;p>In this glorious adventure, we’ll:&lt;/p>
&lt;ol>
&lt;li>Build a simple microservice in &lt;strong>Python&lt;/strong> and &lt;strong>C#&lt;/strong> that divides two numbers.&lt;/li>
&lt;li>Package it up and deploy it to &lt;strong>AWS&lt;/strong> using &lt;strong>Infrastructure as Code (IaC)&lt;/strong>.&lt;/li>
&lt;li>Set up a &lt;strong>CI/CD pipeline&lt;/strong> to automate the deployment using &lt;strong>Bitbucket, Bamboo, and Octopus Deploy&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="step-1-build-the-microservices">Step 1: Build the Microservices
&lt;/h2>&lt;h3 id="python-microservice-">Python Microservice 🐍
&lt;/h3>&lt;p>Let’s keep it simple with &lt;strong>FastAPI&lt;/strong>, because who has time for Flask boilerplate?&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">fastapi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">FastAPI&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">HTTPException&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">app&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">FastAPI&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nd">@app.get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;/divide&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">divide&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nb">float&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="n">HTTPException&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">status_code&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">400&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">detail&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;Division by zero is not allowed!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;result&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kn">import&lt;/span> &lt;span class="nn">uvicorn&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">uvicorn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">app&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">host&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;0.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">port&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">8000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Run it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">uvicorn main:app --host 0.0.0.0 --port &lt;span class="m">8000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Test it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">curl &lt;span class="s2">&amp;#34;http://localhost:8000/divide?a=10&amp;amp;b=2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-microservice-">C# Microservice 🤖
&lt;/h3>&lt;p>Now let’s write the same thing in &lt;strong>ASP.NET Core&lt;/strong>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.AspNetCore.Mvc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">[ApiController]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">[Route(&amp;#34;api&amp;#34;)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">DivideController&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">ControllerBase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na"> [HttpGet(&amp;#34;divide&amp;#34;)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">IActionResult&lt;/span> &lt;span class="n">Divide&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="n">FromQuery&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">FromQuery&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="p">==&lt;/span> &lt;span class="m">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">BadRequest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Division by zero is not allowed!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">a&lt;/span> &lt;span class="p">/&lt;/span> &lt;span class="n">b&lt;/span> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Run it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">dotnet run
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Test it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">curl &lt;span class="s2">&amp;#34;http://localhost:5000/api/divide?a=10&amp;amp;b=2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Boom! Two microservices ready. Let’s move on. 💪&lt;/p>
&lt;hr>
&lt;h2 id="step-2-deploy-to-aws-with-infrastructure-as-code-iac">Step 2: Deploy to AWS with Infrastructure as Code (IaC)
&lt;/h2>&lt;p>We’ll use &lt;strong>Terraform&lt;/strong> for this. Here’s a sample &lt;strong>Terraform&lt;/strong> script to deploy an &lt;strong>EC2 instance&lt;/strong> with Docker.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;us-east-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34; &amp;#34;microservice&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="err">&amp;lt;&amp;lt;-&lt;/span>&lt;span class="k">EOF&lt;/span>&lt;span class="c1">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"> #!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">docker&lt;/span> &lt;span class="k">run&lt;/span> &lt;span class="err">-&lt;/span>&lt;span class="k">d&lt;/span> &lt;span class="err">-&lt;/span>&lt;span class="k">p&lt;/span> &lt;span class="m">8000&lt;/span>&lt;span class="err">:&lt;/span>&lt;span class="m">8000&lt;/span> &lt;span class="k">my&lt;/span>&lt;span class="err">-&lt;/span>&lt;span class="k">python&lt;/span>&lt;span class="err">-&lt;/span>&lt;span class="k">microservice&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Apply it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">terraform init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">terraform apply
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Boom! Microservice is on AWS. ☁️&lt;/p>
&lt;hr>
&lt;h2 id="step-3-automate-with-cicd-bitbucket--bamboo--octopus">Step 3: Automate with CI/CD (Bitbucket + Bamboo + Octopus)
&lt;/h2>&lt;h3 id="bitbucket-pipelines">&lt;strong>Bitbucket Pipelines&lt;/strong>
&lt;/h3>&lt;p>Add this to &lt;code>.bitbucket-pipelines.yml&lt;/code> to automate testing and building.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">python:3.9&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">pipelines&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">default&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">step&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">pip install -r requirements.txt&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">pytest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="bamboo-cicd">&lt;strong>Bamboo CI/CD&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>Create a &lt;strong>Bamboo Plan&lt;/strong>.&lt;/li>
&lt;li>Add a &lt;strong>Build Step&lt;/strong> to run tests.&lt;/li>
&lt;li>Add a &lt;strong>Deployment Step&lt;/strong> to push to AWS.&lt;/li>
&lt;/ol>
&lt;h3 id="octopus-deploy">&lt;strong>Octopus Deploy&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>Create a &lt;strong>Deployment Process&lt;/strong>.&lt;/li>
&lt;li>Define &lt;strong>Environments&lt;/strong> (Dev, Staging, Prod).&lt;/li>
&lt;li>Add an &lt;strong>AWS Deployment Target&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="key-ideas-table">&lt;strong>Key Ideas Table&lt;/strong>
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Step&lt;/th>
&lt;th>Description&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Build Microservice&lt;/td>
&lt;td>Python (FastAPI) and C# (ASP.NET Core)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Deploy to AWS&lt;/td>
&lt;td>Using Terraform for Infrastructure as Code&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Automate CI/CD&lt;/td>
&lt;td>Bitbucket Pipelines, Bamboo, Octopus&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">&lt;strong>Reference Links&lt;/strong>
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://fastapi.tiangolo.com/">https://fastapi.tiangolo.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/">https://docs.microsoft.com/en-us/aspnet/core/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://bitbucket.org/">https://bitbucket.org/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://octopus.com/">https://octopus.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>There you go! 🎉 A &lt;strong>Python &amp;amp; C# Microservice&lt;/strong>, &lt;strong>AWS Deployment&lt;/strong>, and &lt;strong>CI/CD Automation&lt;/strong>. Now go forth and divide… your workload! 😆&lt;/p></description></item><item><title>8 Unusual Things You COULD Do with Infrastructure as Code</title><link>https://brianbraatz.github.io/p/10-unusual-things-you-can-do-with-infrastructure-as-code/</link><pubDate>Wed, 17 May 2023 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/10-unusual-things-you-can-do-with-infrastructure-as-code/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/weirdthingsiasc.jpg" alt="Featured image of post 8 Unusual Things You COULD Do with Infrastructure as Code" />&lt;h1 id="8-unusual-things-you-could-do-with-infrastructure-as-code">8 Unusual Things You COULD Do with Infrastructure as Code
&lt;/h1>&lt;!--
## Introduction
You know Infrastructure as Code (IaC) is great for spinning up AWS servers, managing Kubernetes clusters, and making DevOps people look like wizards. But did you know it can also do some **pretty weird and wild things**? That’s right—IaC isn’t just about deploying boring ol’ cloud infrastructure. It can be used in **unexpected, hilarious, and even borderline ridiculous ways**. 🎩✨
In this article, we’re going to cover:
- A brief **history of IaC** (because nerd cred is important)
- **10 bizarre things** you can do with it
- Some code samples (because why not?)
Buckle up, it’s about to get weird. 🚀
---
-->
&lt;h2 id="a-quick-history-of-infrastructure-as-code">A Quick History of Infrastructure as Code
&lt;/h2>&lt;p>Before IaC, deploying infrastructure was like assembling IKEA furniture &lt;strong>without instructions&lt;/strong>. Sysadmins manually configured everything, leading to errors, inconsistencies, and existential dread. 😵‍💫&lt;/p>
&lt;p>Then, in the 2010s, tools like &lt;strong>AWS CloudFormation (2011)&lt;/strong> and &lt;strong>Terraform (2014)&lt;/strong> changed everything. Suddenly, you could define your entire infrastructure &lt;strong>in code&lt;/strong>, store it in Git, and deploy it automatically. No more clicking around AWS like a lost intern.&lt;/p>
&lt;hr>
&lt;h3 id="1-deploy-a-minecraft-server-">1. &lt;strong>Deploy a Minecraft Server&lt;/strong> 🎮
&lt;/h3>&lt;p>Why manually set up a Minecraft server when &lt;strong>Terraform&lt;/strong> can do it for you? With IaC, you can spin up a dedicated EC2 instance, configure networking, and deploy Minecraft—all in a few lines of code.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34; &amp;#34;minecraft_server&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t3.medium&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> user_data&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;#!/bin/bash\nsudo yum install -y java\nsudo wget -O /home/ec2-user/minecraft_server.jar https://minecraft.net/latest.jar&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-schedule-happy-hour-reminders-in-slack-">2. &lt;strong>Schedule Happy Hour Reminders in Slack&lt;/strong> 🍻
&lt;/h3>&lt;p>Using &lt;strong>Ansible&lt;/strong>, you can automate sending Slack reminders every Friday at 4 PM.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Happy Hour Reminder&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">localhost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Send Slack Message&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">community.general.slack&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">token&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ slack_token }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">msg&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;It&amp;#39;s Friday! Time for a beer 🍺&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-automate-cat-picture-delivery-">3. &lt;strong>Automate Cat Picture Delivery&lt;/strong> 🐱
&lt;/h3>&lt;p>You can use &lt;strong>AWS Lambda and Terraform&lt;/strong> to set up a pipeline that fetches a random cat picture from an API and posts it to your Twitter every day. Because why not?&lt;/p>
&lt;h3 id="4-turn-your-lights-onoff-with-terraform-">4. &lt;strong>Turn Your Lights On/Off with Terraform&lt;/strong> 💡
&lt;/h3>&lt;p>Home automation? With &lt;strong>Pulumi&lt;/strong>, you can control your smart home devices via AWS IoT. A single config change can &lt;strong>turn your lights on and off&lt;/strong>.&lt;/p>
&lt;h3 id="5-create-a-server-that-self-destructs-">5. &lt;strong>Create a Server That Self-Destructs&lt;/strong> 💥
&lt;/h3>&lt;p>Want to deploy a self-destructing AWS EC2 instance? Just use an &lt;strong>auto-terminating Terraform script&lt;/strong> that deletes itself after 10 minutes. Great for security testing!&lt;/p>
&lt;h3 id="6-track-your-plants-watering-schedule-">6. &lt;strong>Track Your Plant’s Watering Schedule&lt;/strong> 🌱
&lt;/h3>&lt;p>Using &lt;strong>IoT + IaC&lt;/strong>, you can automate plant watering reminders or even integrate with a smart irrigation system.&lt;/p>
&lt;h3 id="7-spin-up-a-fake-company-website-for-fun-">7. &lt;strong>Spin Up a Fake Company Website for Fun&lt;/strong> 🏢
&lt;/h3>&lt;p>Ever wanted to prank your coworkers? Use &lt;strong>CloudFormation&lt;/strong> to deploy a static S3-hosted website for a fake company with official-looking branding.&lt;/p>
&lt;h3 id="8-automate-your-resume-deployment-">8. &lt;strong>Automate Your Resume Deployment&lt;/strong> 📄
&lt;/h3>&lt;p>Some developers &lt;strong>host their resumes on AWS S3&lt;/strong> and use &lt;strong>IaC to update it dynamically&lt;/strong> when they make Git commits. Smart move for job seekers!&lt;/p>
&lt;!--
---
## Key Ideas Table
| Idea | Description |
|------|-------------|
| **Minecraft Server** | Deploy a fully automated Minecraft server with Terraform |
| **Slack Happy Hour** | Send automated Friday happy hour reminders via Ansible |
| **Cat Picture Bot** | AWS Lambda posts cat pictures daily to Twitter |
| **Smart Lights Control** | Pulumi + IoT to turn lights on/off remotely |
| **Self-Destructing Server** | EC2 instances that delete themselves automatically |
| **Plant Watering Tracker** | IoT-based plant monitoring system |
| **Fake Company Website** | Deploy a prank corporate website using IaC |
| **Resume Automation** | Automatically update and deploy your resume with Git commits |
| **Personal Jukebox** | Terraform-managed streaming server for personal music |
| **Automated Tinder Bot** | AI-powered swiping bot using Selenium + AWS Lambda |
---
## Reference Links
- https://www.terraform.io/
- https://aws.amazon.com/cloudformation/
- https://www.pulumi.com/
- https://docs.ansible.com/
- https://www.minecraft.net/
---
## Conclusion
Who said **Infrastructure as Code** had to be boring? Sure, IaC is great for managing cloud infrastructure, but as we’ve seen, it can also do **some truly ridiculous and fun things**.
So the next time someone tells you that Terraform and Ansible are just for AWS deployments, tell them you’re using IaC to control your lights, send Slack messages, and run a Tinder bot. 😆
Now go forth and automate some weird stuff! 🚀
--></description></item><item><title>How I Took a Legacy App from Bare Metal to AWS</title><link>https://brianbraatz.github.io/p/legacy-app-from-bare-metal-to-aws/</link><pubDate>Wed, 05 Oct 2022 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/legacy-app-from-bare-metal-to-aws/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/awsdatacenter.jpg" alt="Featured image of post How I Took a Legacy App from Bare Metal to AWS" />&lt;h1 id="how-i-took-a-legacy-app-from-bare-metal-to-aws">How I Took a Legacy App from Bare Metal to AWS
&lt;/h1>&lt;h2 id="the-nightmare-i-walked-into">The Nightmare I Walked Into
&lt;/h2>&lt;p>I got hired as a software engineer at this job, with years of experience with AWS, Azure and Google Cloud..&lt;/p>
&lt;p>WRITING CLOUD CODE.. not doing a ton of DevOps&lt;/p>
&lt;p>In the interview they asked me &amp;ldquo;Hey, can you move our internal app to AWS?&amp;rdquo;.&lt;/p>
&lt;p>I said yes, having no idea what kind of mess I was walking into.&lt;/p>
&lt;p>Sure I ran old school websites (Early 2000&amp;rsquo;s) where we did crazy things to fix real time scaling business problem level issues&amp;hellip;&lt;/p>
&lt;p>The busiest site I worked on: I was Director of Engineering (and head coder ;) ) for a Meta\Dropbox Competitor.. Our Bandwidth bill was around $100K a month&amp;hellip; lots of users for us at least&amp;hellip;&lt;/p>
&lt;p>So we made alot of mistakes.. learned alot of lessons .. and used alot of Duct tape to solve problems..&lt;/p>
&lt;p>We moved MySql into a RAM drive to make it go faster.. To buy us time to clean up the sql code..&lt;br>
We did weird round robin tricks with client side code rotating app servers to try to scale..&lt;/p>
&lt;p>Good painful learning experiences&amp;hellip;..&lt;br>
And these hacks worked.. until the next probelm cropped up..&lt;/p>
&lt;p>I didnt get much sleep in those days..&lt;/p>
&lt;p>but that aside.. this new job was for a large 100,000 employee technolgy company &amp;hellip;&lt;/p>
&lt;p>And what the described in the interview didnt sound THAT bad&amp;hellip; It just sounded like some old code and a slow computer..&lt;/p>
&lt;p>Ill make a few code tweaks..&lt;/p>
&lt;p>Its just some api changes right? Local files into S3.. Reinstall the SQL Server and data into a cloud managed system..&lt;/p>
&lt;p>Fix it allup in an afternoon and be home for supper&amp;hellip;&lt;br>
(yes us old poeple say &amp;ldquo;supper&amp;rdquo;&amp;hellip;)&lt;/p>
&lt;p>SURE I can do this.. no problem&amp;hellip;&lt;/p>
&lt;p>hahah&lt;/p>
&lt;p>So they hired me&amp;hellip;&lt;/p>
&lt;p>Then i learned more about what I was dealing with &amp;hellip;&lt;/p>
&lt;p>This server was running on &lt;strong>a single server&lt;/strong> in a Sacramento data center, complete with &lt;strong>notepad instructions on the desktop&lt;/strong> for how the confiuration .. &lt;strong>MIGHT&lt;/strong> be setup&amp;hellip;..&lt;/p>
&lt;p>The original dev had tried to &amp;ldquo;scale&amp;rdquo; it by adding IT provisioned Virtual MAchines as App servers.. ,&lt;br>
but &lt;strong>the database and web server were running on the same ancient Celeron machine&lt;/strong>.&lt;/p>
&lt;p>AND the App Server VMs, were &lt;strong>MAKING CALLS BACK TO THE PHYSICAL SERVER FOR DATABASE ACCESS&lt;/strong>&lt;/p>
&lt;p>Umm.. ok&amp;hellip;&lt;/p>
&lt;p>Exactly how is that a goood idea?&lt;/p>
&lt;p>I am still not sure..&lt;/p>
&lt;p>Maybe its like if you mixed Horizontal Scaling with Quantum Mechanics&amp;hellip; ????&lt;/p>
&lt;hr>
&lt;p>Oh, and international users were complaining because, surprise surprise, Sacramento is &lt;em>not&lt;/em> great for global access.&lt;/p>
&lt;hr>
&lt;h2 id="step-1-cleaning-up-the-code">Step 1: Cleaning Up the Code
&lt;/h2>&lt;p>The first issue? The codebase looked like it was written &lt;strong>by someone in a hurry, in the dark, during an earthquake&lt;/strong>.&lt;/p>
&lt;h2 id="weird-things-i-found">Weird things I found:
&lt;/h2>&lt;h3 id="hardcoded-configurations-everywhere">&lt;strong>Hardcoded Configurations Everywhere&lt;/strong>
&lt;/h3>&lt;p>I found this:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;Server=localhost;Database=MyDB;User Id=admin;Password=SuperSecret&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Seriously?!&lt;/p>
&lt;h4 id="fix-move-everything-to-environment-variables--later--aws-secrets-manager">&lt;strong>Fix:&lt;/strong> Move everything to environment variables -later- AWS Secrets Manager.
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">Environment&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GetEnvironmentVariable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;DB_CONNECTION_STRING&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="tightly-coupled-code">&lt;strong>Tightly Coupled Code&lt;/strong>
&lt;/h3>&lt;p>Everything was jammed into a single class. Changing &lt;em>anything&lt;/em> broke &lt;em>everything&lt;/em>.&lt;/p>
&lt;h4 id="fix-dependency-injection">&lt;strong>Fix:&lt;/strong> Dependency injection.
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">ReportService&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="k">readonly&lt;/span> &lt;span class="n">IDataRepository&lt;/span> &lt;span class="n">_repo&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">ReportService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">IDataRepository&lt;/span> &lt;span class="n">repo&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_repo&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">repo&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now I could actually test stuff without breaking the whole app.&lt;/p>
&lt;h3 id="stateful-sessions">&lt;strong>Stateful Sessions&lt;/strong>
&lt;/h3>&lt;p>Session data was being stored &lt;em>on the web server&lt;/em>. This was not gonna scale too well..&lt;/p>
&lt;h4 id="fix-move-sessions-to-redis">&lt;strong>Fix:&lt;/strong> Move sessions to &lt;strong>Redis&lt;/strong>.
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">_cache&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;User&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">user&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MemoryCacheEntryOptions&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">SlidingExpiration&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">TimeSpan&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">FromMinutes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">30&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">});&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now, users wouldn’t be tied to a single instance.&lt;/p>
&lt;h2 id="step-2-moving-to-aws">Step 2: Moving to AWS
&lt;/h2>&lt;p>Now that the app was &lt;em>less&lt;/em> of a dumpster fire, it was time to migrate.&lt;/p>
&lt;p>After that I HIT the Books with DevOps and AWS Scaling&amp;hellip;..&lt;/p>
&lt;h3 id="auto-scaling-and-load-balancing">&lt;strong>Auto Scaling and Load Balancing&lt;/strong>
&lt;/h3>&lt;p>I set up an &lt;strong>Elastic Load Balancer (ELB)&lt;/strong> and &lt;strong>Auto Scaling Group (ASG)&lt;/strong> so AWS could spin up new instances as needed.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_autoscaling_group&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;my_app_asg&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">launch_configuration&lt;/span> = &lt;span class="nx">aws_launch_configuration&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">my_app_lc&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">min_size&lt;/span> = &lt;span class="m">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">max_size&lt;/span> = &lt;span class="m">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">desired_capacity&lt;/span> = &lt;span class="m">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>No more single-server nightmares.&lt;/p>
&lt;h3 id="cloudfront-for-performance">&lt;strong>CloudFront for Performance?&lt;/strong>
&lt;/h3>&lt;p>I tried adding &lt;strong>CloudFront&lt;/strong> to cache static assets, but that didn&amp;rsquo;t work on our Corporate Intranet.&lt;br>
(Here is how you could do it if it can work for you.)&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_cloudfront_distribution&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;my_app_cf&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">origin&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">domain_name&lt;/span> = &lt;span class="nx">aws_s3_bucket&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">my_app_static&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">bucket_regional_domain_name&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">origin_id&lt;/span> = &lt;span class="s2">&amp;#34;S3Origin&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>More on Cloudfront and why it doesnt play nicely with Intranets&lt;br>
&lt;a href="https://stackoverflow.com/questions/70556875/how-to-use-cloudfront-only-on-the-internal-network">https://stackoverflow.com/questions/70556875/how-to-use-cloudfront-only-on-the-internal-network&lt;/a>&lt;/p>
&lt;!--
### **Route 53 and CloudFront for Global Performance**
To fix the slow response times for users in India, I added **Route 53** (Private Hosted Zones) for geo-based routing.
I tried adding **CloudFront** to cache static assets, but that didnt work on our Corporate Intranet.
(Here is how you could do it if it can work for you.)
~~~terraform
resource "aws_cloudfront_distribution" "my_app_cf" {
origin {
domain_name = aws_s3_bucket.my_app_static.bucket_regional_domain_name
origin_id = "S3Origin"
}
}
~~~
More on Cloudfront and how it doesnt play nicely with Intranets
&lt;https://stackoverflow.com/questions/70556875/how-to-use-cloudfront-only-on-the-internal-network>
Now, users in India hit the **Mumbai AWS region**, while North America users got **US West**.
-->
&lt;h3 id="moving-the-database-to-aws-rds">&lt;strong>Moving the Database to AWS RDS&lt;/strong>
&lt;/h3>&lt;p>I moved the &lt;strong>database off the web server&lt;/strong> and into &lt;strong>AWS RDS (SQL Server)&lt;/strong>, where it belonged.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-terraform" data-lang="terraform">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_db_instance&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;my_app_db&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">allocated_storage&lt;/span> = &lt;span class="m">50&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">engine&lt;/span> = &lt;span class="s2">&amp;#34;sqlserver-se&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">instance_class&lt;/span> = &lt;span class="s2">&amp;#34;db.t3.medium&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now I had backups, failover, and no more single points of failure.&lt;/p>
&lt;h3 id="cicd-with-aws-codepipeline">&lt;strong>CI/CD with AWS CodePipeline&lt;/strong>
&lt;/h3>&lt;p>No more manual deployments! I set up &lt;strong>AWS CodePipeline&lt;/strong> so everything deployed automatically.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">stages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">actions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">BuildApp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">provider&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">CodeBuild&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">actions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">DeployToAWS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">provider&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">CodeDeploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="migrating-iis-and-the-celeron-web-server">Migrating IIS and the Celeron Web Server
&lt;/h2>&lt;p>Now, the biggest challenge—moving the &lt;strong>ASP.NET app running on IIS&lt;/strong> on that overworked Celeron machine.&lt;/p>
&lt;h3 id="containerizing-iis">&lt;strong>Containerizing IIS&lt;/strong>
&lt;/h3>&lt;p>First, I put the IIS-based ASP.NET application into a &lt;strong>Docker container&lt;/strong> to make deployment more consistent.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> mcr.microsoft.com/dotnet/framework/aspnet:4.8&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">WORKDIR&lt;/span>&lt;span class="s"> /inetpub/wwwroot&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> . .&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This way, we could move it &lt;strong>anywhere&lt;/strong> without worrying about system differences.&lt;/p>
&lt;h3 id="running-on-aws-elastic-beanstalk">&lt;strong>Running on AWS Elastic Beanstalk&lt;/strong>
&lt;/h3>&lt;p>To avoid the headache of managing IIS servers manually, I deployed the container to &lt;strong>AWS Elastic Beanstalk&lt;/strong>, which handles scaling and updates automatically.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">service&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">myapp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">platform&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Windows Server 2019 with IIS&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">option_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">aws:elasticbeanstalk:container:dotnet&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">EnableApplicationHealthCheck&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now, AWS managed the underlying instances, and I didn’t have to worry about IIS configs.&lt;/p>
&lt;h3 id="replacing-iis-with-aws-app-runner">&lt;strong>Replacing IIS with AWS App Runner&lt;/strong>
&lt;/h3>&lt;p>For long-term stability, I moved the app to &lt;strong>AWS App Runner&lt;/strong>, which allows running web applications without dealing with servers.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">service&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">myapp-service&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">instance_configuration&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cpu&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">memory&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">4GB&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">deployment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image_uri&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;&amp;lt;ECR_REPO_URI&amp;gt;:latest&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now, the app was &lt;strong>fully managed&lt;/strong>, &lt;strong>auto-scaled&lt;/strong>, and &lt;strong>not dependent on a single server&lt;/strong> anymore!&lt;/p>
&lt;h2 id="the-final-results">The Final Results
&lt;/h2>&lt;p>After months of refactoring, debugging, and questioning my life choices, the app was &lt;strong>fully running in AWS&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>It &lt;strong>auto-scales&lt;/strong> when needed.&lt;/li>
&lt;li>Users in India and North America both get &lt;strong>fast response times&lt;/strong>.&lt;/li>
&lt;li>No more single points of failure.&lt;/li>
&lt;/ul>
&lt;p>And most importantly—I &lt;strong>finally&lt;/strong> started to understand Modern DevOps.&lt;/p>
&lt;p>No more duct tape.. :)&lt;/p>
&lt;h2 id="key-takeaways">Key Takeaways
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Issue&lt;/th>
&lt;th>Solution&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Hardcoded Config Values&lt;/td>
&lt;td>Used environment variables and Secrets Manager&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tightly Coupled Code&lt;/td>
&lt;td>Introduced dependency injection&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Stateful Sessions&lt;/td>
&lt;td>Used Redis for distributed session storage&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Single-Server Bottleneck&lt;/td>
&lt;td>Implemented AWS Auto Scaling and Load Balancer&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Global Performance Issues&lt;/td>
&lt;td>Used Route 53 and CloudFront for faster access&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Database on Web Server&lt;/td>
&lt;td>Migrated to AWS RDS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Manual Deployments&lt;/td>
&lt;td>Set up CI/CD with AWS CodePipeline&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://aws.amazon.com/elastic-load-balancing/">https://aws.amazon.com/elastic-load-balancing/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/rds/">https://aws.amazon.com/rds/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/cloudfront/">https://aws.amazon.com/cloudfront/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/codepipeline/">https://aws.amazon.com/codepipeline/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Move a legacy IIS app to the AWS Cloud</title><link>https://brianbraatz.github.io/p/how-to-move-a-legacy-iis-app-to-the-aws-cloud/</link><pubDate>Sun, 14 Jan 2024 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/how-to-move-a-legacy-iis-app-to-the-aws-cloud/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/iistoaws.png" alt="Featured image of post Move a legacy IIS app to the AWS Cloud" />&lt;!--
# How to Move a legacy IIS app to the AWS Cloud with Beanstalk, App runner and docker
## A Brief History of IIS and the Cloud Wars
Ah, IIS. The web server that powered countless enterprise apps, intranet portals, and that one weird HR site that only worked in Internet Explorer. Microsoft’s **Internet Information Services (IIS)** has been around since the '90s, back when Windows NT ruled the corporate world and the only "cloud" we knew about was the one storing our MP3s on Napster. Fast forward a couple of decades, and suddenly, on-premises servers are about as trendy as dial-up internet. Welcome to the cloud era!
-->
&lt;p>If you&amp;rsquo;re still running an IIS app on some forgotten rack server in a basement, it’s time to bring it into the 21st century.&lt;/p>
&lt;!--
And what better way than by moving it to **AWS**? In this article, we’ll look at three ways to do it: **Elastic Beanstalk, App Runner, and Docker**. And, of course, we’ll throw in some code samples because what’s an article without some copy-paste magic?
--->
&lt;h2 id="why-move-iis-apps-to-aws">Why Move IIS Apps to AWS?
&lt;/h2>&lt;p>Before we jump into how, let’s talk about &lt;strong>why&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>No more &amp;ldquo;server room&amp;rdquo; that doubles as a storage closet.&lt;/strong> AWS takes care of infrastructure.&lt;/li>
&lt;li>&lt;strong>Scalability.&lt;/strong> Your app can handle Black Friday traffic spikes without breaking a sweat.&lt;/li>
&lt;li>&lt;strong>Security.&lt;/strong> AWS is much better at security than &amp;ldquo;Steve from IT&amp;rdquo; who still uses &amp;ldquo;password123&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Cost Savings.&lt;/strong> No more hardware replacements every few years.&lt;/li>
&lt;/ul>
&lt;h2 id="option-1-elastic-beanstalk--the-i-want-aws-to-do-everything-for-me-approach">Option 1: Elastic Beanstalk – The &amp;ldquo;I Want AWS to Do Everything for Me&amp;rdquo; Approach
&lt;/h2>&lt;p>Elastic Beanstalk is AWS’s &lt;strong>Platform-as-a-Service (PaaS)&lt;/strong>. It handles deployment, scaling, monitoring, and even updates. You just upload your app, sit back, and pretend you did something complex.&lt;/p>
&lt;h3 id="steps-to-deploy-an-iis-app-with-beanstalk">Steps to Deploy an IIS App with Beanstalk
&lt;/h3>&lt;ol>
&lt;li>Package your IIS app (as a &lt;strong>ZIP&lt;/strong> file or &lt;strong>Docker image&lt;/strong>).&lt;/li>
&lt;li>Create an Elastic Beanstalk environment.&lt;/li>
&lt;li>Deploy your app.&lt;/li>
&lt;/ol>
&lt;p>Here&amp;rsquo;s an example of deploying a &lt;strong>Dockerized&lt;/strong> IIS app:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">eb init -p docker my-iis-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">eb create my-iis-env
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">eb deploy
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Pros:&lt;/strong>&lt;br>
✔️ AWS handles everything – networking, load balancing, autoscaling.&lt;br>
✔️ Supports multiple environments (dev, staging, production).&lt;/p>
&lt;p>&lt;strong>Cons:&lt;/strong>&lt;br>
❌ Less flexibility if you need custom configurations.&lt;br>
❌ May cost more if you don’t optimize properly.&lt;/p>
&lt;h2 id="option-2-app-runner--the-i-just-want-to-run-my-app-approach">Option 2: App Runner – The &amp;ldquo;I Just Want to Run My App&amp;rdquo; Approach
&lt;/h2>&lt;p>AWS &lt;strong>App Runner&lt;/strong> is a fully managed service that lets you &lt;strong>run containerized applications&lt;/strong> without dealing with infrastructure. Think of it like AWS’s version of &lt;strong>Heroku&lt;/strong>.&lt;/p>
&lt;h3 id="steps-to-deploy-with-app-runner">Steps to Deploy with App Runner
&lt;/h3>&lt;ol>
&lt;li>Containerize your IIS app.&lt;/li>
&lt;li>Push the image to &lt;strong>Amazon Elastic Container Registry (ECR)&lt;/strong>.&lt;/li>
&lt;li>Create an App Runner service.&lt;/li>
&lt;/ol>
&lt;p>Example:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">aws apprunner create-service --service-name my-iis-app &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --source-configuration &lt;span class="s1">&amp;#39;ImageRepositoryType=ECR,ImageIdentifier=123456789.dkr.ecr.us-east-1.amazonaws.com/my-iis-app:latest&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Pros:&lt;/strong>&lt;br>
✔️ Super simple setup.&lt;br>
✔️ Auto-scaling without complex configs.&lt;/p>
&lt;p>&lt;strong>Cons:&lt;/strong>&lt;br>
❌ Limited customization options.&lt;br>
❌ Only supports containerized apps.&lt;/p>
&lt;h2 id="option-3-docker-on-ecs--the-i-like-control-but-not-too-much-approach">Option 3: Docker on ECS – The &amp;ldquo;I Like Control (But Not Too Much)&amp;rdquo; Approach
&lt;/h2>&lt;p>If you want more control over how your app runs but don’t want to deal with servers, AWS &lt;strong>Elastic Container Service (ECS)&lt;/strong> with &lt;strong>Fargate&lt;/strong> is a great choice. It lets you run Docker containers without managing servers.&lt;/p>
&lt;h3 id="steps-to-deploy-with-ecs">Steps to Deploy with ECS
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Containerize your IIS app:&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-dockerfile" data-lang="dockerfile">&lt;span class="line">&lt;span class="cl">&lt;span class="k">FROM&lt;/span>&lt;span class="s"> mcr.microsoft.com/windows/servercore/iis&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="k">COPY&lt;/span> ./my-app /inetpub/wwwroot&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="2">
&lt;li>&lt;strong>Push to ECR:&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">aws ecr create-repository --repository-name my-iis-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker tag my-iis-app:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/my-iis-app:latest
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/my-iis-app:latest
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="3">
&lt;li>&lt;strong>Deploy with ECS Fargate:&lt;/strong>&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">aws ecs create-cluster --cluster-name my-iis-cluster
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">aws ecs create-service --cluster my-iis-cluster --service-name my-iis-app &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --task-definition my-iis-task --launch-type FARGATE
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Pros:&lt;/strong>&lt;br>
✔️ Full control over environment variables, networking, logging.&lt;br>
✔️ No need to manage VMs.&lt;/p>
&lt;p>&lt;strong>Cons:&lt;/strong>&lt;br>
❌ Slightly more complex than Beanstalk or App Runner.&lt;br>
❌ Requires more AWS knowledge.&lt;/p>
&lt;h2 id="beanstalk-vs-app-runner-vs-ecs-which-one-to-choose">Beanstalk vs. App Runner vs. ECS: Which One to Choose?
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Elastic Beanstalk&lt;/th>
&lt;th>App Runner&lt;/th>
&lt;th>ECS (Fargate)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Ease of Use&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>⭐⭐⭐⭐⭐&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Flexibility&lt;/td>
&lt;td>⭐⭐⭐&lt;/td>
&lt;td>⭐⭐&lt;/td>
&lt;td>⭐⭐⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Scaling&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;td>⭐⭐⭐⭐⭐&lt;/td>
&lt;td>⭐⭐⭐⭐&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Best For&lt;/td>
&lt;td>Traditional apps&lt;/td>
&lt;td>Simple containerized apps&lt;/td>
&lt;td>High-control container apps&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="final-thoughts">Final Thoughts
&lt;/h2>&lt;p>Moving an old IIS app to AWS isn’t as scary as it sounds.&lt;/p>
&lt;p>Whether you choose &lt;strong>Beanstalk, App Runner, or ECS&lt;/strong>, you’ll be saving yourself from a future of on-prem server nightmares.&lt;/p>
&lt;p>Take that leap into the cloud, and maybe, just maybe, retire that ancient server that’s still running on Windows Server 2003.&lt;/p>
&lt;p>:)&lt;/p>
&lt;hr>
&lt;h3 id="key-ideas">Key Ideas
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Summary&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Elastic Beanstalk&lt;/td>
&lt;td>Easiest way to deploy IIS apps with AWS managing everything&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>App Runner&lt;/td>
&lt;td>Best for containerized apps with minimal setup&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ECS Fargate&lt;/td>
&lt;td>Best for full control over the deployment process&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h3 id="reference-links">Reference Links
&lt;/h3>&lt;ul>
&lt;li>&lt;a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html">https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.aws.amazon.com/apprunner/latest/dg/what-is-apprunner.html">https://docs.aws.amazon.com/apprunner/latest/dg/what-is-apprunner.html&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html">https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Azure DevOps-Continuous Integration &amp; Continuous Deployment</title><link>https://brianbraatz.github.io/p/setting-up-ci-cd-in-azure-devops/</link><pubDate>Tue, 12 Sep 2023 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/setting-up-ci-cd-in-azure-devops/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/azure.png" alt="Featured image of post Azure DevOps-Continuous Integration &amp; Continuous Deployment" />&lt;h1 id="setting-up-cicd-in-azure-devops">Setting up CI/CD in Azure DevOps
&lt;/h1>&lt;blockquote>
&lt;p>&amp;ldquo;Why did the developer break up with Git?&lt;br>
Because it had too many &lt;em>commit&lt;/em>ment issues!&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>Alright today we’re setting up CI/CD in &lt;strong>Azure DevOps&lt;/strong>—because manually deploying code is so 2010, and we have better things to do (like debugging why our code doesn’t work in production).&lt;/p>
&lt;p>This is basically the &lt;strong>Azure DevOps&lt;/strong> version of &lt;a href="https://brianbraatz.github.io/p/jenkins-cicd/">this Jenkins CI/CD guide&lt;/a>, but we’re replacing Jenkins with &lt;strong>Azure Pipelines&lt;/strong> because&amp;hellip; well, we like suffering slightly less.&lt;/p>
&lt;hr>
&lt;h2 id="what-is-cicd">What is CI/CD?
&lt;/h2>&lt;p>CI/CD is Continuous Integration and Continuous Deployment (or Delivery). It’s the magical process that ensures your code moves smoothly from your laptop (where it &amp;ldquo;works perfectly&amp;rdquo;) to production (where it immediately catches fire).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Continuous Integration (CI)&lt;/strong> → Developers push code changes frequently, and automation ensures everything is tested before merging.&lt;/li>
&lt;li>&lt;strong>Continuous Deployment (CD)&lt;/strong> → Once the code is tested, it&amp;rsquo;s automatically deployed, so you can focus on more important things, like why your API suddenly has a 500 error.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="setting-up-azure-devops">Setting Up Azure DevOps
&lt;/h2>&lt;p>First, you need an &lt;strong>Azure DevOps&lt;/strong> account. If you don’t have one, go to &lt;a href="https://dev.azure.com/">Azure DevOps&lt;/a> and sign up—it’s free for small teams, and Microsoft hasn’t yet figured out how to charge us for breathing.&lt;/p>
&lt;h3 id="step-1-create-a-new-project">Step 1: Create a New Project
&lt;/h3>&lt;ol>
&lt;li>In &lt;strong>Azure DevOps&lt;/strong>, click &lt;strong>New Project&lt;/strong>.&lt;/li>
&lt;li>Give it a name, like &lt;code>&amp;quot;MyCoolProject&amp;quot;&lt;/code> or &lt;code>&amp;quot;YetAnotherBuggyApp&amp;quot;&lt;/code>.&lt;/li>
&lt;li>Choose &lt;strong>Git&lt;/strong> for version control (because what else would you use, TFVC?!).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="setting-up-the-cicd-pipeline">Setting Up the CI/CD Pipeline
&lt;/h2>&lt;p>Azure DevOps uses &lt;strong>Azure Pipelines&lt;/strong> for CI/CD, which is basically Microsoft’s version of Jenkins but with more YAML and fewer plugins.&lt;/p>
&lt;h3 id="step-2-create-a-build-pipeline">Step 2: Create a Build Pipeline
&lt;/h3>&lt;p>A build pipeline automates the compilation, testing, and artifact creation of your project.&lt;/p>
&lt;ol start="4">
&lt;li>Go to &lt;strong>Pipelines&lt;/strong> &amp;gt; &lt;strong>New Pipeline&lt;/strong>.&lt;/li>
&lt;li>Choose &lt;strong>GitHub&lt;/strong> (or &lt;strong>Azure Repos Git&lt;/strong> if you’re fancy).&lt;/li>
&lt;li>Select your repo and configure the pipeline using &lt;strong>YAML&lt;/strong> (Yes, it&amp;rsquo;s YAML—brace yourself).&lt;/li>
&lt;/ol>
&lt;h4 id="example-yaml-for-a-net-project">Example YAML for a .NET Project
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">trigger&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">pool&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">vmImage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;ubuntu-latest&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">task&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">UseDotNet@2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">inputs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">packageType&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;sdk&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;7.x&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dotnet build --configuration Release&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">displayName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;Build Project&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">dotnet test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">displayName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;Run Tests&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">task&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">PublishBuildArtifacts@1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">inputs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pathToPublish&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;bin/Release/net7.0&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">artifactName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;drop&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This will:&lt;br>
✅ Run the build on &lt;strong>Ubuntu&lt;/strong> (because we like free things).&lt;br>
✅ Install &lt;strong>.NET SDK 7.x&lt;/strong>.&lt;br>
✅ Build the project.&lt;br>
✅ Run tests (so you can see them fail).&lt;br>
✅ Publish the artifacts for deployment.&lt;/p>
&lt;hr>
&lt;h2 id="setting-up-the-release-pipeline">Setting Up the Release Pipeline
&lt;/h2>&lt;p>The release pipeline deploys your app after a successful build.&lt;/p>
&lt;h3 id="step-3-create-a-release-pipeline">Step 3: Create a Release Pipeline
&lt;/h3>&lt;ol start="7">
&lt;li>Go to &lt;strong>Releases&lt;/strong> &amp;gt; &lt;strong>New Pipeline&lt;/strong>.&lt;/li>
&lt;li>Use the &lt;strong>Empty job&lt;/strong> template (because we’re starting fresh).&lt;/li>
&lt;li>Add an &lt;strong>Artifact&lt;/strong> source (pick the &lt;code>drop&lt;/code> artifact from your build pipeline).&lt;/li>
&lt;/ol>
&lt;h3 id="step-4-add-deployment-stage">Step 4: Add Deployment Stage
&lt;/h3>&lt;ol start="10">
&lt;li>Click &lt;strong>Stage 1&lt;/strong> and rename it to something like &lt;code>&amp;quot;Deploy to Staging&amp;quot;&lt;/code> (or &lt;code>&amp;quot;Deploy and Pray&amp;quot;&lt;/code>).&lt;/li>
&lt;li>Add a deployment task.&lt;/li>
&lt;li>If deploying to &lt;strong>Azure App Service&lt;/strong>, use the &lt;code>Azure App Service Deploy&lt;/code> task.&lt;/li>
&lt;li>Configure it with your &lt;strong>Azure subscription&lt;/strong>, &lt;strong>App Service name&lt;/strong>, and &lt;strong>artifact location&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;h4 id="example-deployment-yaml">Example Deployment YAML
&lt;/h4>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">stages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>- &lt;span class="nt">stage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">job&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">DeployJob&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">pool&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">vmImage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;ubuntu-latest&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">steps&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">task&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">AzureRmWebAppDeployment@4&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">inputs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">azureSubscription&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;MyAzureSubscription&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">appType&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;webApp&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">appName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;my-cool-app&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">package&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;$(Build.ArtifactStagingDirectory)/drop&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="adding-a-deployment-trigger">Adding a Deployment Trigger
&lt;/h2>&lt;p>Since we don’t want to manually trigger deployments like cavemen, let’s make it automatic:&lt;/p>
&lt;ol start="14">
&lt;li>Click on your release pipeline.&lt;/li>
&lt;li>Add a trigger to deploy on successful builds.&lt;/li>
&lt;li>Enable &lt;strong>Continuous Deployment trigger&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="running-the-cicd-pipeline">Running the CI/CD Pipeline
&lt;/h2>&lt;p>Now, push a change to your &lt;code>main&lt;/code> branch, sit back, and watch:&lt;/p>
&lt;ol start="17">
&lt;li>&lt;strong>Build starts&lt;/strong> → Installs dependencies, compiles code, and runs tests.&lt;/li>
&lt;li>&lt;strong>Artifact is created&lt;/strong> → This is your deployable package.&lt;/li>
&lt;li>&lt;strong>Release starts&lt;/strong> → Deploys the artifact to your server.&lt;/li>
&lt;li>&lt;strong>Something breaks in production&lt;/strong> → You debug, cry, fix, repeat.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="summary-of-key-ideas">Summary of Key Ideas
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>CI/CD automates builds, testing, and deployments&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Azure DevOps Pipelines&lt;/strong> replaces Jenkins for CI/CD.&lt;/li>
&lt;li>&lt;strong>YAML-based Pipelines&lt;/strong> handle the entire process.&lt;/li>
&lt;li>&lt;strong>Deployment is automated&lt;/strong> so you can focus on more debugging.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="references">References
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://learn.microsoft.com/en-us/azure/devops/">Azure DevOps Documentation&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema">Azure Pipelines YAML Syntax&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://brianbraatz.github.io/p/jenkins-cicd/">The Original Jenkins CI/CD Guide&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Jenkins Setup-Continuous Integration and Deployment CICD</title><link>https://brianbraatz.github.io/p/jenkins-cicd/</link><pubDate>Sun, 05 Jan 2020 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/jenkins-cicd/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/jenkinsloho.png" alt="Featured image of post Jenkins Setup-Continuous Integration and Deployment CICD" />&lt;h2 id="a-brief-history-of-jenkins">A Brief History of Jenkins
&lt;/h2>&lt;p>Jenkins, the beloved but sometimes infuriating CI/CD tool, was born out of necessity.&lt;/p>
&lt;p>Back in 2004, Kohsuke Kawaguchi, a Sun Microsystems engineer, was tired of breaking builds and getting yelled at by his team.&lt;/p>
&lt;p>So, like any good developer, he built a tool to automate the pain away.&lt;/p>
&lt;p>This tool was originally called &lt;strong>Hudson&lt;/strong>, but after some corporate drama with Oracle, it was forked and renamed &lt;strong>Jenkins&lt;/strong> in 2011.&lt;/p>
&lt;p>Since then, it has become the go-to tool for continuous integration and deployment.&lt;/p>
&lt;p>(Fun note- Hudson was the version I learned initially :) - Yes.. I am old )&lt;/p>
&lt;h2 id="what-is-continuous-integration-and-continuous-deployment-cicd">What is Continuous Integration and Continuous Deployment (CI/CD)?
&lt;/h2>&lt;p>Continuous Integration (CI) is like having a really strict but fair coding buddy who immediately runs tests whenever you push code.&lt;/p>
&lt;p>If your code fails, it tells you instantly, saving you from merging a disaster into production.&lt;/p>
&lt;p>Continuous Deployment (CD) takes it a step further and says, “Hey, your code passed?&lt;/p>
&lt;p>Let’s deploy it to production automatically.” This ensures that software is always in a deployable state, with minimal human intervention.&lt;/p>
&lt;p>In short: &lt;strong>CI catches problems early, and CD ensures you’re always ready to ship.&lt;/strong>&lt;/p>
&lt;h2 id="setting-up-a-sample-microservice">Setting Up a Sample Microservice
&lt;/h2>&lt;p>Before Jenkins can do anything useful, we need something to build and test.&lt;/p>
&lt;p>Let&amp;rsquo;s create a simple C# microservice that exposes a REST API to divide two numbers. If you try to divide by zero, it will yell at you—because math.&lt;/p>
&lt;h3 id="c-microservice-code">C# Microservice Code
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.AspNetCore.Mvc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">[ApiController]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">[Route(&amp;#34;api/[controller]&lt;/span>&lt;span class="s">&amp;#34;)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s">&lt;/span>&lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">MathController&lt;/span> &lt;span class="p">:&lt;/span> &lt;span class="n">ControllerBase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na"> [HttpGet(&amp;#34;divide&amp;#34;)]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">IActionResult&lt;/span> &lt;span class="n">Divide&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">double&lt;/span> &lt;span class="n">a&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">double&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">b&lt;/span> &lt;span class="p">==&lt;/span> &lt;span class="m">0&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">BadRequest&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Division by zero is not allowed!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">a&lt;/span> &lt;span class="p">/&lt;/span> &lt;span class="n">b&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="unit-tests-for-the-microservice">Unit Tests for the Microservice
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Xunit&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.AspNetCore.Mvc&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">MathTests&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na"> [Fact]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="k">void&lt;/span> &lt;span class="n">Divide_ValidNumbers_ReturnsCorrectResult&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">controller&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MathController&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">controller&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Divide&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">2&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">OkObjectResult&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Assert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">NotNull&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Assert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Equal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">5.0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na"> [Fact]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="k">void&lt;/span> &lt;span class="n">Divide_ByZero_ReturnsBadRequest&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">controller&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">MathController&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">var&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">controller&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Divide&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">10&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">BadRequestObjectResult&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Assert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">NotNull&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Assert&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Equal&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Division by zero is not allowed!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="running-unit-tests-from-the-command-line">Running Unit Tests from the Command Line
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">dotnet &lt;span class="nb">test&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If all goes well, you’ll see some green checkmarks. If not, well, time to debug.&lt;/p>
&lt;h2 id="configuring-jenkins-to-monitor-git-and-build-code">Configuring Jenkins to Monitor Git and Build Code
&lt;/h2>&lt;ol>
&lt;li>Install Jenkins and necessary plugins (&lt;code>Git&lt;/code>, &lt;code>Pipeline&lt;/code>, &lt;code>Docker Pipeline&lt;/code>).&lt;/li>
&lt;li>Set up a new &lt;strong>Freestyle Project&lt;/strong> or a &lt;strong>Pipeline Project&lt;/strong>.&lt;/li>
&lt;li>Link it to your Git repository.&lt;/li>
&lt;li>Configure Jenkins to trigger a build when new code is pushed.&lt;/li>
&lt;/ol>
&lt;h3 id="example-jenkinsfile-for-cicd">Example Jenkinsfile for CI/CD
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">pipeline&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">agent&lt;/span> &lt;span class="n">any&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stages&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Clone Repository&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">git&lt;/span> &lt;span class="s1">&amp;#39;https://github.com/your-repo/math-service.git&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Build&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;dotnet build&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Test&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;dotnet test&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Dockerize and Deploy&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;docker build -t math-service .&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;docker run -d -p 5000:80 math-service&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Post-Deployment Test&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;./test-api.sh&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="what-happens-if-you-push-code-before-the-first-build-completes">What Happens if You Push Code Before the First Build Completes?
&lt;/h3>&lt;p>Chaos. Jenkins will either queue the new build or cancel the old one, depending on how it&amp;rsquo;s configured. Either way, you’ll probably get an email from your team.&lt;/p>
&lt;h2 id="where-does-jenkins-put-built-files">Where Does Jenkins Put Built Files?
&lt;/h2>&lt;p>Jenkins stores built artifacts in &lt;code>/var/lib/jenkins/workspace/&amp;lt;job-name&amp;gt;/&lt;/code> by default. You can configure it to store them elsewhere.&lt;/p>
&lt;h2 id="setting-up-failure-notifications">Setting Up Failure Notifications
&lt;/h2>&lt;p>To notify a human when the build fails, configure &lt;strong>Email Notifications&lt;/strong> or &lt;strong>Slack Webhooks&lt;/strong>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">post&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">failure&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">mail&lt;/span> &lt;span class="nl">to:&lt;/span> &lt;span class="s1">&amp;#39;devs@example.com&amp;#39;&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">subject:&lt;/span> &lt;span class="s1">&amp;#39;Jenkins Build Failed&amp;#39;&lt;/span>&lt;span class="o">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nl">body:&lt;/span> &lt;span class="s1">&amp;#39;Check Jenkins, something broke.&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="testing-the-api-after-deployment">Testing the API After Deployment
&lt;/h2>&lt;p>Create a simple test script:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">response&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>curl -s -o /dev/null -w &lt;span class="s2">&amp;#34;%{http_code}&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;http://localhost:5000/api/math/divide?a=10&amp;amp;b=2&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$response&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> -eq &lt;span class="m">200&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;API test passed!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;API test failed!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Make it executable:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">chmod +x test-api.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="deploying-to-docker-with-jenkins">Deploying to Docker with Jenkins
&lt;/h2>&lt;p>Modify the Jenkins pipeline to build and run the Docker container, then execute &lt;code>test-api.sh&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Post-Deployment Test&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;./test-api.sh&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="cleaning-up-after-docker-tests">Cleaning Up After Docker Tests
&lt;/h2>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Cleanup&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;docker stop math-service&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;docker rm math-service&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="retaining-files-in-jenkins">Retaining Files in Jenkins
&lt;/h2>&lt;p>Configure &lt;strong>Build Artifacts&lt;/strong> in Jenkins to retain compiled files:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Keep artifacts for a certain number of builds.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Use &amp;ldquo;Discard old builds&amp;rdquo; to prevent disk bloat.&lt;/strong>&lt;/li>
&lt;/ul>
&lt;h2 id="competing-cicd-tools">Competing CI/CD Tools
&lt;/h2>&lt;p>Jenkins isn&amp;rsquo;t the only player. Here are some alternatives:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GitHub Actions&lt;/strong> – Simple, integrated into GitHub.&lt;/li>
&lt;li>&lt;strong>GitLab CI/CD&lt;/strong> – Built-in CI for GitLab.&lt;/li>
&lt;li>&lt;strong>CircleCI&lt;/strong> – Cloud-based and fast.&lt;/li>
&lt;li>&lt;strong>Travis CI&lt;/strong> – Once great, now fading.&lt;/li>
&lt;li>&lt;strong>Azure DevOps&lt;/strong> – Microsoft’s answer to Jenkins.&lt;/li>
&lt;li>&lt;strong>TeamCity&lt;/strong> – Enterprise-grade CI/CD.&lt;/li>
&lt;/ul></description></item><item><title>Azure LAN to Cloud Project- Part 1 - Project Vision and Goals</title><link>https://brianbraatz.github.io/p/azure-lan-to-cloud-1-project-vision-and-goals/</link><pubDate>Tue, 03 Dec 2024 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/azure-lan-to-cloud-1-project-vision-and-goals/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/LanToCloud.png" alt="Featured image of post Azure LAN to Cloud Project- Part 1 - Project Vision and Goals" />&lt;!-- # Azure LAN to Cloud: Part 1 - Project Vision and Goals
-->
&lt;p>Welcome to the first installment of &lt;em>Azure LAN to Cloud&lt;/em>, where we embark on an adventure to build a simple social media application for a local network (LAN) and then migrate it to Microsoft Azure&amp;rsquo;s cloud platform.&lt;/p>
&lt;h2 id="why-this-series">Why This Series?
&lt;/h2>&lt;p>Cloud migration isn&amp;rsquo;t just about taking your code and saying, &lt;em>&amp;ldquo;Hey, server! Meet Azure.&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>No, no, no—it’s more like teaching a small-town LAN application to survive and thrive in the wild urban jungle of the cloud.&lt;/p>
&lt;p>The goal of this series is to explore what it really takes to move from a cozy local network to the vast, sometimes overwhelming Azure cloud.&lt;/p>
&lt;p>We’ll build an app that starts simple—a LAN-based social media chat application with image uploads and pushed chat updates—and then incrementally move it to Azure.&lt;/p>
&lt;p>Along the way, we&amp;rsquo;ll learn about infrastructure as code, cloud security, authentication, Azure services like Functions, Redis, and blob storage, and much more.&lt;/p>
&lt;h2 id="the-local-lan-application">The Local LAN Application
&lt;/h2>&lt;p>The application we start with will be deliberately simple but functional enough to mimic cloud features within a trusted LAN environment.&lt;/p>
&lt;p>Here&amp;rsquo;s what it will have:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Multi-user chat&lt;/strong>: Real-time chat with pushed updates.&lt;/li>
&lt;li>&lt;strong>Image uploads&lt;/strong>: Share those cat memes with friends.&lt;/li>
&lt;li>&lt;strong>Multiple channels&lt;/strong>: Like Slack, but without the enterprise-grade seriousness.&lt;/li>
&lt;li>&lt;strong>Simple authentication&lt;/strong>: Just a name—no passwords, no email, no fuss.&lt;/li>
&lt;/ol>
&lt;p>The LAN app will assume a trusted environment—like your home network—so security will be minimal.&lt;/p>
&lt;p>Users can choose any name, create any channel, and upload any image (yes, even that blurry vacation photo).&lt;/p>
&lt;h3 id="tech-stack-local-phase">Tech Stack (Local Phase)
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Python 3.11+&lt;/strong> (because Python is awesome)&lt;/li>
&lt;li>&lt;strong>Flask or FastAPI&lt;/strong> (still deciding which mood we’re in)&lt;/li>
&lt;li>&lt;strong>SQLite&lt;/strong> (keeping it simple for the LAN phase)&lt;/li>
&lt;li>&lt;strong>WebSockets&lt;/strong> for real-time updates&lt;/li>
&lt;li>&lt;strong>Basic HTML/JS&lt;/strong> for the client&lt;/li>
&lt;/ul>
&lt;p>We&amp;rsquo;ll avoid fancy features that don&amp;rsquo;t add educational value and focus on building a functional app that mimics cloud patterns.&lt;/p>
&lt;h2 id="the-cloud-migration-challenge">The Cloud Migration Challenge
&lt;/h2>&lt;p>Once the app is up and running locally, we&amp;rsquo;ll start the migration to Azure.&lt;/p>
&lt;p>If you&amp;rsquo;re picturing a smooth and easy transition—well, surprise!&lt;/p>
&lt;p>It won&amp;rsquo;t be.&lt;/p>
&lt;p>And that&amp;rsquo;s by design.&lt;/p>
&lt;p>Moving from LAN to cloud is a paradigm shift.&lt;/p>
&lt;p>In the LAN version, we can just push updates to everyone, store images locally, and keep a list of active channels in memory.&lt;/p>
&lt;p>But when we go cloud-side, these shortcuts become liabilities.&lt;/p>
&lt;h3 id="cloud-migration-goals">Cloud Migration Goals
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Real Authentication&lt;/strong>: Goodbye &lt;em>&amp;ldquo;What&amp;rsquo;s your name?&amp;rdquo;&lt;/em> Hello &lt;em>OAuth 2.0&lt;/em>.&lt;/li>
&lt;li>&lt;strong>Scalable Image Handling&lt;/strong>: Blob storage, CDNs, and Azure Functions.&lt;/li>
&lt;li>&lt;strong>Distributed State&lt;/strong>: Redis for chat state.&lt;/li>
&lt;li>&lt;strong>Infrastructure as Code&lt;/strong>: Azure Resource Manager (ARM) templates, Bicep, or Terraform.&lt;/li>
&lt;li>&lt;strong>Horizontal Scalability&lt;/strong>: Containers, Kubernetes, and Azure Functions.&lt;/li>
&lt;/ol>
&lt;h3 id="expected-headaches-aka-learning-opportunities">Expected Headaches (a.k.a. Learning Opportunities)
&lt;/h3>&lt;ul>
&lt;li>Migrating from SQLite to Azure SQL or CosmosDB.&lt;/li>
&lt;li>Debugging performance bottlenecks in the cloud.&lt;/li>
&lt;li>Implementing real-time chat across multiple nodes.&lt;/li>
&lt;li>Cost optimization because, well, cloud bills.&lt;/li>
&lt;/ul>
&lt;h2 id="the-plan-or-how-well-try-to-stay-organized">The Plan (or, How We’ll Try to Stay Organized)
&lt;/h2>&lt;p>The journey will unfold in phases:&lt;/p>
&lt;h3 id="phase-1-local-lan-app">Phase 1: Local LAN App
&lt;/h3>&lt;ul>
&lt;li>Build a basic Python chat app with image uploads.&lt;/li>
&lt;li>Test and document the core features.&lt;/li>
&lt;li>Explore basic architecture patterns that mimic cloud behavior.&lt;/li>
&lt;/ul>
&lt;h3 id="phase-2-initial-cloud-migration">Phase 2: Initial Cloud Migration
&lt;/h3>&lt;ul>
&lt;li>Deploy the app on Azure App Service.&lt;/li>
&lt;li>Migrate data to Azure SQL/Blob Storage.&lt;/li>
&lt;li>Add basic authentication.&lt;/li>
&lt;/ul>
&lt;h3 id="phase-3-cloud-optimization">Phase 3: Cloud Optimization
&lt;/h3>&lt;ul>
&lt;li>Introduce Redis for state management.&lt;/li>
&lt;li>Scale horizontally with containers.&lt;/li>
&lt;li>Implement caching and performance tuning.&lt;/li>
&lt;/ul>
&lt;h3 id="phase-4-production-readiness">Phase 4: Production Readiness
&lt;/h3>&lt;ul>
&lt;li>Set up Azure DevOps pipelines.&lt;/li>
&lt;li>Use Infrastructure as Code to manage deployments.&lt;/li>
&lt;li>Add monitoring and logging.&lt;/li>
&lt;li>Follow Modern Security Practices
&lt;ul>
&lt;li>&lt;a href="https://brianbraatz.github.io/p/owasp-security-tools/">OWAS Tools In a Nutshell&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://brianbraatz.github.io/p/why-nist-matters-for-cloud-based-web-applications/">NIST Resources for Cloud Devs&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Integrate OWASP Tools into our pipeline
&lt;ul>
&lt;li>&lt;a href="https://brianbraatz.github.io/p/owasp-tools-pipeline/">OWASP tools Integration into the DevOps pipeline&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="phase-5-mobile--cross-cloud-exploration">Phase 5: Mobile &amp;amp; Cross-Cloud Exploration
&lt;/h3>&lt;ul>
&lt;li>Add a MAUI-based mobile app.&lt;/li>
&lt;li>Compare Azure with AWS and Google Cloud.&lt;/li>
&lt;/ul>
&lt;h2 id="why-azure">Why Azure?
&lt;/h2>&lt;p>I&amp;rsquo;ve been working with AWS and Azure since around 2008—back when Azure was simpler and cloud jargon didn’t require a dictionary.&lt;/p>
&lt;p>Azure, like AWS, has grown immensely, and with growth comes complexity.&lt;/p>
&lt;p>This series will give us a chance to explore Azure&amp;rsquo;s features without getting lost in the complexity jungle.&lt;/p>
&lt;h2 id="whats-next">What’s Next?
&lt;/h2>&lt;p>In the next article, we’ll start building our LAN-based social media app.&lt;/p>
&lt;p>Expect some Python code, some architectural diagrams, and maybe a cat meme or two.&lt;/p>
&lt;p>&lt;strong>Stay tuned, and remember:&lt;/strong> The cloud isn’t scary—it’s just someone else’s computer.&lt;/p>
&lt;h2 id="key-ideas">Key Ideas
&lt;/h2>&lt;ul>
&lt;li>Build a LAN-based social media app with chat, images, and channels.&lt;/li>
&lt;li>Explore Azure services through a real migration process.&lt;/li>
&lt;li>Focus on practical, hands-on learning with a working app.&lt;/li>
&lt;li>Cover DevOps, Infrastructure as Code, and performance optimization.&lt;/li>
&lt;/ul>
&lt;h2 id="references">References
&lt;/h2>&lt;ol>
&lt;li>Microsoft Azure Documentation: &lt;a href="https://docs.microsoft.com/azure">https://docs.microsoft.com/azure&lt;/a>&lt;/li>
&lt;li>Python 3.11+ Official Documentation: &lt;a href="https://docs.python.org/3.11/">https://docs.python.org/3.11/&lt;/a>&lt;/li>
&lt;li>Flask Web Framework: &lt;a href="https://flask.palletsprojects.com/">https://flask.palletsprojects.com/&lt;/a>&lt;/li>
&lt;li>FastAPI Documentation: &lt;a href="https://fastapi.tiangolo.com/">https://fastapi.tiangolo.com/&lt;/a>&lt;/li>
&lt;li>Redis Documentation: &lt;a href="https://redis.io/documentation">https://redis.io/documentation&lt;/a>&lt;/li>
&lt;li>Docker Documentation: &lt;a href="https://docs.docker.com/">https://docs.docker.com/&lt;/a>&lt;/li>
&lt;li>Azure Functions: &lt;a href="https://docs.microsoft.com/azure/azure-functions">https://docs.microsoft.com/azure/azure-functions&lt;/a>&lt;/li>
&lt;li>MAUI Documentation: &lt;a href="https://learn.microsoft.com/en-us/dotnet/maui/">https://learn.microsoft.com/en-us/dotnet/maui/&lt;/a>&lt;/li>
&lt;li>OAuth 2.0 Framework: &lt;a href="https://oauth.net/2/">https://oauth.net/2/&lt;/a>&lt;/li>
&lt;li>Infrastructure as Code: &lt;a href="https://docs.microsoft.com/azure/azure-resource-manager/templates/overview">https://docs.microsoft.com/azure/azure-resource-manager/templates/overview&lt;/a>&lt;/li>
&lt;/ol>
&lt;!--
**See you in Part 2, where we get our hands dirty with some Python code!**
--></description></item><item><title>How Bamboo and Octopus Work Together</title><link>https://brianbraatz.github.io/p/understanding-bitbucket-bamboo-octopus/</link><pubDate>Mon, 30 Nov 2020 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/understanding-bitbucket-bamboo-octopus/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/bambooandoctopus.png" alt="Featured image of post How Bamboo and Octopus Work Together" />&lt;!--
# Understanding Bitbucket + Bamboo + Octopus, Their History and How They Relate to Each Other with Example Code
## Introduction
Alright, buckle up, because we’re about to take a ride through the magical world of **Bitbucket, Bamboo, and Octopus Deploy**—the ultimate power trio of modern software deployment. If you’ve ever wondered how these three work together like a rock band of DevOps, this article is for you. 🎸🔥
We’ll cover:
- The **history** of each tool (because knowing where they came from makes you sound smart in meetings 😎).
- How they **connect** and work together.
- Example **CI/CD pipelines** using these tools.
- Why Octopus Deploy is **not** a seafood restaurant. 🐙
Let’s dive in!
-->
&lt;hr>
&lt;h2 id="the-history-of-each-tool">The History of Each Tool
&lt;/h2>&lt;h3 id="bitbucket---git-repo-hosting-by-atlassian">&lt;strong>Bitbucket 🏗️ – Git Repo Hosting by Atlassian&lt;/strong>
&lt;/h3>&lt;p>Once upon a time (2008, to be exact), Bitbucket was born as a &lt;strong>Mercurial&lt;/strong>-based repository hosting service.&lt;/p>
&lt;p>But, since nobody outside of a few stubborn devs really cared about Mercurial, Atlassian acquired it in &lt;strong>2010&lt;/strong> and gave it a &lt;strong>Git makeover&lt;/strong>. Now, it’s one of the big Git repo hosting services, standing alongside GitHub and GitLab.&lt;/p>
&lt;p>👉 &lt;strong>Think of Bitbucket as:&lt;/strong> The cool storage locker where all your code lives before it gets deployed.&lt;/p>
&lt;p>More on Bitbucket: &lt;a href="https://bitbucket.org/">https://bitbucket.org/&lt;/a>&lt;/p>
&lt;h3 id="bamboo---cicd-for-the-atlassian-world">&lt;strong>Bamboo 🎋 – CI/CD for the Atlassian World&lt;/strong>
&lt;/h3>&lt;p>Atlassian created &lt;strong>Bamboo&lt;/strong> as an alternative to Jenkins because, let’s be honest, Jenkins is great but looks like it belongs in Windows 95.&lt;/p>
&lt;p>Bamboo was built to integrate smoothly with Bitbucket, Jira, and other Atlassian tools. It provides &lt;strong>CI/CD pipelines&lt;/strong> with a slick UI and &lt;strong>deep integrations&lt;/strong> with source control.&lt;/p>
&lt;p>👉 &lt;strong>Think of Bamboo as:&lt;/strong> The conveyor belt in your software factory, making sure your code gets tested and built correctly before it ships.&lt;/p>
&lt;p>More on Bamboo: &lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/p>
&lt;h3 id="octopus-deploy---the-deployment-powerhouse">&lt;strong>Octopus Deploy 🐙 – The Deployment Powerhouse&lt;/strong>
&lt;/h3>&lt;p>Founded in &lt;strong>2012&lt;/strong>, Octopus Deploy is an &lt;strong>independent deployment automation tool&lt;/strong>. While Bitbucket and Bamboo handle the &lt;strong>coding and building&lt;/strong>,&lt;/p>
&lt;p>Octopus takes care of the actual &lt;strong>deployment&lt;/strong>. It specializes in multi-environment releases (like Dev, Staging, Production) and supports &lt;strong>auto-rollback, variable scoping, and approvals&lt;/strong>.&lt;/p>
&lt;p>👉 &lt;strong>Think of Octopus as:&lt;/strong> The expert delivery guy making sure your software package is delivered safely—whether to Kubernetes, AWS, or a bunch of VMs.&lt;/p>
&lt;p>More on Octopus Deploy: &lt;a href="https://octopus.com/">https://octopus.com/&lt;/a>&lt;/p>
&lt;hr>
&lt;h2 id="how-they-work-together">How They Work Together
&lt;/h2>&lt;p>Here’s a high-level overview of how Bitbucket, Bamboo, and Octopus &lt;strong>collaborate&lt;/strong> in a CI/CD pipeline:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Bitbucket&lt;/strong> – Developers push their code to a Bitbucket repository.&lt;/li>
&lt;li>&lt;strong>Bamboo&lt;/strong> – Detects the new code, runs automated tests, and builds the application.&lt;/li>
&lt;li>&lt;strong>Octopus Deploy&lt;/strong> – Takes the successfully built artifact and deploys it to environments like Staging or Production.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="cicd-example-bitbucket--bamboo--octopus">CI/CD Example: Bitbucket + Bamboo + Octopus
&lt;/h2>&lt;h3 id="1-bitbucket-pipelines-optional">&lt;strong>1. Bitbucket Pipelines (Optional)&lt;/strong>
&lt;/h3>&lt;p>If you’re not using Bamboo yet, you can have Bitbucket Pipelines handle initial builds.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mcr.microsoft.com/dotnet/sdk:6.0&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">pipelines&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">default&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">step&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">dotnet build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">dotnet test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-bamboo-build-plan">&lt;strong>2. Bamboo Build Plan&lt;/strong>
&lt;/h3>&lt;p>In Bamboo:&lt;/p>
&lt;ol>
&lt;li>Create a &lt;strong>new plan&lt;/strong> and connect it to your &lt;strong>Bitbucket repo&lt;/strong>.&lt;/li>
&lt;li>Add a &lt;strong>build step&lt;/strong>:
&lt;ul>
&lt;li>Use a &lt;strong>Docker container&lt;/strong> or &lt;strong>build script&lt;/strong>.&lt;/li>
&lt;li>Run tests and package the app.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Artifact Sharing&lt;/strong> – Save the build output so Octopus Deploy can use it.&lt;/li>
&lt;/ol>
&lt;h3 id="3-octopus-deploy-process">&lt;strong>3. Octopus Deploy Process&lt;/strong>
&lt;/h3>&lt;ol>
&lt;li>Define &lt;strong>Environments&lt;/strong> (e.g., Dev, Staging, Prod).&lt;/li>
&lt;li>Create a &lt;strong>Release Pipeline&lt;/strong>:
&lt;ul>
&lt;li>Pulls build artifacts from Bamboo.&lt;/li>
&lt;li>Deploys to &lt;strong>Kubernetes, AWS ECS, Azure, or on-prem servers&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Set up &lt;strong>Approval Steps&lt;/strong> if needed.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="key-ideas-table">&lt;strong>Key Ideas Table&lt;/strong>
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Step&lt;/th>
&lt;th>Description&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Bitbucket&lt;/td>
&lt;td>Git-based repo hosting from Atlassian&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bamboo&lt;/td>
&lt;td>CI/CD automation and build pipelines&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Octopus Deploy&lt;/td>
&lt;td>Deployment automation and release management&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Integration&lt;/td>
&lt;td>Bitbucket triggers Bamboo; Bamboo builds and sends artifacts to Octopus Deploy&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Example Code&lt;/td>
&lt;td>Bitbucket Pipelines YAML, Bamboo Build Plan, Octopus Deployment&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">&lt;strong>Reference Links&lt;/strong>
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://bitbucket.org/">https://bitbucket.org/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://octopus.com/">https://octopus.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.atlassian.com/git/tutorials/what-is-version-control">https://www.atlassian.com/git/tutorials/what-is-version-control&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="final-thoughts">&lt;strong>Final Thoughts&lt;/strong>
&lt;/h2>&lt;p>Bitbucket, Bamboo, and Octopus work &lt;strong>best together&lt;/strong> like peanut butter, jelly, and bread. Bitbucket stores your code, Bamboo makes sure it actually works, and Octopus gets it where it needs to go. If you’re looking for a &lt;strong>solid, battle-tested CI/CD setup&lt;/strong>, this trio is a fantastic choice.&lt;/p>
&lt;p>Now go forth and automate your deployments like a &lt;strong>DevOps wizard!&lt;/strong> 🧙‍♂️✨&lt;/p></description></item><item><title>Ansible in a nutshell</title><link>https://brianbraatz.github.io/p/ansible-in-a-nutshell/</link><pubDate>Mon, 11 Nov 2019 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/ansible-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/ansible.png" alt="Featured image of post Ansible in a nutshell" />&lt;h1 id="ansible-in-a-nutshell">Ansible in a Nutshell
&lt;/h1>&lt;h2 id="what-is-ansible">What is Ansible?
&lt;/h2>&lt;p>Ansible is like a magic wand for system administrators.&lt;/p>
&lt;p>You write some YAML, wave your SSH key, and boom!&lt;/p>
&lt;p>Servers are configured, applications are deployed, and your DevOps team thinks you’re a genius (until they see your YAML indentation errors). (hahaha)&lt;/p>
&lt;h2 id="a-brief-history-of-ansible-or-how-we-got-here">A Brief History of Ansible (Or How We Got Here)
&lt;/h2>&lt;p>Ansible was created in 2012 by Michael DeHaan, who must have been tired of writing the same Bash scripts over and over.&lt;/p>
&lt;p>Instead of spending hours debugging shell scripts, he decided to make a tool that could automate infrastructure easily, with no agents or extra dependencies. Thus, Ansible was born!&lt;/p>
&lt;p>(Software engineers had tedious things - so we invent things.. sometimes people use our things and think our things are too tedious&amp;hellip; so they invent more things.. the world is full of things&amp;hellip; and this is why&amp;hellip;.)&lt;/p>
&lt;p>In 2015, Red Hat acquired Ansible, proving that if you make a good enough open-source tool, eventually someone will throw money at you.&lt;/p>
&lt;h2 id="infrastructure-as-code-iac---the-big-picture">Infrastructure as Code (IaC) - The Big Picture
&lt;/h2>&lt;p>If you’ve ever heard the phrase “treat your servers like cattle, not pets,” then you already get the gist of Infrastructure as Code. Instead of manually configuring each server like a delicate bonsai tree, IaC lets you define everything in code so that it can be automated, version-controlled, and replicated.&lt;/p>
&lt;p>Ansible takes this a step further by making sure you don’t need a Ph.D. in YAML just to get things working (though it helps).&lt;/p>
&lt;h2 id="how-does-ansible-compare-to-other-tools">How Does Ansible Compare to Other Tools?
&lt;/h2>&lt;h3 id="-ansible-vs-puppet">🏆 Ansible vs. Puppet
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Ansible&lt;/strong>: Agentless, uses SSH, simple to set up.&lt;/li>
&lt;li>&lt;strong>Puppet&lt;/strong>: Uses agents, requires a master node, more complex but powerful.&lt;/li>
&lt;/ul>
&lt;h3 id="-ansible-vs-chef">🏆 Ansible vs. Chef
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Ansible&lt;/strong>: Uses YAML (easy to read, but can be annoying to debug).&lt;/li>
&lt;li>&lt;strong>Chef&lt;/strong>: Uses Ruby (which means, if you’re not a Ruby dev, good luck).&lt;/li>
&lt;/ul>
&lt;h3 id="-ansible-vs-terraform">🏆 Ansible vs. Terraform
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Ansible&lt;/strong>: Great for configuration management and app deployment.&lt;/li>
&lt;li>&lt;strong>Terraform&lt;/strong>: Great for infrastructure provisioning (they actually work well together!).&lt;/li>
&lt;/ul>
&lt;h2 id="common-ansible-examples">Common Ansible Examples
&lt;/h2>&lt;h3 id="1-installing-packages">1. Installing Packages
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">web_servers&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apt&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-starting-a-service">2. Starting a Service
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Start and Enable Nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">web_servers&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Start Nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">service&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">nginx&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">started&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">enabled&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">yes&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-copying-a-file">3. Copying a File
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Copy Config File&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Copy nginx.conf&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">copy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">src&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">./nginx.conf&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">dest&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/etc/nginx/nginx.conf&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-running-a-shell-command">4. Running a Shell Command
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Check Disk Usage&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Run df command&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">command&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">df -h&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-creating-a-user">5. Creating a User
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Create a User&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Add User&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">user&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devops&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-deploying-an-app">6. Deploying an App
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy Web App&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">web_servers&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Pull latest code&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">git&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;https://github.com/example/repo.git&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">dest&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">/var/www/html&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-managing-firewall-rules">7. Managing Firewall Rules
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Open Port 80&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Allow HTTP traffic&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ufw&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rule&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">allow&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">port&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">80&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">proto&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">tcp&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-configuring-a-database">8. Configuring a Database
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Configure MySQL&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">db_servers&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Ensure MySQL is installed&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apt&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mysql-server&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-using-variables">9. Using Variables
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Custom Package&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">vars&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">package_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">htop&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install package&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apt&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{ package_name }}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-looping-over-tasks">10. Looping Over Tasks
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install Multiple Packages&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">all&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install common tools&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">apt&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">vim, curl, git]&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="key-ideas">Key Ideas
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Topic&lt;/th>
&lt;th>Summary&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>What is Ansible?&lt;/td>
&lt;td>A simple, agentless automation tool using YAML.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>History&lt;/td>
&lt;td>Created in 2012, acquired by Red Hat in 2015.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Infrastructure as Code&lt;/td>
&lt;td>Managing servers using code instead of manual setup.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Comparison&lt;/td>
&lt;td>Competes with Puppet, Chef, Terraform (but works well with Terraform).&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Common Usage&lt;/td>
&lt;td>Configuration management, deployment, provisioning.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.ansible.com/">https://docs.ansible.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/ansible/ansible">https://github.com/ansible/ansible&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.redhat.com/en/technologies/management/ansible">https://www.redhat.com/en/technologies/management/ansible&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Terraform in a Nutshell</title><link>https://brianbraatz.github.io/p/terraform-in-a-nutshell/</link><pubDate>Tue, 14 Sep 2021 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/terraform-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/terraform.png" alt="Featured image of post Terraform in a Nutshell" />&lt;h1 id="terraform-in-a-nutshell">Terraform in a Nutshell
&lt;/h1>&lt;h2 id="introduction">Introduction
&lt;/h2>&lt;p>Terraform: the Swiss Army knife of Infrastructure as Code (IaC). If you’ve ever wanted to &lt;strong>manage cloud infrastructure like a boss&lt;/strong> without manually clicking through AWS, Terraform is your new best friend.&lt;/p>
&lt;p>It automates the entire process, leaving you more time to drink coffee and pretend you’re fixing production issues. ☕🔥&lt;/p>
&lt;!--
In this article, we’ll cover:
- The **history** of Terraform
- How it stacks up against **competing and complementary tools**
- **10 super useful Terraform code examples**
So grab your YAML decoder ring, and let’s get started! 🚀
-->
&lt;hr>
&lt;h2 id="a-brief-history-of-terraform">A Brief History of Terraform
&lt;/h2>&lt;p>Back in the day (pre-2014), cloud provisioning was a wild, wild west of manual configurations and spaghetti scripts.&lt;/p>
&lt;p>Then, HashiCorp entered the scene with &lt;strong>Terraform&lt;/strong>, a tool that changed everything by introducing &lt;strong>declarative infrastructure as code&lt;/strong>. Instead of &lt;strong>imperative&lt;/strong> scripts (do X, then Y), Terraform lets you &lt;strong>define the desired end state&lt;/strong>, and it figures out the rest.&lt;/p>
&lt;p>Since then, it’s become the &lt;strong>de facto standard&lt;/strong> for managing cloud infrastructure, outshining other tools like AWS CloudFormation and Ansible for provisioning tasks.&lt;/p>
&lt;p>&lt;strong>Why is Terraform so popular?&lt;/strong>&lt;br>
✅ &lt;strong>Multi-cloud support&lt;/strong> – Works with AWS, Azure, GCP, Kubernetes, and even random things like Cloudflare DNS.&lt;br>
✅ &lt;strong>State management&lt;/strong> – Keeps track of infrastructure changes with a state file.&lt;br>
✅ &lt;strong>Modular&lt;/strong> – You can reuse Terraform code across projects.&lt;br>
✅ &lt;strong>Easy to learn&lt;/strong> – HCL (HashiCorp Configuration Language) is &lt;strong>simpler than YAML, JSON, or writing Bash scripts at 3 AM&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="terraform-vs-other-iac-tools">Terraform vs. Other IaC Tools
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Terraform&lt;/th>
&lt;th>CloudFormation&lt;/th>
&lt;th>Pulumi&lt;/th>
&lt;th>Ansible&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Multi-cloud&lt;/strong>&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>❌ AWS-only&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Declarative&lt;/strong>&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>❌ No (Imperative)&lt;/td>
&lt;td>❌ No (Imperative)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Programming Language&lt;/strong>&lt;/td>
&lt;td>HCL&lt;/td>
&lt;td>YAML/JSON&lt;/td>
&lt;td>Python/JS/Go&lt;/td>
&lt;td>YAML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best For&lt;/strong>&lt;/td>
&lt;td>Cloud provisioning&lt;/td>
&lt;td>AWS environments&lt;/td>
&lt;td>Devs who like real languages&lt;/td>
&lt;td>Configuration management&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>If you want to provision &lt;strong>multi-cloud infrastructure&lt;/strong>, use &lt;strong>Terraform&lt;/strong>. If you’re AWS-only, &lt;strong>CloudFormation&lt;/strong> is fine. If you prefer Python, try &lt;strong>Pulumi&lt;/strong>. If you just want to install packages, use &lt;strong>Ansible&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="10-common-terraform-code-examples">10 Common Terraform Code Examples
&lt;/h2>&lt;h3 id="1-provision-an-aws-ec2-instance">1. &lt;strong>Provision an AWS EC2 Instance&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;us-east-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34; &amp;#34;my_vm&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-create-an-s3-bucket">2. &lt;strong>Create an S3 Bucket&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket&amp;#34; &amp;#34;my_bucket&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-awesome-bucket&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> acl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;private&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-deploy-a-load-balancer">3. &lt;strong>Deploy a Load Balancer&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_lb&amp;#34; &amp;#34;my_lb&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-load-balancer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> internal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> load_balancer_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;application&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-spin-up-an-rds-database">4. &lt;strong>Spin Up an RDS Database&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_db_instance&amp;#34; &amp;#34;my_db&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> engine&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;postgres&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_class&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;db.t3.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> allocated_storage&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">20&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-provision-a-kubernetes-cluster-eks">5. &lt;strong>Provision a Kubernetes Cluster (EKS)&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_eks_cluster&amp;#34; &amp;#34;my_eks&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-cluster&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> role_arn&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">aws_iam_role&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">eks_role&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">arn&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-manage-dns-records-with-cloudflare">6. &lt;strong>Manage DNS Records with Cloudflare&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;cloudflare_record&amp;#34; &amp;#34;my_dns&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> zone_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;your-zone-id&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;A&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;192.168.1.1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-create-a-terraform-module">7. &lt;strong>Create a Terraform Module&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">module&lt;/span> &lt;span class="s2">&amp;#34;s3_bucket&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> source&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;terraform-aws-modules/s3-bucket/aws&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-modular-bucket&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-use-terraform-variables">8. &lt;strong>Use Terraform Variables&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">variable&lt;/span> &lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> default&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34; &amp;#34;my_vm&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">var&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">instance_type&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-set-up-auto-scaling">9. &lt;strong>Set Up Auto Scaling&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_autoscaling_group&amp;#34; &amp;#34;my_asg&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> desired_capacity&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> min_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> max_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">5&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-use-terraform-outputs">10. &lt;strong>Use Terraform Outputs&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">output&lt;/span> &lt;span class="s2">&amp;#34;instance_ip&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">aws_instance&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">my_vm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">public_ip&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="key-ideas-table">Key Ideas Table
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Explanation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Terraform&lt;/strong>&lt;/td>
&lt;td>Open-source IaC tool by HashiCorp&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-cloud support&lt;/strong>&lt;/td>
&lt;td>Works with AWS, Azure, GCP, Kubernetes, and more&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>Keeps track of infrastructure changes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>HCL&lt;/strong>&lt;/td>
&lt;td>HashiCorp’s configuration language for Terraform&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Comparison&lt;/strong>&lt;/td>
&lt;td>Competes with CloudFormation, Pulumi, and Ansible&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Example Uses&lt;/strong>&lt;/td>
&lt;td>Provisioning VMs, Load Balancers, Kubernetes, and DNS&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.pulumi.com/">https://www.pulumi.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;!--
## Conclusion
Terraform is **the ultimate tool** for managing cloud infrastructure at scale. Whether you’re deploying a simple **EC2 instance**, spinning up **Kubernetes clusters**, or automating **DNS management**, Terraform has your back. So go ahead, embrace automation, and let Terraform do the hard work while you take all the credit. 🚀
--></description></item><item><title>Azure Data Storage Compared Blob, File, Table, Cosmos DB, SQL</title><link>https://brianbraatz.github.io/p/azure-store-data/</link><pubDate>Tue, 05 Dec 2023 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/azure-store-data/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/azure2.png" alt="Featured image of post Azure Data Storage Compared Blob, File, Table, Cosmos DB, SQL" />&lt;p>So, you&amp;rsquo;re diving into Azure and wondering, &lt;em>&amp;ldquo;What&amp;rsquo;s the best way to store my precious data?&amp;rdquo;&lt;/em>&lt;/p>
&lt;h2 id="why-azure-for-data-storage">Why Azure for Data Storage?
&lt;/h2>&lt;p>Azure is like that fancy buffet with all-you-can-eat options for data storage. Whether you’re dealing with images, logs, documents, or structured data, Azure&amp;rsquo;s got you covered.&lt;/p>
&lt;p>Here&amp;rsquo;s the menu:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Blob Storage&lt;/strong>: For unstructured data like files, images, and videos.&lt;/li>
&lt;li>&lt;strong>File Storage&lt;/strong>: For network file shares.&lt;/li>
&lt;li>&lt;strong>Table Storage&lt;/strong>: For NoSQL key-value stores.&lt;/li>
&lt;li>&lt;strong>Cosmos DB&lt;/strong>: For scalable NoSQL databases.&lt;/li>
&lt;li>&lt;strong>SQL Database&lt;/strong>: For relational data.&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s dig into each of these with code samples in Python and C#.&lt;/p>
&lt;hr>
&lt;h2 id="1-azure-blob-storage-when-you-just-need-a-bucket-of-files-">1. Azure Blob Storage: When You Just Need a Bucket of Files 🪣
&lt;/h2>&lt;p>Blob Storage is perfect for when you need a place to dump files—think of it like a cloud-based USB drive.&lt;/p>
&lt;h3 id="python-code-">Python Code 🐍
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">azure.storage.blob&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">BlobServiceClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">connection_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">container_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-container&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">blob_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;hello.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Initialize client&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">BlobServiceClient&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_connection_string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connection_string&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">container_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_container_client&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">container_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Upload blob&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;hello.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;rb&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">container_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upload_blob&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">blob_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Blob uploaded successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-code-">C# Code ⚙️
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Azure.Storage.Blobs&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.IO&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">containerName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;my-container&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">blobName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;hello.txt&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BlobServiceClient&lt;/span> &lt;span class="n">blobServiceClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">BlobServiceClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connectionString&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">BlobContainerClient&lt;/span> &lt;span class="n">containerClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">blobServiceClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">GetBlobContainerClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">containerName&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">FileStream&lt;/span> &lt;span class="n">fs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">File&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">OpenRead&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello.txt&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">containerClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">UploadBlob&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">blobName&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">fs&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Blob uploaded successfully!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Blob Storage Verdict:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Great for unstructured data.&lt;/li>
&lt;li>Easily scalable.&lt;/li>
&lt;li>Not ideal if you need querying or indexing.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="2-azure-file-storage-your-cloud-based-shared-drive-">2. Azure File Storage: Your Cloud-Based Shared Drive 📂
&lt;/h2>&lt;p>Think of Azure File Storage as your network drive in the sky.&lt;/p>
&lt;h3 id="python-code--1">Python Code 🐍
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">azure.storage.fileshare&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">ShareFileClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">connection_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">share_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-share&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;notes.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">file_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ShareFileClient&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_connection_string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connection_string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">share_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;notes.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;rb&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">data&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">file_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">upload_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;File uploaded successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-code--1">C# Code ⚙️
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Azure.Storage.Files.Shares&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.IO&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">shareName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;my-share&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">fileName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;notes.txt&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">ShareFileClient&lt;/span> &lt;span class="n">fileClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">ShareFileClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connectionString&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">shareName&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">fileName&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">FileStream&lt;/span> &lt;span class="n">fs&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">File&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">OpenRead&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;notes.txt&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">fileClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Upload&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fs&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;File uploaded successfully!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>File Storage Verdict:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Perfect for shared file access.&lt;/li>
&lt;li>SMB protocol support.&lt;/li>
&lt;li>Not designed for large-scale analytics workloads.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-azure-table-storage-the-nosql-key-value-whisperer-">3. Azure Table Storage: The NoSQL Key-Value Whisperer 🔑
&lt;/h2>&lt;p>Azure Table Storage offers a super-simple NoSQL solution for key-value data.&lt;/p>
&lt;h3 id="python-code--2">Python Code 🐍
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">azure.data.tables&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">TableServiceClient&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TableEntity&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">connection_string&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">table_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;mytable&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Create table client&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">table_service&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TableServiceClient&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">from_connection_string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connection_string&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">table_client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">table_service&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get_table_client&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">table_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Insert entity&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">table_client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_entity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;PartitionKey&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;users&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;RowKey&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Entity inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-code--2">C# Code ⚙️
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Azure.Data.Tables&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;YourConnectionString&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">tableName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;mytable&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">TableClient&lt;/span> &lt;span class="n">tableClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">TableClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connectionString&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">tableName&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">var&lt;/span> &lt;span class="n">entity&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">TableEntity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;users&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="s">&amp;#34;Name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;Alice&amp;#34;&lt;/span> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span> &lt;span class="s">&amp;#34;Age&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">30&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">tableClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">AddEntity&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Entity inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Table Storage Verdict:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Simple and fast for key-value data.&lt;/li>
&lt;li>Great for logs and telemetry.&lt;/li>
&lt;li>Limited querying capabilities.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="4-azure-cosmos-db-the-swiss-army-knife-of-nosql-">4. Azure Cosmos DB: The Swiss Army Knife of NoSQL 🌌
&lt;/h2>&lt;p>Cosmos DB supports multiple NoSQL models with global distribution.&lt;/p>
&lt;h3 id="python-code--3">Python Code 🐍
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">azure.cosmos&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">CosmosClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">url&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourCosmosDBUrl&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">key&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourKey&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">database_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;mydb&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">container_name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;mycontainer&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CosmosClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">url&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">database&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_database_if_not_exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">database_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">container&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">database&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_container_if_not_exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">id&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">container_name&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">partition_key&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">PartitionKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/id&amp;#34;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">item&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">30&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">container&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">create_item&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Item inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-code--3">C# Code ⚙️
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.Azure.Cosmos&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Threading.Tasks&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">endpointUrl&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;YourCosmosDBUrl&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">primaryKey&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;YourKey&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">databaseName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;mydb&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">containerName&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;mycontainer&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CosmosClient&lt;/span> &lt;span class="n">cosmosClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">CosmosClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">endpointUrl&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">primaryKey&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Database&lt;/span> &lt;span class="n">database&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">cosmosClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CreateDatabaseIfNotExistsAsync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">databaseName&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Container&lt;/span> &lt;span class="n">container&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">await&lt;/span> &lt;span class="n">database&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CreateContainerIfNotExistsAsync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">containerName&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;/id&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">var&lt;/span> &lt;span class="n">item&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">id&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;Alice&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">age&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">30&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">await&lt;/span> &lt;span class="n">container&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CreateItemAsync&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">PartitionKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Item inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>Cosmos DB Verdict:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Supports various NoSQL models.&lt;/li>
&lt;li>Global distribution built-in.&lt;/li>
&lt;li>Pricier than Table Storage.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="5-azure-sql-database-old-school-relational-goodness-">5. Azure SQL Database: Old-School Relational Goodness 📊
&lt;/h2>&lt;p>When you need the comfort of good ol&amp;rsquo; SQL.&lt;/p>
&lt;h3 id="python-code--4">Python Code 🐍
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pyodbc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">server&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourServer&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">database&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;mydb&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">username&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourUsername&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">password&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;YourPassword&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">conn_str&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;DRIVER=&lt;/span>&lt;span class="se">{{&lt;/span>&lt;span class="s2">ODBC Driver 17 for SQL Server&lt;/span>&lt;span class="se">}}&lt;/span>&lt;span class="s2">;SERVER=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">server&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">;DATABASE=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">database&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">;UID=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">username&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">;PWD=&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">password&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">with&lt;/span> &lt;span class="n">pyodbc&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">connect&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">conn_str&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">conn&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">conn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cursor&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;CREATE TABLE IF NOT EXISTS Users (Id INT, Name NVARCHAR(50))&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cursor&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">execute&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;INSERT INTO Users (Id, Name) VALUES (?, ?)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;Alice&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">conn&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;SQL data inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="c-code--4">C# Code ⚙️
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">System.Data.SqlClient&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">connectionString&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;Server=&amp;lt;YourServer&amp;gt;;Database=mydb;User Id=&amp;lt;YourUsername&amp;gt;;Password=&amp;lt;YourPassword&amp;gt;;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">SqlConnection&lt;/span> &lt;span class="n">connection&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SqlConnection&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">connectionString&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">connection&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Open&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">createTableQuery&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;CREATE TABLE IF NOT EXISTS Users (Id INT, Name NVARCHAR(50))&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">string&lt;/span> &lt;span class="n">insertQuery&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;INSERT INTO Users (Id, Name) VALUES (1, &amp;#39;Alice&amp;#39;)&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">SqlCommand&lt;/span> &lt;span class="n">cmd&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">SqlCommand&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">createTableQuery&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">connection&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ExecuteNonQuery&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CommandText&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">insertQuery&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ExecuteNonQuery&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;SQL data inserted successfully!&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>SQL Database Verdict:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>The classic choice for relational data.&lt;/li>
&lt;li>Azure manages scaling, backups, and security.&lt;/li>
&lt;li>Requires schema design upfront.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h1 id="key-ideas">Key Ideas
&lt;/h1>&lt;ul>
&lt;li>Azure offers various storage options for different needs.&lt;/li>
&lt;li>Python and C# both have robust libraries for interacting with Azure.&lt;/li>
&lt;li>Blobs are great for files; tables are great for logs; Cosmos DB is fantastic for global apps.&lt;/li>
&lt;li>Choose based on your workload and data requirements.&lt;/li>
&lt;/ul>
&lt;h1 id="references">References
&lt;/h1>&lt;ol>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/storage/">Azure Storage Overview&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/storage/blobs/">Azure Blob Storage&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/storage/files/">Azure File Storage&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/storage/tables/">Azure Table Storage&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/cosmos-db/">Azure Cosmos DB&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/en-us/azure/azure-sql/">Azure SQL Database&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://pypi.org/project/azure-storage-blob/">Python SDK for Azure&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.nuget.org/packages/Azure.Storage.Blobs">C# SDK for Azure&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Azure- Tracing, Debugging, Troubleshooting, and Monitoring</title><link>https://brianbraatz.github.io/p/azure-logging-tracing/</link><pubDate>Mon, 05 Dec 2022 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/azure-logging-tracing/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/azureblack.png" alt="Featured image of post Azure- Tracing, Debugging, Troubleshooting, and Monitoring" />&lt;hr>
&lt;h2 id="1-tracing-follow-the-breadcrumbs">1. Tracing: Follow the Breadcrumbs
&lt;/h2>&lt;p>&lt;strong>Tracing&lt;/strong> is like leaving sticky notes throughout your codebase saying, &lt;em>&amp;ldquo;Hey, I was here, and I did this thing.&amp;rdquo;&lt;/em> It&amp;rsquo;s essential for understanding application flow and performance.&lt;/p>
&lt;h3 id="azure-tools-for-tracing">Azure Tools for Tracing
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Azure Monitor&lt;/strong>: Collects logs, metrics, and traces.&lt;/li>
&lt;li>&lt;strong>Application Insights&lt;/strong>: Great for distributed tracing.&lt;/li>
&lt;li>&lt;strong>Log Analytics&lt;/strong>: Query logs like a pro.&lt;/li>
&lt;/ul>
&lt;h3 id="best-practices-for-tracing">Best Practices for Tracing
&lt;/h3>&lt;ul>
&lt;li>Use &lt;strong>correlation IDs&lt;/strong> across services.&lt;/li>
&lt;li>Don’t log sensitive info. Nobody wants passwords exposed.&lt;/li>
&lt;li>Use structured logging (e.g., JSON) for better parsing.&lt;/li>
&lt;/ul>
&lt;h3 id="tracing-in-c">Tracing in C#
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.Extensions.Logging&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">public&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">MyService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">private&lt;/span> &lt;span class="k">readonly&lt;/span> &lt;span class="n">ILogger&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">MyService&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">_logger&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="n">MyService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ILogger&lt;/span>&lt;span class="p">&amp;lt;&lt;/span>&lt;span class="n">MyService&lt;/span>&lt;span class="p">&amp;gt;&lt;/span> &lt;span class="n">logger&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_logger&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">logger&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kd">public&lt;/span> &lt;span class="k">void&lt;/span> &lt;span class="n">ProcessData&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LogTrace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Starting data processing&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Do some work&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">_logger&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">LogTrace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Finished data processing&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="tracing-in-python">Tracing in Python
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">logging&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">basicConfig&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">level&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">DEBUG&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">logger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">logging&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getLogger&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="vm">__name__&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">process_data&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">debug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Starting data processing&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Do some work&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">logger&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">debug&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Finished data processing&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">process_data&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="what-works">What Works:
&lt;/h3>&lt;ul>
&lt;li>Azure Application Insights makes distributed tracing simple.&lt;/li>
&lt;li>Structured logs are easy to search.&lt;/li>
&lt;/ul>
&lt;h3 id="what-doesnt">What Doesn&amp;rsquo;t:
&lt;/h3>&lt;ul>
&lt;li>Over-logging can cause performance hits.&lt;/li>
&lt;li>Ignoring trace correlation in microservices makes debugging a nightmare.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="2-debugging-the-code-detective">2. Debugging: The Code Detective
&lt;/h2>&lt;p>Debugging is the art of staring at code until you find the bug… or the bug finds you.&lt;/p>
&lt;h3 id="azure-debugging-tools">Azure Debugging Tools
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Azure App Service Diagnostics&lt;/strong>: Interactive troubleshooting for web apps.&lt;/li>
&lt;li>&lt;strong>Azure DevOps&lt;/strong>: Integrated with Visual Studio.&lt;/li>
&lt;li>&lt;strong>Live Debugging with Azure Monitor&lt;/strong>: Debug apps without redeploying.&lt;/li>
&lt;/ul>
&lt;h3 id="best-practices">Best Practices
&lt;/h3>&lt;ul>
&lt;li>Reproduce issues locally whenever possible.&lt;/li>
&lt;li>Use remote debugging sparingly in production.&lt;/li>
&lt;li>Leverage exception tracking.&lt;/li>
&lt;/ul>
&lt;h3 id="debugging-in-c">Debugging in C#
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="m">10&lt;/span> &lt;span class="p">/&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Parse&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;0&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">Exception&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Console&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">WriteLine&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">$&amp;#34;Exception caught: {ex.Message}&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Add breakpoint here&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="debugging-in-python">Debugging in Python
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">10&lt;/span> &lt;span class="o">/&lt;/span> &lt;span class="mi">0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Exception caught: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Add a breakpoint here&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="what-works-1">What Works:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Visual Studio&lt;/strong>&amp;rsquo;s remote debugging is fantastic.&lt;/li>
&lt;li>Python&amp;rsquo;s &lt;code>pdb&lt;/code> debugger is simple yet powerful.&lt;/li>
&lt;/ul>
&lt;h3 id="what-doesnt-1">What Doesn&amp;rsquo;t:
&lt;/h3>&lt;ul>
&lt;li>Remote debugging production apps can degrade performance.&lt;/li>
&lt;li>Debugging containerized apps can be tricky if logging isn’t set up properly.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="3-troubleshooting-diagnosing-the-mystery">3. Troubleshooting: Diagnosing the Mystery
&lt;/h2>&lt;p>Troubleshooting is about going full-on &lt;em>CSI: Cloud Edition&lt;/em>. It involves analyzing patterns, logs, metrics, and errors.&lt;/p>
&lt;h3 id="azure-troubleshooting-tools">Azure Troubleshooting Tools
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Azure Service Health&lt;/strong>: Check Azure service status.&lt;/li>
&lt;li>&lt;strong>Azure Resource Health&lt;/strong>: Resource-specific diagnostics.&lt;/li>
&lt;li>&lt;strong>Kusto Query Language (KQL)&lt;/strong>: Query logs easily.&lt;/li>
&lt;/ul>
&lt;h3 id="best-practices-1">Best Practices
&lt;/h3>&lt;ul>
&lt;li>Automate alerts for key metrics.&lt;/li>
&lt;li>Use &lt;strong>KQL&lt;/strong> for pattern detection.&lt;/li>
&lt;li>Document common issues and their resolutions.&lt;/li>
&lt;/ul>
&lt;h3 id="troubleshooting-in-c">Troubleshooting in C#
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="nn">Microsoft.ApplicationInsights&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">var&lt;/span> &lt;span class="n">telemetryClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">telemetryClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">TrackException&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="n">Exception&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Test exception&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="troubleshooting-in-python">Troubleshooting in Python
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">applicationinsights&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;your_instrumentation_key&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">track_exception&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="what-works-2">What Works:
&lt;/h3>&lt;ul>
&lt;li>Automated alerts with Application Insights.&lt;/li>
&lt;li>KQL is incredibly powerful for investigating issues.&lt;/li>
&lt;/ul>
&lt;h3 id="what-doesnt-2">What Doesn&amp;rsquo;t:
&lt;/h3>&lt;ul>
&lt;li>Relying on manual log checks is exhausting.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="4-monitoring-watch-it-like-a-hawk">4. Monitoring: Watch It Like a Hawk
&lt;/h2>&lt;p>Monitoring is like being a helicopter parent, but for your application.&lt;/p>
&lt;h3 id="azure-monitoring-tools">Azure Monitoring Tools
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Azure Monitor&lt;/strong>: Centralized metrics and logs.&lt;/li>
&lt;li>&lt;strong>Azure Application Insights&lt;/strong>: App performance insights.&lt;/li>
&lt;li>&lt;strong>Azure Log Analytics&lt;/strong>: Query logs with KQL.&lt;/li>
&lt;/ul>
&lt;h3 id="best-practices-2">Best Practices
&lt;/h3>&lt;ul>
&lt;li>Use dashboards to visualize metrics.&lt;/li>
&lt;li>Set up anomaly detection.&lt;/li>
&lt;li>Monitor performance, not just failures.&lt;/li>
&lt;/ul>
&lt;h3 id="monitoring-in-c">Monitoring in C#
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">var&lt;/span> &lt;span class="n">telemetryClient&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">telemetryClient&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">TrackMetric&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;ResponseTime&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="m">200&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="monitoring-in-python">Monitoring in Python
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">applicationinsights&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TelemetryClient&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;your_instrumentation_key&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">client&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">track_metric&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;ResponseTime&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">200&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="what-works-3">What Works:
&lt;/h3>&lt;ul>
&lt;li>Application Insights with live metrics.&lt;/li>
&lt;li>Automated anomaly detection reduces manual overhead.&lt;/li>
&lt;/ul>
&lt;h3 id="what-doesnt-3">What Doesn&amp;rsquo;t:
&lt;/h3>&lt;ul>
&lt;li>Setting up too many alerts leads to alert fatigue.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="thoughts">Thoughts&amp;hellip;
&lt;/h2>&lt;p>Tracing, debugging, troubleshooting, and monitoring your Azure application isn’t rocket science… but it does feel like juggling flaming swords sometimes.&lt;/p>
&lt;p>The key is to implement structured logs, use the right tools, automate what you can, and stay cool when things break.&lt;/p>
&lt;hr>
&lt;h2 id="key-ideas">Key Ideas
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>Tracing&lt;/strong>: Follow app execution with logs.&lt;/li>
&lt;li>&lt;strong>Debugging&lt;/strong>: Investigate bugs via breakpoints and logs.&lt;/li>
&lt;li>&lt;strong>Troubleshooting&lt;/strong>: Diagnose issues using Azure tools.&lt;/li>
&lt;li>&lt;strong>Monitoring&lt;/strong>: Proactively watch application health.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="references">References
&lt;/h2>&lt;ol>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/azure-monitor">Azure Monitor Documentation&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/azure-monitor/app">Azure Application Insights&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/data-explorer/kusto/query/">Kusto Query Language (KQL)&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/devops/">Azure DevOps Debugging&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.python.org/3/library/logging.html">Python Logging&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/aspnet/core/fundamentals/logging/">C# Logging with ILogger&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/app-service/diagnostics">Azure App Service Diagnostics&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/azure-monitor/app/python">Application Insights for Python&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://azure.microsoft.com/en-us/resources/cloud-monitoring/">Best Practices for Cloud Monitoring&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.microsoft.com/azure/architecture/patterns/">Cloud Design Patterns&lt;/a>&lt;/li>
&lt;/ol></description></item><item><title>Scale Deployments Horizontally in AWS-Iac</title><link>https://brianbraatz.github.io/p/iac-aws-scale/</link><pubDate>Tue, 15 Jun 2021 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/iac-aws-scale/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/awsinfraascode.png" alt="Featured image of post Scale Deployments Horizontally in AWS-Iac" />&lt;!--
# How to Deploy and Manage Applications in AWS with Infrastructure as Code
-->
&lt;!--
## Introduction
Let’s face it—deploying and managing applications manually is **a one-way ticket to insanity**. If you’ve ever SSH’d into an EC2 instance at 2 AM to fix a broken config file, you know exactly what I mean. 😩
Enter **Infrastructure as Code (IaC)**: the magical, YAML-infested world where infrastructure is managed with scripts instead of tears. In this article, we’ll cover:
- The **history** of Infrastructure as Code.
- What **IaC actually is** and why it’s a game-changer.
- **How to deploy and manage AWS applications** using tools like Terraform and CloudFormation.
- Code examples (because who doesn’t love some spicy YAML and HCL?).
Buckle up! 🚀
-->
&lt;hr>
&lt;h2 id="a-brief-history-of-infrastructure-as-code">A Brief History of Infrastructure as Code
&lt;/h2>&lt;h3 id="the-dark-ages-pre-iac-era">&lt;strong>The Dark Ages (Pre-IaC Era)&lt;/strong>
&lt;/h3>&lt;p>Back in the ancient times (aka &lt;strong>before IaC&lt;/strong>), developers and sysadmins had to manually configure servers, databases, and networking. This usually involved:&lt;/p>
&lt;ol>
&lt;li>Clicking around in AWS like it’s a game of Minesweeper.&lt;/li>
&lt;li>Copy-pasting long bash scripts that broke when your colleague looked at them wrong.&lt;/li>
&lt;li>Manually provisioning infrastructure and forgetting how you did it when things went down.&lt;/li>
&lt;/ol>
&lt;p>In short: it was &lt;strong>chaotic, error-prone, and not scalable&lt;/strong>. 😵&lt;/p>
&lt;h3 id="the-rise-of-iac-2010s---present">&lt;strong>The Rise of IaC (2010s - Present)&lt;/strong>
&lt;/h3>&lt;p>Then came the heroes of &lt;strong>Infrastructure as Code&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>AWS CloudFormation&lt;/strong> (2011): AWS’s first attempt at automation using JSON/YAML.&lt;/li>
&lt;li>&lt;strong>Terraform&lt;/strong> (2014): HashiCorp introduced Terraform, bringing a multi-cloud, declarative IaC approach.&lt;/li>
&lt;li>&lt;strong>Pulumi, Ansible, and CDK&lt;/strong>: The IaC family expanded with more flexible tools.&lt;/li>
&lt;/ul>
&lt;p>Now, DevOps engineers could manage infrastructure the same way developers manage code—&lt;strong>with version control, repeatability, and automation&lt;/strong>. 🎉&lt;/p>
&lt;hr>
&lt;h2 id="what-is-infrastructure-as-code-">What is Infrastructure as Code? 🤔
&lt;/h2>&lt;p>&lt;strong>Infrastructure as Code (IaC)&lt;/strong> is the practice of &lt;strong>defining and managing cloud infrastructure using configuration files&lt;/strong> instead of manually setting things up.&lt;/p>
&lt;p>Key benefits:&lt;/p>
&lt;p>✅ &lt;strong>Automation:&lt;/strong> No more clicking through AWS Console like a lost tourist.&lt;/p>
&lt;p>✅ &lt;strong>Version Control:&lt;/strong> Infrastructure changes are tracked in Git—no more “it worked on my machine” excuses.&lt;/p>
&lt;p>✅ &lt;strong>Repeatability:&lt;/strong> Deploy the same stack across different environments effortlessly.&lt;/p>
&lt;p>✅ &lt;strong>Scalability:&lt;/strong> Spin up 100 servers with a single command (or by accident—oops 🤭).&lt;/p>
&lt;p>IaC is typically &lt;strong>declarative&lt;/strong> (you define the desired state, and the tool figures out how to get there). The most popular tools include:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Terraform&lt;/strong> 🏗️ (multi-cloud, declarative HCL)&lt;/li>
&lt;li>&lt;strong>AWS CloudFormation&lt;/strong> ☁️ (AWS-only, YAML/JSON)&lt;/li>
&lt;li>&lt;strong>Pulumi&lt;/strong> (uses real programming languages)&lt;/li>
&lt;li>&lt;strong>Ansible&lt;/strong> (great for server configuration)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="how-to-deploy-applications-in-aws-using-iac">How to Deploy Applications in AWS Using IaC
&lt;/h2>&lt;p>Now that we understand IaC, let’s get our hands dirty with some examples. 🛠️&lt;/p>
&lt;h3 id="1-deploying-an-ec2-instance-with-terraform">&lt;strong>1. Deploying an EC2 Instance with Terraform&lt;/strong>
&lt;/h3>&lt;p>Terraform is an &lt;strong>awesome&lt;/strong> IaC tool that lets you manage AWS, Azure, GCP, and more with a &lt;strong>single config file&lt;/strong>.&lt;/p>
&lt;p>📜 &lt;strong>Terraform example:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;us-east-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_instance&amp;#34; &amp;#34;my_server&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> ami&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> tags&lt;/span> &lt;span class="o">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> Name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;MyTerraformInstance&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> }
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Run it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">terraform init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">terraform apply
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Your EC2 instance is now &lt;strong>automated and repeatable&lt;/strong>. 🚀&lt;/p>
&lt;p>!!!!&lt;br>
Cool eh?&lt;/p>
&lt;hr>
&lt;h3 id="2-deploying-an-s3-bucket-with-aws-cloudformation">&lt;strong>2. Deploying an S3 Bucket with AWS CloudFormation&lt;/strong>
&lt;/h3>&lt;p>AWS &lt;strong>CloudFormation&lt;/strong> lets you define AWS infrastructure using YAML or JSON.&lt;/p>
&lt;p>📜 &lt;strong>CloudFormation template:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">AWSTemplateFormatVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2010-09-09&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyS3Bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::S3::Bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">BucketName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;my-cloudformation-bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Deploy it:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">aws cloudformation deploy --template-file template.yaml --stack-name MyS3Stack
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>You now have an S3 bucket &lt;strong>without touching the AWS console&lt;/strong>. 🎉&lt;/p>
&lt;p>!!!!!!&lt;br>
very cool&amp;hellip;&lt;br>
!!!!!!&lt;/p>
&lt;hr>
&lt;h2 id="how-to-scale-deployments-horizontally-in-aws">How to Scale Deployments Horizontally in AWS
&lt;/h2>&lt;p>Scaling horizontally means adding &lt;strong>more instances&lt;/strong> rather than making a single instance more powerful. This is crucial for handling increased loads efficiently.&lt;/p>
&lt;h3 id="using-auto-scaling-groups-and-load-balancers">&lt;strong>Using Auto Scaling Groups and Load Balancers&lt;/strong>
&lt;/h3>&lt;p>AWS provides &lt;strong>Auto Scaling Groups (ASG)&lt;/strong> and &lt;strong>Elastic Load Balancers (ELB)&lt;/strong> to distribute traffic and automatically add/remove instances based on demand.&lt;/p>
&lt;p>📜 &lt;strong>Terraform Example for Auto Scaling:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_launch_configuration&amp;#34; &amp;#34;my_app&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> name&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-app-config&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> image_id&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_autoscaling_group&amp;#34; &amp;#34;my_asg&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> launch_configuration&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">aws_launch_configuration&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">my_app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="k">id&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> min_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">2&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> max_size&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">10&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> desired_capacity&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="m">3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> vpc_zone_identifier&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="s2">&amp;#34;subnet-abc123&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This setup ensures &lt;strong>more instances are added automatically when needed&lt;/strong> and removed when traffic decreases. 🚀&lt;/p>
&lt;hr>
&lt;h2 id="pros-and-cons-of-not-using-iac">&lt;strong>Pros and Cons of NOT Using IaC&lt;/strong>
&lt;/h2>&lt;h3 id="the-nightmare-of-manual-deployment">&lt;strong>The Nightmare of Manual Deployment&lt;/strong>
&lt;/h3>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Without IaC&lt;/th>
&lt;th>With IaC&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Manually provisioning servers ☠️&lt;/td>
&lt;td>Automate everything with scripts 🎉&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hard to replicate environments&lt;/td>
&lt;td>Deploy the same infra repeatedly&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Prone to human errors&lt;/td>
&lt;td>Version-controlled infrastructure&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Scaling means manually launching new instances&lt;/td>
&lt;td>Auto Scaling ensures dynamic scaling&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Debugging is painful&lt;/td>
&lt;td>Logs and state management make troubleshooting easy&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>If you &lt;strong>don’t&lt;/strong> use IaC, scaling becomes a &lt;strong>tedious, manual nightmare&lt;/strong>. Imagine adding 50 EC2 instances manually while your website crashes—yeah, no thanks. 😅&lt;/p>
&lt;hr>
&lt;h2 id="key-ideas-table">Key Ideas Table
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Explanation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Infrastructure as Code&lt;/strong>&lt;/td>
&lt;td>Managing infrastructure with configuration files instead of manual processes.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Terraform&lt;/strong>&lt;/td>
&lt;td>A multi-cloud declarative IaC tool using HCL.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AWS CloudFormation&lt;/strong>&lt;/td>
&lt;td>AWS-native IaC tool using YAML/JSON.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Benefits of IaC&lt;/strong>&lt;/td>
&lt;td>Automation, repeatability, scalability, and version control.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Horizontal Scaling&lt;/strong>&lt;/td>
&lt;td>Adding more instances dynamically using Auto Scaling Groups.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Example Deployments&lt;/strong>&lt;/td>
&lt;td>Terraform for EC2, CloudFormation for S3, ASG setup for scaling.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cons of No IaC&lt;/strong>&lt;/td>
&lt;td>Manual errors, lack of version control, slow scaling, and chaos.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/autoscaling/">https://aws.amazon.com/autoscaling/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.ansible.com/">https://docs.ansible.com/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Octopus in a nutshell</title><link>https://brianbraatz.github.io/p/octopus-in-a-nutshell/</link><pubDate>Sun, 27 Jan 2019 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/octopus-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/octopus.png" alt="Featured image of post Octopus in a nutshell" />&lt;h1 id="octopus-in-a-nutshell">Octopus in a nutshell
&lt;/h1>&lt;h2 id="a-brief-history-of-octopus">A Brief History of Octopus
&lt;/h2>&lt;!--
Alright, let's get this straight—Octopus Deploy is **not** about wrangling eight-limbed sea creatures into a DevOps pipeline.
It’s actually a killer **continuous deployment (CD) tool** that takes the hassle out of deploying applications, so you don’t have to feel like a deep-sea diver drowning in YAML files.
-->
&lt;p>Back in &lt;strong>2011&lt;/strong>, a developer named &lt;strong>Paul Stovell&lt;/strong> got fed up with the nightmare of deploying applications manually.&lt;/p>
&lt;p>He figured, “Hey, why not make a tool that automates this mess?” And thus, &lt;strong>Octopus Deploy&lt;/strong> was born.&lt;/p>
&lt;!--
Since then, it's been helping teams **deploy code faster, more reliably, and with fewer headaches**—because let’s be real, deployment should *not* feel like a game of Russian roulette.
-->
&lt;h2 id="motivation-why-octopus">Motivation: Why Octopus?
&lt;/h2>&lt;p>Before Octopus, deployment felt like:&lt;/p>
&lt;ul>
&lt;li>SSHing into servers and praying nothing breaks&lt;/li>
&lt;li>Copy-pasting config files like a caveman&lt;/li>
&lt;li>Manually running SQL scripts and hoping they don’t nuke the database&lt;/li>
&lt;/ul>
&lt;p>Octopus Deploy came along and said, &lt;strong>&amp;ldquo;Enough!&amp;rdquo;&lt;/strong> It introduced a smarter way:&lt;/p>
&lt;p>✅ &lt;strong>Automated deployments&lt;/strong> – No more 3 AM deployment calls!&lt;br>
✅ &lt;strong>Rollback support&lt;/strong> – Because mistakes happen.&lt;br>
✅ &lt;strong>Multi-environment support&lt;/strong> – Dev, Test, Prod? All handled!&lt;br>
✅ &lt;strong>Permissions &amp;amp; security&lt;/strong> – Stop giving your intern access to production.&lt;br>
✅ &lt;strong>Integration with everything&lt;/strong> – Azure, AWS, Kubernetes, and more.&lt;/p>
&lt;h2 id="octopus-vs-the-competition">Octopus vs. The Competition
&lt;/h2>&lt;p>So how does it stack up against the &lt;strong>big names&lt;/strong> like Jenkins, GitHub Actions, and Azure DevOps? Let’s break it down:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Octopus Deploy&lt;/th>
&lt;th>Jenkins&lt;/th>
&lt;th>GitHub Actions&lt;/th>
&lt;th>Azure DevOps&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Ease of Use&lt;/strong>&lt;/td>
&lt;td>⭐⭐⭐⭐⭐ (Super user-friendly)&lt;/td>
&lt;td>⭐⭐ (Good luck with XML hell)&lt;/td>
&lt;td>⭐⭐⭐ (Pretty nice)&lt;/td>
&lt;td>⭐⭐⭐⭐ (Solid UI)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Deployment Focus&lt;/strong>&lt;/td>
&lt;td>✅ (Built &lt;em>for&lt;/em> deployments)&lt;/td>
&lt;td>❌ (More of a CI tool)&lt;/td>
&lt;td>❌ (More of a CI tool)&lt;/td>
&lt;td>✅ (Supports CD, but complex)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-Environment Support&lt;/strong>&lt;/td>
&lt;td>✅&lt;/td>
&lt;td>⚠️ (Requires plugins)&lt;/td>
&lt;td>⚠️ (Workarounds needed)&lt;/td>
&lt;td>✅&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Rollback Features&lt;/strong>&lt;/td>
&lt;td>✅ (Super easy)&lt;/td>
&lt;td>⚠️ (Painful)&lt;/td>
&lt;td>❌ (Not built-in)&lt;/td>
&lt;td>✅ (But tricky)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Security &amp;amp; Access Control&lt;/strong>&lt;/td>
&lt;td>✅ (Granular permissions)&lt;/td>
&lt;td>⚠️ (Plugins needed)&lt;/td>
&lt;td>⚠️ (Limited)&lt;/td>
&lt;td>✅ (Enterprise-ready)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Integrations&lt;/strong>&lt;/td>
&lt;td>✅ (All major platforms)&lt;/td>
&lt;td>✅ (Through plugins)&lt;/td>
&lt;td>✅ (But limited)&lt;/td>
&lt;td>✅ (Best with Azure)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="code-examples-deploy-like-a-pro">Code Examples: Deploy Like a Pro
&lt;/h2>&lt;h3 id="1-create-a-new-deployment-project">1. Create a New Deployment Project
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">create-project&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-project&lt;/span> &lt;span class="s2">&amp;#34;My Awesome App&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-server&lt;/span> &lt;span class="s2">&amp;#34;https://octopus.example.com&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-apiKey&lt;/span> &lt;span class="s2">&amp;#34;API-KEY&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-deploy-a-release">2. Deploy a Release
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">deploy-release&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-project&lt;/span> &lt;span class="s2">&amp;#34;My Awesome App&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-releaseNumber&lt;/span> &lt;span class="s2">&amp;#34;1.2.3&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-deployTo&lt;/span> &lt;span class="s2">&amp;#34;Production&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-create-a-new-release">3. Create a New Release
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">create-release&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-project&lt;/span> &lt;span class="s2">&amp;#34;My Awesome App&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-version&lt;/span> &lt;span class="s2">&amp;#34;1.2.3&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-packageVersion&lt;/span> &lt;span class="s2">&amp;#34;1.2.3&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-list-available-environments">4. List Available Environments
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">list-environments&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-server&lt;/span> &lt;span class="s2">&amp;#34;https://octopus.example.com&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-apiKey&lt;/span> &lt;span class="s2">&amp;#34;API-KEY&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-push-a-package-to-octopus">5. Push a Package to Octopus
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="n">push&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-package&lt;/span> &lt;span class="s2">&amp;#34;MyApp.1.2.3.nupkg&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-server&lt;/span> &lt;span class="s2">&amp;#34;https://octopus.example.com&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-apiKey&lt;/span> &lt;span class="s2">&amp;#34;API-KEY&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-view-deployment-logs">6. View Deployment Logs
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">get-deployment&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-deploymentId&lt;/span> &lt;span class="s2">&amp;#34;DEPLOYMENT-ID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-promote-a-release">7. Promote a Release
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">promote-release&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-project&lt;/span> &lt;span class="s2">&amp;#34;My Awesome App&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-from&lt;/span> &lt;span class="s2">&amp;#34;Staging&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-to&lt;/span> &lt;span class="s2">&amp;#34;Production&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-cancel-a-deployment">8. Cancel a Deployment
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">cancel-deployment&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-deploymentId&lt;/span> &lt;span class="s2">&amp;#34;DEPLOYMENT-ID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-list-all-projects">9. List All Projects
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">list-projects&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-server&lt;/span> &lt;span class="s2">&amp;#34;https://octopus.example.com&amp;#34;&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-apiKey&lt;/span> &lt;span class="s2">&amp;#34;API-KEY&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-view-deployment-progress">10. View Deployment Progress
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">octo&lt;/span> &lt;span class="nb">get-tasklog&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-taskId&lt;/span> &lt;span class="s2">&amp;#34;TASK-ID&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="key-takeaways">Key Takeaways
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Summary&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>History&lt;/strong>&lt;/td>
&lt;td>Created in 2011 to simplify deployments&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Purpose&lt;/strong>&lt;/td>
&lt;td>Automates deployments, rollbacks, and multi-environment setups&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Comparison&lt;/strong>&lt;/td>
&lt;td>More deployment-focused than Jenkins, GitHub Actions, and Azure DevOps&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best Features&lt;/strong>&lt;/td>
&lt;td>Rollbacks, security, environment management, and easy integrations&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CLI Power&lt;/strong>&lt;/td>
&lt;td>Automate everything using the Octopus CLI&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="references">References
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://octopus.com/">https://octopus.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://octopus.com/docs">https://octopus.com/docs&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/OctopusDeploy">https://github.com/OctopusDeploy&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Pulumi in a Nutshell</title><link>https://brianbraatz.github.io/p/pulumi-in-a-nutshell/</link><pubDate>Thu, 10 Aug 2023 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/pulumi-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/Pulumi.jpg" alt="Featured image of post Pulumi in a Nutshell" />&lt;!--
# Pulumi in a Nutshell
## Introduction
Tired of YAML? Sick of HCL? Wish you could just **use Python, JavaScript, or Go** to provision cloud infrastructure? Well, **Pulumi** is here to grant your wish! 🎉
-->
&lt;p>Pulumi is an &lt;strong>Infrastructure as Code (IaC) tool&lt;/strong> that lets you define cloud infrastructure using &lt;strong>real programming languages&lt;/strong> instead of domain-specific ones.&lt;/p>
&lt;p>This means you can finally write your infrastructure like you write your applications.&lt;/p>
&lt;p>If you&amp;rsquo;ve ever wished for loops and conditionals in Terraform, &lt;strong>Pulumi is your new best friend&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="a-brief-history-of-pulumi">A Brief History of Pulumi
&lt;/h2>&lt;p>Pulumi was founded in &lt;strong>2017&lt;/strong> by some smart folks who decided that writing &lt;strong>infrastructure in JSON, YAML, or HCL&lt;/strong> was &lt;strong>painful&lt;/strong>.&lt;/p>
&lt;p>Istead of creating Yet Another Configuration Language™, they made &lt;strong>Pulumi&lt;/strong>, which lets you use Python, TypeScript, JavaScript, Go, and .NET to provision cloud resources.&lt;/p>
&lt;p>Since its launch, &lt;strong>Pulumi has gained traction&lt;/strong> as an alternative to Terraform, especially among developers who prefer using real programming languages to manage infrastructure.&lt;/p>
&lt;hr>
&lt;h2 id="pulumi-vs-other-iac-tools">Pulumi vs. Other IaC Tools
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Pulumi&lt;/th>
&lt;th>Terraform&lt;/th>
&lt;th>CloudFormation&lt;/th>
&lt;th>Ansible&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Multi-Cloud&lt;/strong>&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>❌ No (AWS-only)&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Language&lt;/strong>&lt;/td>
&lt;td>Python, JS, Go, .NET&lt;/td>
&lt;td>HCL&lt;/td>
&lt;td>YAML/JSON&lt;/td>
&lt;td>YAML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>Managed or self-hosted&lt;/td>
&lt;td>Self-managed&lt;/td>
&lt;td>AWS-managed&lt;/td>
&lt;td>No state&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Imperative or Declarative&lt;/strong>&lt;/td>
&lt;td>Imperative&lt;/td>
&lt;td>Declarative&lt;/td>
&lt;td>Declarative&lt;/td>
&lt;td>Imperative&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best For&lt;/strong>&lt;/td>
&lt;td>DevOps &amp;amp; developers&lt;/td>
&lt;td>DevOps teams&lt;/td>
&lt;td>AWS-heavy shops&lt;/td>
&lt;td>Config management&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>If you love programming, use &lt;strong>Pulumi&lt;/strong>. If you want multi-cloud support but don’t mind HCL, use &lt;strong>Terraform&lt;/strong>. If you only use AWS, &lt;strong>CloudFormation&lt;/strong> is fine. If you just need to install software, &lt;strong>Ansible&lt;/strong> is your go-to.&lt;/p>
&lt;hr>
&lt;h2 id="common-pulumi-code-examples">Common Pulumi Code Examples
&lt;/h2>&lt;h3 id="1-deploy-an-aws-s3-bucket">1. &lt;strong>Deploy an AWS S3 Bucket&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi_aws&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">aws&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">s3&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Bucket&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-bucket&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;bucket_name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bucket&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-create-an-ec2-instance">2. &lt;strong>Create an EC2 Instance&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">instance&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">ec2&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Instance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-instance&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ami&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">instance_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;instance_id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">instance&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-provision-an-rds-database">3. &lt;strong>Provision an RDS Database&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">db&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">rds&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Instance&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-db&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">engine&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;mysql&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">instance_class&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;db.t3.micro&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">allocated_storage&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">20&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;db_endpoint&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">db&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">endpoint&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-deploy-a-kubernetes-cluster">4. &lt;strong>Deploy a Kubernetes Cluster&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi_kubernetes&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">k8s&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">cluster&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">k8s&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">core&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">v1&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Namespace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-namespace&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;namespace_name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cluster&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">metadata&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-create-an-iam-role">5. &lt;strong>Create an IAM Role&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">role&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">iam&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Role&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-role&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">assume_role_policy&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;Version&amp;#34;: &amp;#34;2012-10-17&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;Statement&amp;#34;: [{&amp;#34;Effect&amp;#34;: &amp;#34;Allow&amp;#34;, &amp;#34;Principal&amp;#34;: {&amp;#34;Service&amp;#34;: &amp;#34;ec2.amazonaws.com&amp;#34;}, &amp;#34;Action&amp;#34;: &amp;#34;sts:AssumeRole&amp;#34;}]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s2"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;role_name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">role&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-set-up-a-load-balancer">6. &lt;strong>Set Up a Load Balancer&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">lb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">lb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">LoadBalancer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-lb&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">internal&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">load_balancer_type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;application&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;lb_dns&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">lb&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dns_name&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-define-a-cloudwatch-alarm">7. &lt;strong>Define a CloudWatch Alarm&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">alarm&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">cloudwatch&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">MetricAlarm&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-alarm&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">comparison_operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;GreaterThanThreshold&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">threshold&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">80&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">evaluation_periods&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;alarm_arn&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">alarm&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">arn&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-use-pulumi-variables">8. &lt;strong>Use Pulumi Variables&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">pulumi&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">Config&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">config&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">Config&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">instance_type&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">config&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="ow">or&lt;/span> &lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;instance_type&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">instance_type&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-deploy-a-static-website-on-s3">9. &lt;strong>Deploy a Static Website on S3&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">s3&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Bucket&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;website&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">website&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="s2">&amp;#34;index_document&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;index.html&amp;#34;&lt;/span>&lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;website_url&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bucket&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">website_endpoint&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-automate-secret-management-with-aws-secrets-manager">10. &lt;strong>Automate Secret Management with AWS Secrets Manager&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="n">secret&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">secretsmanager&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Secret&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-secret&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;secret_id&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">secret&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="key-ideas-table">Key Ideas Table
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Explanation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Pulumi&lt;/strong>&lt;/td>
&lt;td>IaC tool that uses real programming languages&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-cloud support&lt;/strong>&lt;/td>
&lt;td>Works with AWS, Azure, GCP, Kubernetes, and more&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>Can be managed by Pulumi or self-hosted&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Comparison&lt;/strong>&lt;/td>
&lt;td>Competes with Terraform, CloudFormation, and Ansible&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Example Uses&lt;/strong>&lt;/td>
&lt;td>Provisioning VMs, Load Balancers, Kubernetes, and IAM roles&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://www.pulumi.com/">https://www.pulumi.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;!--
## Conclusion
Pulumi is **the future of Infrastructure as Code** for developers who love real programming languages. Whether you’re provisioning **AWS, Azure, Kubernetes, or multi-cloud environments**, Pulumi provides a more **flexible, expressive, and powerful way to manage infrastructure**.
So, if you’ve ever wanted to use **Python, TypeScript, or Go to deploy cloud resources**, it’s time to give Pulumi a shot. 🚀
--></description></item><item><title>Bamboo in a nutshell</title><link>https://brianbraatz.github.io/p/bamboo-in-a-nutshell/</link><pubDate>Wed, 01 Nov 2023 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/bamboo-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/bamboologo.png" alt="Featured image of post Bamboo in a nutshell" />&lt;!--
# Bamboo in a Nutshell
-->
&lt;h2 id="what-is-bamboo">What is Bamboo?
&lt;/h2>&lt;p>Bamboo is Atlassian’s Continuous Integration (CI) and Continuous Deployment (CD) tool that makes sure your code doesn’t break every time Chad from QA pushes an update.&lt;/p>
&lt;p>It’s like Jenkins but with a fancier UI and built-in Jira integration.&lt;/p>
&lt;p>DevOps teams love it because it automates builds, tests, and releases, reducing the need for manual deployment drama.&lt;/p>
&lt;h2 id="a-brief-history-of-bamboo-or-how-we-got-here">A Brief History of Bamboo (Or How We Got Here)
&lt;/h2>&lt;p>Bamboo was launched by Atlassian in 2007, back when people still thought Subversion was the future.&lt;/p>
&lt;p>Bamboo Integrates well with Atlassian’s ecosystem (Jira, Bitbucket, Confluence, and probably a few other tools nobody fully understands).&lt;/p>
&lt;h2 id="infrastructure-as-code-iac---the-big-picture">Infrastructure as Code (IaC) - The Big Picture
&lt;/h2>&lt;p>In the old days, setting up a new server meant physically plugging in machines, installing software manually, and praying to the IT gods.&lt;/p>
&lt;p>Infrastructure as Code (IaC) changed that by letting us define infrastructure with code, so we can automate provisioning, configuration, and management.&lt;/p>
&lt;p>Bamboo plays in the IaC world by integrating with Terraform, Ansible, and Kubernetes.&lt;/p>
&lt;h2 id="how-does-bamboo-compare-to-other-tools">How Does Bamboo Compare to Other Tools?
&lt;/h2>&lt;h3 id="-bamboo-vs-jenkins">🏆 Bamboo vs. Jenkins
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Bamboo&lt;/strong>: Sleek UI, native Jira/Bitbucket integration, and better support.&lt;/li>
&lt;li>&lt;strong>Jenkins&lt;/strong>: Free and open-source but requires tons of plugins and setup.&lt;/li>
&lt;/ul>
&lt;h3 id="-bamboo-vs-gitlab-cicd">🏆 Bamboo vs. GitLab CI/CD
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Bamboo&lt;/strong>: Stronger Jira/Bitbucket integration.&lt;/li>
&lt;li>&lt;strong>GitLab CI/CD&lt;/strong>: Built directly into GitLab, no separate tool required.&lt;/li>
&lt;/ul>
&lt;h3 id="-bamboo-vs-circleci">🏆 Bamboo vs. CircleCI
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Bamboo&lt;/strong>: Great for Atlassian users.&lt;/li>
&lt;li>&lt;strong>CircleCI&lt;/strong>: Strong cloud-based CI/CD with fast execution.&lt;/li>
&lt;/ul>
&lt;h2 id="10-common-bamboo-examples">10 Common Bamboo Examples
&lt;/h2>&lt;h3 id="1-setting-up-a-simple-build-plan">1. Setting Up a Simple Build Plan
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">plan&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">MYPROJ-BUILD&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build My Project&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">stages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Compile&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mvn clean install&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-running-unit-tests">2. Running Unit Tests
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">mvn test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-deploying-to-staging">3. Deploying to Staging
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy Staging&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kubectl apply -f deployment.yaml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-checking-out-code-from-git">4. Checking Out Code from Git
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">repositories&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">MyRepo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://bitbucket.org/myrepo.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-building-a-docker-image">5. Building a Docker Image
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build Docker Image&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker build -t my-app:latest .&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-pushing-docker-image-to-registry">6. Pushing Docker Image to Registry
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Push Docker Image&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">docker push my-app:latest&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-running-a-static-code-analysis">7. Running a Static Code Analysis
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Code Quality&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">sonar-scanner&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-sending-notifications-to-slack">8. Sending Notifications to Slack
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Notify Slack&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">curl -X POST -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#39;{&amp;#34;text&amp;#34;:&amp;#34;Build completed!&amp;#34;}&amp;#39; https://hooks.slack.com/services/XXX&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-deploying-to-production">9. Deploying to Production
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy Prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ansible-playbook deploy.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-running-a-performance-test">10. Running a Performance Test
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Load Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">locust -f load_test.py&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="key-ideas">Key Ideas
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Topic&lt;/th>
&lt;th>Summary&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>What is Bamboo?&lt;/td>
&lt;td>A CI/CD tool by Atlassian for automating builds, tests, and deployments.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>History&lt;/td>
&lt;td>Launched in 2007, optimized for Atlassian tools.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Infrastructure as Code&lt;/td>
&lt;td>Automates infrastructure deployment alongside code.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Comparison&lt;/td>
&lt;td>Competes with Jenkins, GitLab CI/CD, and CircleCI.&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Common Usage&lt;/td>
&lt;td>Automating builds, testing, deployment, and notifications.&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://confluence.atlassian.com/bamboo">https://confluence.atlassian.com/bamboo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://bitbucket.org/product">https://bitbucket.org/product&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.jenkins.io">https://www.jenkins.io&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://docs.gitlab.com/ee/ci/">https://docs.gitlab.com/ee/ci/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>AWS CloudFormation in a Nutshell</title><link>https://brianbraatz.github.io/p/aws-cloudformation-in-a-nutshell/</link><pubDate>Mon, 28 Mar 2022 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/aws-cloudformation-in-a-nutshell/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/awscloudformation.png" alt="Featured image of post AWS CloudFormation in a Nutshell" />&lt;!--
# AWS CloudFormation in a Nutshell
## Introduction
So, you want to deploy cloud resources **without losing your mind** clicking around the AWS console? Say hello to **AWS CloudFormation**—Amazon’s homegrown Infrastructure as Code (IaC) tool that lets you define and manage AWS resources **declaratively**. Think of it as YAML-powered wizardry for **automating cloud deployments**. 🧙‍♂️✨
In this article, we’ll cover:
- **The history of CloudFormation** (because knowing the past makes you look cool in DevOps meetings)
- **How it compares to other IaC tools** (Terraform, Pulumi, Ansible, etc.)
- **10 super handy CloudFormation templates** for common AWS tasks
By the end, you’ll be ready to CloudFormation your way into infrastructure **nirvana**. 🚀
---
-->
&lt;h2 id="a-brief-history-of-aws-cloudformation">A Brief History of AWS CloudFormation
&lt;/h2>&lt;p>Back in &lt;strong>2011&lt;/strong>, AWS decided to make life easier by introducing &lt;strong>CloudFormation&lt;/strong>, a tool that allows engineers to define AWS infrastructure in JSON (or YAML, if you have taste).&lt;/p>
&lt;p>Before this, people had to:&lt;/p>
&lt;ol>
&lt;li>Manually create resources through the AWS Console 😵&lt;/li>
&lt;li>Write long, fragile bash scripts to automate deployments 🔧&lt;/li>
&lt;li>Cry when their cloud environment wasn’t repeatable 😭&lt;/li>
&lt;/ol>
&lt;!--
Fast forward to today, and **CloudFormation is a cornerstone of AWS deployments**. It supports most AWS services, integrates deeply with IAM, and ensures deployments are consistent across environments.
-->
&lt;hr>
&lt;h2 id="aws-cloudformation-vs-other-iac-tools">AWS CloudFormation vs. Other IaC Tools
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>CloudFormation&lt;/th>
&lt;th>Terraform&lt;/th>
&lt;th>Pulumi&lt;/th>
&lt;th>Ansible&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>AWS-Native&lt;/strong>&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Multi-Cloud Support&lt;/strong>&lt;/td>
&lt;td>❌ No&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;td>✅ Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Language&lt;/strong>&lt;/td>
&lt;td>YAML/JSON&lt;/td>
&lt;td>HCL&lt;/td>
&lt;td>Python/JS/Go&lt;/td>
&lt;td>YAML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>AWS Managed&lt;/td>
&lt;td>Self-managed&lt;/td>
&lt;td>Self-managed&lt;/td>
&lt;td>No explicit state&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best For&lt;/strong>&lt;/td>
&lt;td>AWS-only infra&lt;/td>
&lt;td>Multi-cloud infra&lt;/td>
&lt;td>Devs who prefer real code&lt;/td>
&lt;td>Config management&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>If you’re &lt;strong>all-in on AWS&lt;/strong>, CloudFormation is a solid choice.&lt;/p>
&lt;p>If you need &lt;strong>multi-cloud&lt;/strong> support, &lt;strong>Terraform&lt;/strong> is your best bet.&lt;/p>
&lt;p>&lt;strong>Pulumi&lt;/strong> is for devs who hate YAML, and &lt;strong>Ansible&lt;/strong> is for managing software/configurations rather than provisioning infra.&lt;/p>
&lt;hr>
&lt;h2 id="cloudformation-code-examples">CloudFormation Code Examples
&lt;/h2>&lt;h3 id="1-create-an-s3-bucket">1. &lt;strong>Create an S3 Bucket&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">AWSTemplateFormatVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2010-09-09&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyS3Bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::S3::Bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">BucketName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;my-cloudformation-bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="2-provision-an-ec2-instance">2. &lt;strong>Provision an EC2 Instance&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyEC2Instance&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::EC2::Instance&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">InstanceType&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;t2.micro&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ImageId&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;ami-12345678&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="3-set-up-a-vpc">3. &lt;strong>Set Up a VPC&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyVPC&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::EC2::VPC&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">CidrBlock&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;10.0.0.0/16&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="4-deploy-a-load-balancer">4. &lt;strong>Deploy a Load Balancer&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyLoadBalancer&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::ElasticLoadBalancingV2::LoadBalancer&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;my-load-balancer&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;application&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="5-spin-up-an-rds-database">5. &lt;strong>Spin Up an RDS Database&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyRDS&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::RDS::DBInstance&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Engine&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;mysql&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">DBInstanceClass&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;db.t3.micro&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">AllocatedStorage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">20&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="6-create-an-iam-role">6. &lt;strong>Create an IAM Role&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyIAMRole&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::IAM::Role&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">RoleName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;MyCloudFormationRole&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">AssumeRolePolicyDocument&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;2012-10-17&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Statement&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">Effect&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;Allow&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Principal&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Service&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;ec2.amazonaws.com&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Action&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;sts:AssumeRole&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="7-set-up-an-auto-scaling-group">7. &lt;strong>Set Up an Auto Scaling Group&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyAutoScalingGroup&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::AutoScaling::AutoScalingGroup&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MinSize&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;1&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MaxSize&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;5&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="8-deploy-a-lambda-function">8. &lt;strong>Deploy a Lambda Function&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyLambda&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::Lambda::Function&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Runtime&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;python3.8&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Handler&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;index.lambda_handler&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Code&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">S3Bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;my-lambda-bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="9-create-an-sns-topic">9. &lt;strong>Create an SNS Topic&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MySNSTopic&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::SNS::Topic&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">DisplayName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;My SNS Topic&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="10-define-a-cloudwatch-alarm">10. &lt;strong>Define a CloudWatch Alarm&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyCloudWatchAlarm&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::CloudWatch::Alarm&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">AlarmDescription&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;High CPU usage&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">ComparisonOperator&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;GreaterThanThreshold&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Threshold&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">80&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="key-ideas-table">Key Ideas Table
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Explanation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>CloudFormation&lt;/strong>&lt;/td>
&lt;td>AWS-native IaC tool (YAML/JSON)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>AWS manages state internally&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best Use Case&lt;/strong>&lt;/td>
&lt;td>Deploying AWS-only infrastructure&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Comparison&lt;/strong>&lt;/td>
&lt;td>Competes with Terraform, Pulumi, and Ansible&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Example Uses&lt;/strong>&lt;/td>
&lt;td>Provisioning VMs, databases, networks, and IAM roles&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.pulumi.com/">https://www.pulumi.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;!--
## Conclusion
AWS CloudFormation is **a powerful IaC tool for AWS environments**. If you’re deep into the AWS ecosystem, **it’s an excellent choice** for defining and deploying infrastructure **in a repeatable and automated way**. However, if you need **multi-cloud flexibility**, tools like **Terraform or Pulumi** might be a better fit.
Now go forth and CloudFormation your infrastructure like a pro! 🚀
--></description></item><item><title>Understanding AWS CloudFormation, Terraform, Pulumi, and Ansible</title><link>https://brianbraatz.github.io/p/aws-cloudformation-terraform-pulumi-ansible/</link><pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/aws-cloudformation-terraform-pulumi-ansible/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/cloudformterraformpulumiansible.png" alt="Featured image of post Understanding AWS CloudFormation, Terraform, Pulumi, and Ansible" />&lt;!--
# Understanding AWS CloudFormation, Terraform, Pulumi, and Ansible
## Introduction
So, you want to manage your cloud infrastructure without turning into a sleep-deprived DevOps engineer who lives off caffeine and debugging logs? Good news! **Infrastructure as Code (IaC)** is here to save you from the dark ages of manual AWS configurations. 🚀
Today, we’re talking about four of the biggest names in the **IaC** world: **AWS CloudFormation, Terraform, Pulumi, and Ansible**. We’ll cover:
- The **history** of each tool
- How they **compare** (pros, cons, and when to use what)
- **Example code snippets**
And of course, we’ll throw in some jokes to keep things fun. Let's dive in! 🏊‍♂️
---
-->
&lt;h2 id="what-is-infrastructure-as-code-iac-">What is Infrastructure as Code (IaC)? 🤔
&lt;/h2>&lt;p>Before we go full throttle, let’s define &lt;strong>Infrastructure as Code&lt;/strong>.&lt;/p>
&lt;p>IaC is the practice of &lt;strong>managing and provisioning infrastructure through code&lt;/strong> instead of manually clicking around AWS like a lost intern. It lets you:&lt;/p>
&lt;p>✅ Automate deployments 🔄&lt;br>
✅ Keep infrastructure consistent across environments 🌍&lt;br>
✅ Easily roll back changes when things inevitably break 😅&lt;br>
✅ Version control your infrastructure just like application code 📜&lt;/p>
&lt;p>Now, let’s talk about the key players in the IaC world.&lt;/p>
&lt;hr>
&lt;h2 id="the-history-of-iac-tools">The History of IaC Tools
&lt;/h2>&lt;h3 id="aws-cloudformation-2011---the-aws-native-solution-">&lt;strong>AWS CloudFormation (2011) - The AWS Native Solution&lt;/strong> ☁️
&lt;/h3>&lt;p>AWS CloudFormation was Amazon’s first major attempt at &lt;strong>automating infrastructure&lt;/strong>. Using YAML/JSON templates, you could define AWS resources and deploy them in a &lt;strong>predictable, repeatable&lt;/strong> way.&lt;/p>
&lt;p>👉 &lt;strong>Think of CloudFormation as&lt;/strong>: That AWS employee who only uses AWS-approved tools and thinks everything else is unnecessary. 😆&lt;/p>
&lt;p>More on CloudFormation: &lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/p>
&lt;h3 id="terraform-2014---the-multi-cloud-king-">&lt;strong>Terraform (2014) - The Multi-Cloud King&lt;/strong> 👑
&lt;/h3>&lt;p>Terraform, built by HashiCorp, changed the game by introducing a &lt;strong>declarative, cloud-agnostic approach&lt;/strong> to IaC using its own language called &lt;strong>HCL (HashiCorp Configuration Language)&lt;/strong>.&lt;/p>
&lt;p>👉 &lt;strong>Think of Terraform as&lt;/strong>: That developer who insists on supporting AWS, Azure, and GCP all at once. 🌍&lt;/p>
&lt;p>More on Terraform: &lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/p>
&lt;h3 id="pulumi-2018---iac-with-real-code-">&lt;strong>Pulumi (2018) - IaC with Real Code&lt;/strong> 💻
&lt;/h3>&lt;p>Pulumi took a different route: instead of using YAML/HCL, it lets you define infrastructure using real programming languages like &lt;strong>Python, JavaScript, and Go&lt;/strong>.&lt;/p>
&lt;p>👉 &lt;strong>Think of Pulumi as&lt;/strong>: That cool DevOps engineer who writes infrastructure in TypeScript because &amp;ldquo;everything should be JavaScript!&amp;rdquo;&lt;/p>
&lt;p>More on Pulumi: &lt;a href="https://www.pulumi.com/">https://www.pulumi.com/&lt;/a>&lt;/p>
&lt;h3 id="ansible-2012---configuration-management-meets-iac-">&lt;strong>Ansible (2012) - Configuration Management Meets IaC&lt;/strong> ⚙️
&lt;/h3>&lt;p>Ansible started as a &lt;strong>configuration management&lt;/strong> tool but evolved into an IaC powerhouse. It uses &lt;strong>YAML playbooks&lt;/strong> to define infrastructure and automate deployments.&lt;/p>
&lt;p>👉 &lt;strong>Think of Ansible as&lt;/strong>: The reliable sysadmin who believes &amp;ldquo;everything can be fixed with a YAML playbook!&amp;rdquo;&lt;/p>
&lt;p>More on Ansible: &lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/p>
&lt;hr>
&lt;h2 id="how-they-compare-cloudformation-vs-terraform-vs-pulumi-vs-ansible">How They Compare: CloudFormation vs Terraform vs Pulumi vs Ansible
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>CloudFormation&lt;/th>
&lt;th>Terraform&lt;/th>
&lt;th>Pulumi&lt;/th>
&lt;th>Ansible&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Multi-Cloud&lt;/strong>&lt;/td>
&lt;td>No (AWS-only)&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>Yes&lt;/td>
&lt;td>Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Language&lt;/strong>&lt;/td>
&lt;td>YAML/JSON&lt;/td>
&lt;td>HCL&lt;/td>
&lt;td>Python/JS/Go&lt;/td>
&lt;td>YAML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>State Management&lt;/strong>&lt;/td>
&lt;td>AWS Manages&lt;/td>
&lt;td>Self-managed&lt;/td>
&lt;td>Self-managed&lt;/td>
&lt;td>No explicit state&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Ease of Use&lt;/strong>&lt;/td>
&lt;td>Medium&lt;/td>
&lt;td>Medium&lt;/td>
&lt;td>Harder (code-heavy)&lt;/td>
&lt;td>Easy&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Best for&lt;/strong>&lt;/td>
&lt;td>AWS-only setups&lt;/td>
&lt;td>Multi-cloud infra&lt;/td>
&lt;td>DevOps with coding&lt;/td>
&lt;td>Server Configs&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="example-code-for-each-iac-tool">Example Code for Each IaC Tool
&lt;/h2>&lt;h3 id="aws-cloudformation-example-creates-an-s3-bucket">&lt;strong>AWS CloudFormation Example&lt;/strong> (Creates an S3 Bucket)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">AWSTemplateFormatVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s1">&amp;#39;2010-09-09&amp;#39;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">Resources&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">MyS3Bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Type&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;AWS::S3::Bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">Properties&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">BucketName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;my-cloudformation-bucket&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="terraform-example-creates-the-same-s3-bucket">&lt;strong>Terraform Example&lt;/strong> (Creates the Same S3 Bucket)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-hcl" data-lang="hcl">&lt;span class="line">&lt;span class="cl">&lt;span class="k">provider&lt;/span> &lt;span class="s2">&amp;#34;aws&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> region&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;us-east-1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">resource&lt;/span> &lt;span class="s2">&amp;#34;aws_s3_bucket&amp;#34; &amp;#34;my_bucket&amp;#34;&lt;/span> {
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n"> bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;my-terraform-bucket&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="pulumi-example-python">&lt;strong>Pulumi Example (Python)&lt;/strong>
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">pulumi_aws&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="nn">aws&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">bucket&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">aws&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">s3&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Bucket&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;my-pulumi-bucket&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">pulumi&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">export&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;bucket_name&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bucket&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">id&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="ansible-playbook-example-deploys-s3-bucket">&lt;strong>Ansible Playbook Example&lt;/strong> (Deploys S3 Bucket)
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Create an S3 Bucket&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">hosts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">localhost&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tasks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Create bucket&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">amazon.aws.s3_bucket&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">my-ansible-bucket&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">state&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">present&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="key-ideas-table">Key Ideas Table
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concept&lt;/th>
&lt;th>Explanation&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Infrastructure as Code&lt;/strong>&lt;/td>
&lt;td>Automating infrastructure using code&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CloudFormation&lt;/strong>&lt;/td>
&lt;td>AWS-native IaC tool (YAML/JSON)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Terraform&lt;/strong>&lt;/td>
&lt;td>Multi-cloud declarative IaC (HCL)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Pulumi&lt;/strong>&lt;/td>
&lt;td>Code-based IaC using real languages (Python/JS)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Ansible&lt;/strong>&lt;/td>
&lt;td>Configuration management + IaC (YAML Playbooks)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">Reference Links
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://aws.amazon.com/cloudformation/">https://aws.amazon.com/cloudformation/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.terraform.io/">https://www.terraform.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.pulumi.com/">https://www.pulumi.com/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.ansible.com/">https://www.ansible.com/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;!--
## Conclusion
If you’re deep into AWS, **CloudFormation** is your best bet. If you need **multi-cloud** support, **Terraform** is the way to go. If you love **writing real code**, check out **Pulumi**. And if you need **simple automation**, **Ansible** is your friend.
No matter which you choose, **IaC is the future**. So stop manually clicking around AWS and start automating! 🚀
--></description></item><item><title>Bamboo vs Jenkins In Depth</title><link>https://brianbraatz.github.io/p/bamboo-vs-jenkins-in-depth/</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/bamboo-vs-jenkins-in-depth/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/jenkinsvsbamboo.png" alt="Featured image of post Bamboo vs Jenkins In Depth" />&lt;!--
# Bamboo vs Jenkins In Depth
## Introduction
Welcome to the **Battle of CI/CD Titans!** 🎉 In one corner, we have **Bamboo**, the slick and polished champion from Atlassian. In the other, the **bearded warlord Jenkins**, the open-source veteran with a plugin for literally *everything* (probably even your toaster).
Which one should you use? Well, let’s deep dive into their **history, features, pros and cons, and even some code samples** to see which one truly deserves a spot in your DevOps pipeline.
---
-->
&lt;h2 id="the-history-of-jenkins-and-bamboo">The History of Jenkins and Bamboo
&lt;/h2>&lt;h3 id="jenkins-the-granddaddy-of-cicd-">&lt;strong>Jenkins: The Granddaddy of CI/CD 👴&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Born in 2004&lt;/strong> as Hudson at Sun Microsystems.&lt;/li>
&lt;li>&lt;strong>2011&lt;/strong>: Oracle acquires Sun ☠️, and the community forks Hudson to create &lt;strong>Jenkins&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Now&lt;/strong>: The undisputed king of open-source CI/CD with thousands of plugins and community support.&lt;/li>
&lt;/ul>
&lt;p>👉 &lt;strong>Think of Jenkins as&lt;/strong> that old Unix admin who knows everything but looks like he was programmed in 1995.&lt;/p>
&lt;p>More on Jenkins: &lt;a href="https://www.jenkins.io/">https://www.jenkins.io/&lt;/a>&lt;/p>
&lt;h3 id="bamboo-the-sleek-corporate-solution-">&lt;strong>Bamboo: The Sleek Corporate Solution 🏢&lt;/strong>
&lt;/h3>&lt;ul>
&lt;li>Created by &lt;strong>Atlassian&lt;/strong> in &lt;strong>2007&lt;/strong>.&lt;/li>
&lt;li>Designed to integrate &lt;strong>seamlessly&lt;/strong> with Bitbucket, Jira, and Confluence.&lt;/li>
&lt;li>Supports &lt;strong>Docker, Kubernetes, AWS&lt;/strong>, and integrates beautifully with enterprise environments.&lt;/li>
&lt;/ul>
&lt;p>👉 &lt;strong>Think of Bamboo as&lt;/strong> the polished DevOps engineer who uses an iPad instead of a terminal.&lt;/p>
&lt;p>More on Bamboo: &lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/p>
&lt;hr>
&lt;h2 id="feature-comparison-bamboo-vs-jenkins">Feature Comparison: Bamboo vs Jenkins
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Feature&lt;/th>
&lt;th>Jenkins&lt;/th>
&lt;th>Bamboo&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Ease of Use&lt;/strong>&lt;/td>
&lt;td>Complex UI, requires plugins for simple tasks&lt;/td>
&lt;td>Simple UI, built-in integrations&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Scalability&lt;/strong>&lt;/td>
&lt;td>Requires tuning, supports distributed builds&lt;/td>
&lt;td>Scales out of the box with AWS, Docker, Kubernetes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Plugins &amp;amp; Extensibility&lt;/strong>&lt;/td>
&lt;td>1800+ plugins, but chaotic&lt;/td>
&lt;td>Fewer plugins, but structured&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Built-in Features&lt;/strong>&lt;/td>
&lt;td>Core is minimal; everything is a plugin&lt;/td>
&lt;td>CI/CD, Deployment, Reporting, Bitbucket integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Security&lt;/strong>&lt;/td>
&lt;td>Community-managed updates, can be risky&lt;/td>
&lt;td>Enterprise-level security, access controls&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cost&lt;/strong>&lt;/td>
&lt;td>Free &amp;amp; open-source&lt;/td>
&lt;td>Paid license for full features&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="example-cicd-pipelines-jenkins-vs-bamboo">Example CI/CD Pipelines: Jenkins vs Bamboo
&lt;/h2>&lt;h3 id="jenkins-pipeline-example">&lt;strong>Jenkins Pipeline Example&lt;/strong>
&lt;/h3>&lt;p>Here’s a &lt;strong>basic Jenkinsfile&lt;/strong> to build a simple Node.js app.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-groovy" data-lang="groovy">&lt;span class="line">&lt;span class="cl">&lt;span class="n">pipeline&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">agent&lt;/span> &lt;span class="n">any&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stages&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Build&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;npm install&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Test&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;npm test&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">stage&lt;/span>&lt;span class="o">(&lt;/span>&lt;span class="s1">&amp;#39;Deploy&amp;#39;&lt;/span>&lt;span class="o">)&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">steps&lt;/span> &lt;span class="o">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sh&lt;/span> &lt;span class="s1">&amp;#39;npm run deploy&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>To set up this pipeline:&lt;/p>
&lt;ol>
&lt;li>Install &lt;strong>Jenkins&lt;/strong>.&lt;/li>
&lt;li>Install the &lt;strong>Pipeline plugin&lt;/strong>.&lt;/li>
&lt;li>Create a new &lt;strong>Multibranch Pipeline Job&lt;/strong>.&lt;/li>
&lt;li>Point it to your &lt;strong>Git repo with Jenkinsfile&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;h3 id="bamboo-pipeline-example">&lt;strong>Bamboo Pipeline Example&lt;/strong>
&lt;/h3>&lt;p>Now, here’s a simple &lt;strong>Bamboo build plan&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">stages&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">stage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Build&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">job&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Install and Test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm install&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm test&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">stage&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">jobs&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">job&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Deploy to Staging&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">script&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">npm run deploy&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>To set this up:&lt;/p>
&lt;ol>
&lt;li>Go to &lt;strong>Bamboo&lt;/strong>.&lt;/li>
&lt;li>Create a new &lt;strong>Build Plan&lt;/strong>.&lt;/li>
&lt;li>Add the &lt;strong>Stages and Jobs&lt;/strong>.&lt;/li>
&lt;li>Connect it to &lt;strong>Bitbucket&lt;/strong> (if using Atlassian products).&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="when-to-use-bamboo-vs-jenkins">When to Use Bamboo vs Jenkins
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Use Case&lt;/th>
&lt;th>Best Tool&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>You&amp;rsquo;re an enterprise using Bitbucket &amp;amp; Jira&lt;/strong>&lt;/td>
&lt;td>🚀 &lt;strong>Bamboo&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>You love open-source, flexibility, and don&amp;rsquo;t mind chaos&lt;/strong>&lt;/td>
&lt;td>🤖 &lt;strong>Jenkins&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Security and structured enterprise support is critical&lt;/strong>&lt;/td>
&lt;td>🏢 &lt;strong>Bamboo&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>You want a free solution with a massive community&lt;/strong>&lt;/td>
&lt;td>🌍 &lt;strong>Jenkins&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>You need rapid, plugin-driven customization&lt;/strong>&lt;/td>
&lt;td>🛠️ &lt;strong>Jenkins&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>You prefer built-in CI/CD with less maintenance&lt;/strong>&lt;/td>
&lt;td>🏆 &lt;strong>Bamboo&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="final-verdict">&lt;strong>Final Verdict&lt;/strong>
&lt;/h2>&lt;ul>
&lt;li>&lt;strong>If you’re a startup or love open-source freedom&lt;/strong> → Use &lt;strong>Jenkins&lt;/strong> (but be ready for some plugin mayhem). 🎭&lt;/li>
&lt;li>&lt;strong>If you’re in an enterprise using Atlassian tools&lt;/strong> → Use &lt;strong>Bamboo&lt;/strong> (less headache, better integration). 🏢&lt;/li>
&lt;/ul>
&lt;p>Whichever you choose, &lt;strong>both Bamboo and Jenkins are awesome in their own way&lt;/strong>. Pick what fits your stack and DevOps culture best! 🚀&lt;/p>
&lt;hr>
&lt;h2 id="key-ideas-table">&lt;strong>Key Ideas Table&lt;/strong>
&lt;/h2>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Topic&lt;/th>
&lt;th>Summary&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Jenkins&lt;/strong>&lt;/td>
&lt;td>Open-source, highly flexible but requires plugins&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Bamboo&lt;/strong>&lt;/td>
&lt;td>Enterprise CI/CD solution with strong Bitbucket integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Ease of Use&lt;/strong>&lt;/td>
&lt;td>Bamboo is more user-friendly; Jenkins is powerful but complex&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Security&lt;/strong>&lt;/td>
&lt;td>Bamboo has better built-in security; Jenkins relies on community updates&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Cost&lt;/strong>&lt;/td>
&lt;td>Jenkins is free; Bamboo is paid&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Example Pipelines&lt;/strong>&lt;/td>
&lt;td>Showcased a basic Jenkinsfile and Bamboo YAML pipeline&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="reference-links">&lt;strong>Reference Links&lt;/strong>
&lt;/h2>&lt;ul>
&lt;li>&lt;a href="https://www.jenkins.io/">https://www.jenkins.io/&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.atlassian.com/software/bamboo">https://www.atlassian.com/software/bamboo&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.atlassian.com/continuous-delivery/ci-vs-cd">https://www.atlassian.com/continuous-delivery/ci-vs-cd&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://plugins.jenkins.io/">https://plugins.jenkins.io/&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="conclusion">&lt;strong>Conclusion&lt;/strong>
&lt;/h2>&lt;p>So there you have it! &lt;strong>Bamboo vs Jenkins&lt;/strong>, the ultimate showdown. Whether you want &lt;strong>Jenkins&amp;rsquo; flexibility&lt;/strong> or &lt;strong>Bamboo’s tight Atlassian integration&lt;/strong>, both are solid choices. Now go forth and automate! 🚀🔥&lt;/p></description></item><item><title>OpenAPI-Use Jenkins to Detect OpenAPI Changes + Email Docs Team</title><link>https://brianbraatz.github.io/p/detect-openapi-changes-jenkins/</link><pubDate>Tue, 23 Jul 2019 00:00:00 +0000</pubDate><guid>https://brianbraatz.github.io/p/detect-openapi-changes-jenkins/</guid><description>&lt;img src="https://brianbraatz.github.io/post/Articles/IMAGES/openapi.png" alt="Featured image of post OpenAPI-Use Jenkins to Detect OpenAPI Changes + Email Docs Team" />&lt;p>So, you’re maintaining &lt;strong>manual API documentation&lt;/strong>, but how do you know &lt;strong>when&lt;/strong> to update it?&lt;/p>
&lt;p>If your API changes, but nobody tells the documentation team&amp;hellip; &lt;strong>you’ve got a problem.&lt;/strong>&lt;/p>
&lt;p>What if Jenkins could:&lt;br>
✅ &lt;strong>Detect when swagger.json changes&lt;/strong>&lt;br>
✅ &lt;strong>Log the differences in a file&lt;/strong>&lt;br>
✅ &lt;strong>Trigger a documentation update notification&lt;/strong>&lt;br>
✅ &lt;strong>Fail the build if documentation updates are ignored&lt;/strong>&lt;/p>
&lt;hr>
&lt;h2 id="-the-plan">🔥 The Plan
&lt;/h2>&lt;p>We’re setting up &lt;strong>two Jenkins jobs&lt;/strong> to monitor OpenAPI changes:&lt;/p>
&lt;p>1️⃣ &lt;strong>API Repo Jenkins Job&lt;/strong> – Detects changes in &lt;code>swagger.json&lt;/code> and logs them in a &lt;code>apichangessensedbyjenkins.txt&lt;/code> file.&lt;br>
2️⃣ &lt;strong>Docs Repo Jenkins Job&lt;/strong> – Watches for changes in this file and emails the doc team with the API diff.&lt;/p>
&lt;p>If the diff logging &lt;strong>fails&lt;/strong>, the &lt;strong>API build fails&lt;/strong>.&lt;br>
If documentation updates are &lt;strong>ignored&lt;/strong>, a &lt;strong>reminder email is sent&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="-step-1-set-up-jenkins-to-detect-openapi-changes">🛠 Step 1: Set Up Jenkins to Detect OpenAPI Changes
&lt;/h2>&lt;h3 id="-11-install-required-tools-on-jenkins-server">✅ 1.1: Install Required Tools on Jenkins Server
&lt;/h3>&lt;p>Make sure Jenkins has:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Git&lt;/strong> (&lt;code>apt install git&lt;/code> or &lt;code>choco install git&lt;/code>)&lt;/li>
&lt;li>&lt;strong>jq&lt;/strong> (JSON diff tool, &lt;code>apt install jq&lt;/code> or &lt;code>choco install jq&lt;/code>)&lt;/li>
&lt;li>&lt;strong>diff&lt;/strong> (should be pre-installed)&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h3 id="-12-create-jenkins-job-to-detect-api-changes">✅ 1.2: Create Jenkins Job to Detect API Changes
&lt;/h3>&lt;ol>
&lt;li>Open &lt;strong>Jenkins Dashboard&lt;/strong> → &lt;strong>New Item&lt;/strong> → &lt;strong>Freestyle Project&lt;/strong>&lt;/li>
&lt;li>Name it &lt;strong>Detect-OpenAPI-Changes&lt;/strong>&lt;/li>
&lt;li>Under &lt;strong>Source Code Management&lt;/strong>, choose &lt;strong>Git&lt;/strong>, and add your API repo URL.&lt;/li>
&lt;li>Under &lt;strong>Build Triggers&lt;/strong>, enable &lt;strong>Poll SCM&lt;/strong> (e.g., every 5 minutes: &lt;code>H/5 * * * *&lt;/code>).&lt;/li>
&lt;li>Add the following &lt;strong>Bash Script&lt;/strong> under &lt;strong>Build Steps → Execute Shell&lt;/strong>:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Define paths&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">API_REPO&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/var/lib/jenkins/workspace/Detect-OpenAPI-Changes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">DOCS_REPO&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/var/lib/jenkins/workspace/API-Docs-Changes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">SWAGGER_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$API_REPO&lt;/span>&lt;span class="s2">/swagger.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">OLD_SWAGGER_FILE&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$API_REPO&lt;/span>&lt;span class="s2">/old_swagger.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">CHANGE_LOG&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">/apichangessensedbyjenkins.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Clone docs repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> ! -d &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> git clone git@github.com:your-org/api-docs.git &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pull latest changes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Check if old swagger file exists&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> -f &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$OLD_SWAGGER_FILE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Compute JSON diff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">DIFF&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>diff &amp;lt;&lt;span class="o">(&lt;/span>jq -S . &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$OLD_SWAGGER_FILE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span> &amp;lt;&lt;span class="o">(&lt;/span>jq -S . &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$SWAGGER_FILE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="o">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="o">[&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DIFF&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> !&lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Swagger JSON has changed!&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Append diff to log file&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;----------------------------&amp;#34;&lt;/span> &amp;gt;&amp;gt; &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Date: &lt;/span>&lt;span class="k">$(&lt;/span>date&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &amp;gt;&amp;gt; &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Commit: &lt;/span>&lt;span class="k">$(&lt;/span>git -C &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$API_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> rev-parse HEAD&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &amp;gt;&amp;gt; &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Changes:&amp;#34;&lt;/span> &amp;gt;&amp;gt; &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DIFF&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &amp;gt;&amp;gt; &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Push changes to docs repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> git add &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> git commit -m &lt;span class="s2">&amp;#34;API changes detected by Jenkins on &lt;/span>&lt;span class="k">$(&lt;/span>date&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> git push origin main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;No changes detected in Swagger JSON.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;First run, saving initial Swagger file.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Save new Swagger file for future comparison&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cp &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$SWAGGER_FILE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$OLD_SWAGGER_FILE&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="6">
&lt;li>&lt;strong>Save and Build Now&lt;/strong>.&lt;/li>
&lt;li>Check if &lt;code>apichangessensedbyjenkins.txt&lt;/code> is created/updated in your &lt;strong>API-Docs&lt;/strong> repo.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="-step-2-set-up-jenkins-to-notify-the-documentation-team">📩 Step 2: Set Up Jenkins to Notify the Documentation Team
&lt;/h2>&lt;h3 id="-21-create-a-second-jenkins-job">✅ 2.1: Create a Second Jenkins Job
&lt;/h3>&lt;ol>
&lt;li>Open &lt;strong>Jenkins Dashboard&lt;/strong> → &lt;strong>New Item&lt;/strong> → &lt;strong>Freestyle Project&lt;/strong>&lt;/li>
&lt;li>Name it &lt;strong>Notify-Docs-Team&lt;/strong>&lt;/li>
&lt;li>Under &lt;strong>Source Code Management&lt;/strong>, choose &lt;strong>Git&lt;/strong>, and add the &lt;strong>API-Docs repo URL&lt;/strong>.&lt;/li>
&lt;li>Under &lt;strong>Build Triggers&lt;/strong>, enable &lt;strong>Poll SCM&lt;/strong> (&lt;code>H/5 * * * *&lt;/code>).&lt;/li>
&lt;li>Under &lt;strong>Build Steps → Execute Shell&lt;/strong>, add:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">DOCS_REPO&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/var/lib/jenkins/workspace/API-Docs-Changes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">CHANGE_LOG&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">/apichangessensedbyjenkins.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pull latest changes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Check if file has been updated&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> git diff --name-only HEAD~1 HEAD &lt;span class="p">|&lt;/span> grep -q &lt;span class="s2">&amp;#34;apichangessensedbyjenkins.txt&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Swagger changes detected! Sending email notification...&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Extract last changes&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">DIFF_CONTENT&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>tail -n &lt;span class="m">20&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CHANGE_LOG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1"># Send email&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> -e &lt;span class="s2">&amp;#34;Subject: API Documentation Update Required\n\nThe following API changes were detected:\n\n&lt;/span>&lt;span class="nv">$DIFF_CONTENT&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="p">|&lt;/span> sendmail -v docs-team@example.com
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;No new API changes detected.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;ol start="6">
&lt;li>&lt;strong>Save and Build Now&lt;/strong>.&lt;/li>
&lt;li>Check email inbox for &lt;strong>API change notifications&lt;/strong>.&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="-step-3-fail-build-if-api-docs-arent-updated">🚨 Step 3: Fail Build if API Docs Aren&amp;rsquo;t Updated
&lt;/h2>&lt;p>If the documentation team &lt;strong>doesn’t update&lt;/strong> the API docs (by updating the swagger.json) after changes, we can &lt;strong>fail the build&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>In &lt;strong>Notify-Docs-Team&lt;/strong>, go to &lt;strong>Post-Build Actions → Add Post-Build Script&lt;/strong>&lt;/li>
&lt;li>Add the following check:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">DOCS_REPO&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/var/lib/jenkins/workspace/API-Docs-Changes&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">CHANGE_LOG&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">/apichangessensedbyjenkins.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Get last commit message&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">LAST_COMMIT_MSG&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="k">$(&lt;/span>git -C &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$DOCS_REPO&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> log -1 --pretty&lt;span class="o">=&lt;/span>%B&lt;span class="k">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># If the last commit was by Jenkins, the docs haven&amp;#39;t been updated yet&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[[&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$LAST_COMMIT_MSG&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">==&lt;/span> *&lt;span class="s2">&amp;#34;API changes detected by Jenkins&amp;#34;&lt;/span>* &lt;span class="o">]]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Documentation has not been updated. Failing build.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">exit&lt;/span> &lt;span class="m">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;Documentation updated. Build successful.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Now, if the docs team &lt;strong>doesn’t update API documentation&lt;/strong>, the &lt;strong>build will fail&lt;/strong>, forcing them to take action.&lt;/p>
&lt;hr>
&lt;!--
## 🎯 Conclusion: Automating API Documentation Updates
✅ **Jenkins now automatically detects OpenAPI changes**
✅ **It logs differences in `apichangessensedbyjenkins.txt`**
✅ **It triggers email notifications to the documentation team**
✅ **It fails the build if documentation updates are ignored**
With this setup, **no API change goes unnoticed**, and documentation stays **up-to-date**. 🚀
Now go forth and **automate your API docs like a boss!** 🏆
---
## 🔑 Key Takeaways
| Summary | Details |
|---------------|---------|
| **How to detect API changes?** | Compare `swagger.json` with an old version. |
| **Where to store API diffs?** | Log them in `apichangessensedbyjenkins.txt` in another repo. |
| **How to notify documentation teams?** | Send email with API diffs when the file changes. |
| **How to enforce updates?** | Fail the build if documentation isn't updated. |
| **Why use Jenkins?** | Automates API change tracking without manual effort. |
```
-->
&lt;p>So, Jenkins is now &lt;strong>detecting API changes&lt;/strong>, logging diffs, and &lt;strong>failing the build&lt;/strong> if documentation isn’t updated. &lt;strong>Great!&lt;/strong>&lt;/p>
&lt;p>But now the docs team has &lt;strong>a new problem&lt;/strong>:&lt;br>
➡️ How do they actually &lt;strong>update the Swagger JSON&lt;/strong> and prevent build failures?&lt;/p>
&lt;h2 id="which-is-the-answer-to-most-things-in-life-hahaha-">The answer? &lt;strong>A simple Python script.&lt;/strong>&lt;br>
(Which is the answer to &lt;strong>most things in life&lt;/strong> hahaha.. )
&lt;/h2>&lt;h1 id="how-the-docs-team-can-push-a-button-after-the-docs-are-fix--and-make-the-build-work-again">How The Docs Team can push a button after the docs are fix- and make the build work again
&lt;/h1>&lt;h2 id="-the-plan-1">🚀 The Plan
&lt;/h2>&lt;p>The docs team will:&lt;br>
✅ Run a Python script to pull the latest &lt;code>swagger.json&lt;/code>&lt;br>
✅ Manually review and update the documentation&lt;br>
✅ Commit and push the updated &lt;code>swagger.json&lt;/code>&lt;br>
✅ Fix the &lt;strong>Jenkins failure&lt;/strong>, keeping API docs up to date&lt;/p>
&lt;p>Let’s build it. 🚀&lt;/p>
&lt;hr>
&lt;h2 id="-step-1-install-dependencies">🔧 Step 1: Install Dependencies
&lt;/h2>&lt;p>The script uses &lt;strong>GitPython&lt;/strong> to manage Git operations and &lt;strong>jsondiff&lt;/strong> to detect changes in &lt;code>swagger.json&lt;/code>.&lt;/p>
&lt;h3 id="install-them-with">Install them with:
&lt;/h3>&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">pip install gitpython jsondiff
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="-step-2-create-the-python-script">📝 Step 2: Create the Python Script
&lt;/h2>&lt;p>Save the following script as &lt;code>update_swagger.py&lt;/code> in the &lt;strong>manual documentation repository&lt;/strong>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt"> 10
&lt;/span>&lt;span class="lnt"> 11
&lt;/span>&lt;span class="lnt"> 12
&lt;/span>&lt;span class="lnt"> 13
&lt;/span>&lt;span class="lnt"> 14
&lt;/span>&lt;span class="lnt"> 15
&lt;/span>&lt;span class="lnt"> 16
&lt;/span>&lt;span class="lnt"> 17
&lt;/span>&lt;span class="lnt"> 18
&lt;/span>&lt;span class="lnt"> 19
&lt;/span>&lt;span class="lnt"> 20
&lt;/span>&lt;span class="lnt"> 21
&lt;/span>&lt;span class="lnt"> 22
&lt;/span>&lt;span class="lnt"> 23
&lt;/span>&lt;span class="lnt"> 24
&lt;/span>&lt;span class="lnt"> 25
&lt;/span>&lt;span class="lnt"> 26
&lt;/span>&lt;span class="lnt"> 27
&lt;/span>&lt;span class="lnt"> 28
&lt;/span>&lt;span class="lnt"> 29
&lt;/span>&lt;span class="lnt"> 30
&lt;/span>&lt;span class="lnt"> 31
&lt;/span>&lt;span class="lnt"> 32
&lt;/span>&lt;span class="lnt"> 33
&lt;/span>&lt;span class="lnt"> 34
&lt;/span>&lt;span class="lnt"> 35
&lt;/span>&lt;span class="lnt"> 36
&lt;/span>&lt;span class="lnt"> 37
&lt;/span>&lt;span class="lnt"> 38
&lt;/span>&lt;span class="lnt"> 39
&lt;/span>&lt;span class="lnt"> 40
&lt;/span>&lt;span class="lnt"> 41
&lt;/span>&lt;span class="lnt"> 42
&lt;/span>&lt;span class="lnt"> 43
&lt;/span>&lt;span class="lnt"> 44
&lt;/span>&lt;span class="lnt"> 45
&lt;/span>&lt;span class="lnt"> 46
&lt;/span>&lt;span class="lnt"> 47
&lt;/span>&lt;span class="lnt"> 48
&lt;/span>&lt;span class="lnt"> 49
&lt;/span>&lt;span class="lnt"> 50
&lt;/span>&lt;span class="lnt"> 51
&lt;/span>&lt;span class="lnt"> 52
&lt;/span>&lt;span class="lnt"> 53
&lt;/span>&lt;span class="lnt"> 54
&lt;/span>&lt;span class="lnt"> 55
&lt;/span>&lt;span class="lnt"> 56
&lt;/span>&lt;span class="lnt"> 57
&lt;/span>&lt;span class="lnt"> 58
&lt;/span>&lt;span class="lnt"> 59
&lt;/span>&lt;span class="lnt"> 60
&lt;/span>&lt;span class="lnt"> 61
&lt;/span>&lt;span class="lnt"> 62
&lt;/span>&lt;span class="lnt"> 63
&lt;/span>&lt;span class="lnt"> 64
&lt;/span>&lt;span class="lnt"> 65
&lt;/span>&lt;span class="lnt"> 66
&lt;/span>&lt;span class="lnt"> 67
&lt;/span>&lt;span class="lnt"> 68
&lt;/span>&lt;span class="lnt"> 69
&lt;/span>&lt;span class="lnt"> 70
&lt;/span>&lt;span class="lnt"> 71
&lt;/span>&lt;span class="lnt"> 72
&lt;/span>&lt;span class="lnt"> 73
&lt;/span>&lt;span class="lnt"> 74
&lt;/span>&lt;span class="lnt"> 75
&lt;/span>&lt;span class="lnt"> 76
&lt;/span>&lt;span class="lnt"> 77
&lt;/span>&lt;span class="lnt"> 78
&lt;/span>&lt;span class="lnt"> 79
&lt;/span>&lt;span class="lnt"> 80
&lt;/span>&lt;span class="lnt"> 81
&lt;/span>&lt;span class="lnt"> 82
&lt;/span>&lt;span class="lnt"> 83
&lt;/span>&lt;span class="lnt"> 84
&lt;/span>&lt;span class="lnt"> 85
&lt;/span>&lt;span class="lnt"> 86
&lt;/span>&lt;span class="lnt"> 87
&lt;/span>&lt;span class="lnt"> 88
&lt;/span>&lt;span class="lnt"> 89
&lt;/span>&lt;span class="lnt"> 90
&lt;/span>&lt;span class="lnt"> 91
&lt;/span>&lt;span class="lnt"> 92
&lt;/span>&lt;span class="lnt"> 93
&lt;/span>&lt;span class="lnt"> 94
&lt;/span>&lt;span class="lnt"> 95
&lt;/span>&lt;span class="lnt"> 96
&lt;/span>&lt;span class="lnt"> 97
&lt;/span>&lt;span class="lnt"> 98
&lt;/span>&lt;span class="lnt"> 99
&lt;/span>&lt;span class="lnt">100
&lt;/span>&lt;span class="lnt">101
&lt;/span>&lt;span class="lnt">102
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-python" data-lang="python">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">os&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">json&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">git&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="nn">subprocess&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">from&lt;/span> &lt;span class="nn">jsondiff&lt;/span> &lt;span class="kn">import&lt;/span> &lt;span class="n">diff&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Set repository paths&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">DOCS_REPO_PATH&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">abspath&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1"># Run this script inside the docs repo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">API_REPO_URL&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;git@github.com:your-org/api-repo.git&amp;#34;&lt;/span> &lt;span class="c1"># API repository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">TEMP_CLONE_PATH&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;/tmp/api-repo&amp;#34;&lt;/span> &lt;span class="c1"># Temporary API clone location&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">SWAGGER_FILE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;swagger.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">CHANGE_LOG_FILE&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;apichangessensedbyjenkins.txt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">clone_api_repo&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Clone the API repository to fetch the latest swagger.json.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TEMP_CLONE_PATH&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">run&lt;/span>&lt;span class="p">([&lt;/span>&lt;span class="s2">&amp;#34;rm&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;-rf&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TEMP_CLONE_PATH&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="n">check&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="kc">True&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Cloning API repository...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">clone_from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">API_REPO_URL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TEMP_CLONE_PATH&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">fetch_swagger_file&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Fetch the latest swagger.json from the API repo.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">api_swagger_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TEMP_CLONE_PATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">SWAGGER_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_swagger_path&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">raise&lt;/span> &lt;span class="ne">FileNotFoundError&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Swagger file not found in API repository!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">api_swagger_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">load_current_swagger&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Load the existing swagger.json from the docs repo.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">docs_swagger_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DOCS_REPO_PATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">SWAGGER_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="ow">not&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">exists&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">docs_swagger_path&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;No existing swagger.json found. Creating a new one...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">docs_swagger_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;r&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">load&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">f&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">detect_changes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">old&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Detect changes between old and new Swagger JSON.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">diff&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">old&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">syntax&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;symmetric&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">update_swagger_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_swagger&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Update the local swagger.json file in the documentation repo.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">docs_swagger_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DOCS_REPO_PATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">SWAGGER_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">docs_swagger_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dump&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_swagger&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indent&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Updated &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">SWAGGER_FILE&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2"> with the latest API changes.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">append_to_changelog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">changes&lt;/span>&lt;span class="p">):&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Append detected changes to the Jenkins change log file.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">changelog_path&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">os&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DOCS_REPO_PATH&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">CHANGE_LOG_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">with&lt;/span> &lt;span class="nb">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">changelog_path&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;a&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">f&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">----------------------------&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Date: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">subprocess&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">getoutput&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s1">&amp;#39;date&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">f&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">write&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Changes detected:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">json&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">dumps&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">changes&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">indent&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;Changes appended to &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">CHANGE_LOG_FILE&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">def&lt;/span> &lt;span class="nf">commit_and_push&lt;/span>&lt;span class="p">():&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;&amp;#34;&amp;#34;Commit and push the updated swagger.json to prevent Jenkins build failure.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repo&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">Repo&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">DOCS_REPO_PATH&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SWAGGER_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">CHANGE_LOG_FILE&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">commit_message&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;Updated Swagger JSON to match API changes.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">commit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;-m&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">commit_message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Pushing changes to documentation repository...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">repo&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">git&lt;/span>&lt;span class="o">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;origin&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s2">&amp;#34;main&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Swagger JSON updated and pushed successfully!&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="vm">__name__&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;__main__&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">clone_api_repo&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">new_swagger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">fetch_swagger_file&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">old_swagger&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">load_current_swagger&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">changes&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">detect_changes&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">old_swagger&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">new_swagger&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="n">changes&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;Changes detected! Updating documentation...&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">update_swagger_file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">new_swagger&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">append_to_changelog&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">changes&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">commit_and_push&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;✅ Documentation successfully updated.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">else&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s2">&amp;#34;No changes detected. Documentation is already up to date.&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">except&lt;/span> &lt;span class="ne">Exception&lt;/span> &lt;span class="k">as&lt;/span> &lt;span class="n">e&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">print&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">f&lt;/span>&lt;span class="s2">&amp;#34;❌ Error: &lt;/span>&lt;span class="si">{&lt;/span>&lt;span class="n">e&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">exit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="-step-3-run-the-script">📌 Step 3: Run the Script
&lt;/h2>&lt;p>The documentation team can now update the API docs with:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">python update_swagger.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="-step-4-automate-updates-with-jenkins">🔥 Step 4: Automate Updates with Jenkins
&lt;/h2>&lt;p>If the docs team wants to &lt;strong>automate this&lt;/strong>, add it to &lt;strong>Jenkins&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>Open &lt;strong>Jenkins Dashboard&lt;/strong> → &lt;strong>New Item&lt;/strong> → &lt;strong>Freestyle Project&lt;/strong>&lt;/li>
&lt;li>Name it &lt;strong>Update-Swagger-Docs&lt;/strong>&lt;/li>
&lt;li>Under &lt;strong>Source Code Management&lt;/strong>, choose &lt;strong>Git&lt;/strong>, and add the &lt;strong>documentation repo URL&lt;/strong>&lt;/li>
&lt;li>Under &lt;strong>Build Triggers&lt;/strong>, enable &lt;strong>Poll SCM&lt;/strong> (&lt;code>H/10 * * * *&lt;/code>).&lt;/li>
&lt;li>Under &lt;strong>Build Steps → Execute Shell&lt;/strong>, add:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-sh" data-lang="sh">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#!/bin/bash
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> /var/lib/jenkins/workspace/API-Docs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git pull origin main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">python3 update_swagger.py
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;!--
6. **Save &amp; Build Now**
Now Jenkins will **auto-sync Swagger JSON** whenever the API changes.
---
## 🎯 Conclusion: Keep Docs Up to Date, Keep Jenkins Happy
✅ **Docs team can now update Swagger JSON easily**
✅ **Prevents build failures due to outdated docs**
✅ **Automates updates using Jenkins**
With this, your API documentation stays **fresh**, Jenkins stays **green**, and the team stays **happy**. 😃
Now go forth and **automate your API docs like a pro!** 🚀
---
## 🔑 Key Takeaways
| Summary | Details |
|---------------|---------|
| **Why update Swagger JSON?** | Prevent Jenkins build failures due to outdated API docs. |
| **What does this script do?** | Pulls latest `swagger.json`, updates docs, commits &amp; pushes. |
| **Which libraries are used?** | `GitPython` for Git commands, `jsondiff` for Swagger comparison. |
| **How does Jenkins help?** | Automates API documentation updates. |
| **How to run the script manually?** | `python update_swagger.py` |
| **How to automate it?** | Add to a Jenkins job with `python3 update_swagger.py`. |
```
--></description></item></channel></rss>