Files
nexus/sreweekly/articles/150/01-5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-co.html
2026-09-12 17:23:01 +08:00

590 lines
79 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html data-wf-domain="www.gruntwork.io" data-wf-page="67f979d81d1c2b91340833aa" data-wf-site="67f94fda8156ff7b19690b57" lang="en" data-wf-collection="67f979d81d1c2b9134083359" data-wf-item-slug="5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code">
<head><meta charset="utf-8"><title>Infrastructure code: 5 lessons from 300,000 lines</title><meta content="Infrastructure code lessons from a HashiConf 2018 talk by Gruntwork, with the video, the slides, and a condensed written version of five key takeaways." name="description"/><meta content="Infrastructure code: 5 lessons from 300,000 lines" property="og:title"/><meta content="Infrastructure code lessons from a HashiConf 2018 talk by Gruntwork, with the video, the slides, and a condensed written version of five key takeaways." property="og:description"/><meta content="https://www.gruntwork.io/_assets/media/blog-5-lessons-learned-writing-over-300-000-lines-1.png" property="og:image"/><meta content="Infrastructure code: 5 lessons from 300,000 lines" name="twitter:title"/><meta content="Infrastructure code lessons from a HashiConf 2018 talk by Gruntwork, with the video, the slides, and a condensed written version of five key takeaways." name="twitter:description"/><meta content="https://www.gruntwork.io/_assets/media/blog-5-lessons-learned-writing-over-300-000-lines-1.png" name="twitter:image"/><meta property="og:type" content="website"/><meta content="summary_large_image" name="twitter:card"/><meta content="width=device-width, initial-scale=1" name="viewport"><meta content="3re3MoFNLbPNORg0xRkES7tGiMwZo2z-id0m0NsCW1E" name="google-site-verification"><script src="/_assets/ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js" type="text/javascript"></script><script type="text/javascript">
WebFont.load({
custom: {
families: ['Geist Mono', 'Inter'],
urls: ['/_assets/fonts.googleapis.com/css.43f4a82175de.2d399752.css'],
},
});
</script><script type="text/javascript">
!(function (o, c) {
var n = c.documentElement,
t = ' w-mod-';
((n.className += t + 'js'),
('ontouchstart' in o || (o.DocumentTouch && c instanceof DocumentTouch)) &&
(n.className += t + 'touch'));
})(window, document);
</script><link href="/_assets/media/favicon.png" rel="shortcut icon" type="image/x-icon"><link href="/_assets/media/social-icon-glacier-on-midnight-2x.png" rel="apple-touch-icon"><link href="https://www.gruntwork.io/blog/5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code" rel="canonical"/><script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = '/mtag/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-5TTJJGTL');
</script><script type="text/javascript">
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('set', 'developer_id.dZGVlNj', true);
gtag('set', 'developer_id.dYWYxNW', true);
gtag('js', new Date());
gtag('config', 'GTM-5TTJJGTL');
</script><meta property="og:image:secure_url" content="https://www.gruntwork.io/_assets/cdn.prod.website-files.com/67f94fda8156ff7b19690b57/68b66fa7bf9d6c42875cbb68_Social-Card-Gruntwork.io1200x630.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<style>
.dropdown-tog.w-dropdown-toggle.w--open > .dropdown-label {
background-color: var(--overlays--opacity-10);
}
.dropdown-tog.w-dropdown-toggle.w--open > .dropdown-label > .icon-4 {
transform: rotate(180deg);
}
.g-recaptcha {
display: block !important;
}
</style><script>
if (window.location.pathname === '/blog/why-i-use-terragrunt-over-terraform-opentofu-in-2025') {
var meta = document.createElement('meta');
meta.name = 'robots';
meta.content = 'noindex, nofollow';
document.head.appendChild(meta);
}
</script>
<style>
.gradient-border {
border: solid 1px transparent;
border-radius: 12px;
background-image:
-webkit-linear-gradient(#0F0726, #0F0726),
radial-gradient(circle 50px at left 0 bottom 40px, #6CCEDA, transparent),
radial-gradient(circle farthest-corner at 100% 80%, #FFFFFF55, #343956);
background-image:
-moz-linear-gradient(#0F0726, #0F0726),
radial-gradient(circle 50px at left 0 bottom 40px, #6CCEDA, transparent),
radial-gradient(circle farthest-corner at 100% 80%, #FFFFFF55, #343956);
background-image:
-o-linear-gradient(#0F0726, #0F0726),
radial-gradient(circle 50px at left 0 bottom 40px, #6CCEDA, transparent),
radial-gradient(circle farthest-corner at 100% 80%, #FFFFFF55, #343956);
background-image:
linear-gradient(#0F0726, #0F0726),
radial-gradient(circle 50px at left 0 bottom 40px, #6CCEDA, transparent),
radial-gradient(circle farthest-corner at 100% 80%, #FFFFFF55, #343956);
background-origin: border-box;
background-clip: padding-box, border-box, border-box;
}
</style><script>window.__FORM_BRIDGE__={"pageName":"","endpoint":"/ftag","siteId":"67f94fda8156ff7b19690b57","forms":{}};</script><script src="/_form-bridge.js" defer></script><link rel="stylesheet" href="/_astro/SiteHead.Dfqs6W6l.css">
<link rel="stylesheet" href="/_astro/_slug_.B71nJL7v.css"></head><body class="body blog"><nav data-figma-id="206:7371" class="navbar">
<div class="w-layout-blockcontainer navbar-inner-wrapper w-container">
<div data-animation="over-right" class="global-nav w-nav" data-easing2="ease" data-easing="ease" data-collapse="medium" role="banner" data-no-scroll="1" data-duration="400" data-doc-height="1">
<div class="navbar-inner-container w-container">
<a href="/" class="nav-logo-link w-inline-block"><img class="gruntwork-logotype-black-2" src="/_assets/media/gruntwork-logotype-black.svg" data-figma-image-id="68015d50397c30ba14b5763f" alt="" data-figma-id="206:7374" data-figma-image-hash="48fa76d53936e0afd4446a63bb8236f3" loading="lazy"></a><nav role="navigation" class="nav-menu w-nav-menu">
<a href="/accelerator" class="nav-link w-nav-link">Accelerator</a><div data-hover="true" data-delay="170" data-w-id="f1c11b7a-7779-b915-f346-0cb911adf448" class="dropdown w-dropdown">
<div class="dropdown-tog w-dropdown-toggle">
<div class="menu-label">Solutions</div><div class="nav-arrow w-icon-dropdown-toggle">
</div>
</div><nav class="dropdown-list solutions w-dropdown-list">
<div class="dropdown-list-container">
<a href="/solutions/ai-infrastructure-delivery" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/cpu.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">AI Infrastructure Delivery</div><div class="link-description">
</div>
</div></a><a href="/solutions/aws-landing-zone" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/airplane-landing.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">AWS Landing Zone</div><div class="link-description">
</div>
</div></a><a href="/solutions/gcp-landing-zone" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/airplane-landing.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">GCP Landing Zone</div><div class="link-description">
</div>
</div></a><a href="/solutions/azure-landing-zone" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/airplane-landing.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Azure Landing Zone</div><div class="link-description">
</div>
</div></a><a href="/solutions/hipaa-compliant-infra" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/asclepius.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">HIPAA Compliant Infra</div><div class="link-description">
</div>
</div></a><a href="/solutions/iac-residency" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/lighthouse.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">IaC Residency</div><div class="link-description"></div>
</div></a>
</div>
</nav>
</div><div data-hover="true" data-delay="170" data-w-id="23babe82-25c8-2ee7-e42c-4818b2d5da67" class="dropdown w-dropdown">
<div class="dropdown-tog w-dropdown-toggle">
<div class="menu-label">Platform</div><div class="nav-arrow w-icon-dropdown-toggle">
</div>
</div><nav class="dropdown-list platform w-dropdown-list">
<div class="dropdown-list-container">
<a href="/platform/pipelines" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/product-icon-pipelines.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Pipelines</div><div class="link-description">
Deploy infrastructure changes
</div>
</div></a><a href="/platform/account-factory" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/product-icon-account-factory.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Account Factory</div><div class="link-description">
Stamp out new AWS accounts
</div>
</div></a><a href="/platform/iac-library" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/product-icon-iac-library.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">IaC Library</div><div class="link-description">
Use best practices from thought leaders
</div>
</div></a><a href="/platform/patcher" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/product-icon-patcher.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Patcher</div><div class="link-description">
Keep infrastructure up to date
</div>
</div></a>
</div>
</nav>
</div><div data-hover="true" data-delay="0" data-w-id="de6ed864-f85d-e8a9-ace2-9b050e1921e5" class="dropdown w-dropdown">
<div class="dropdown-tog w-dropdown-toggle">
<div class="menu-label">Open Source</div><div class="nav-arrow w-icon-dropdown-toggle">
</div>
</div><nav class="dropdown-list w-dropdown-list">
<div class="dropdown-list-container">
<a href="/open-source" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/home-1.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Open Source</div><div class="link-description"></div>
</div></a><a href="/services/opentofu" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/opentofu-icon-services.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">OpenTofu Services</div><div class="link-description">
</div>
</div></a><a href="/services/terragrunt" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/logo-light.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Terragrunt Services</div><div class="link-description">
</div>
</div></a>
</div>
</nav>
</div><a href="/pricing" class="nav-link w-nav-link">Pricing</a><div data-hover="true" data-delay="0" data-w-id="b7c6ed9a-59ad-6285-f72a-0d866bc8d534" class="dropdown w-dropdown">
<div class="dropdown-tog w-dropdown-toggle">
<div class="menu-label">Resources</div><div class="nav-arrow w-icon-dropdown-toggle">
</div>
</div><nav class="dropdown-list w-dropdown-list">
<div class="dropdown-list-container">
<a href="https://docs.gruntwork.io" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/home-2.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Docs</div><div class="link-description"></div>
</div></a><a href="/customer-stories" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/icon-handshake.png" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Customer Stories</div><div class="link-description">
</div>
</div></a><a href="/blog" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/home-3.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Blog</div><div class="link-description"></div>
</div></a><a href="/changelog" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/icon-clock-counterclockwise.png" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Changelog</div><div class="link-description"></div>
</div></a><a href="/books" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/home-4.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Books</div><div class="link-description"></div>
</div></a><a href="/resources/community" class="dropdown-link-block w-inline-block"><div class="navbaricon">
<img width="16" height="16" alt="" src="/_assets/media/home-5.svg" loading="lazy" class="producticons">
</div><div class="link-label">
<div class="link-title">Community</div><div class="link-description"></div>
</div></a>
</div>
</nav>
</div>
</nav><div data-figma-id="206:7390" class="nav-cta">
<div class="desktop-up">
<div data-figma-id="206:7391" data-wf--textbutton--variant="base" class="text-button">
<a href="https://app.gruntwork.io" target="_blank" class="text-button-link w-inline-block"><p data-figma-id="I206:7391;717:7964" class="text-button-label-text">
Sign In
</p><div class="text-button-icon-container">
<img src="/_assets/media/home-6.svg" loading="lazy" alt="">
</div></a>
</div>
</div><div data-figma-id="205:7249" data-wf--primarybutton--variant="base" data-w-id="033e3097-30a2-6234-e57e-4268074b582d" class="primary-button-wrapper">
<a href="/contact" class="primary-button-link w-inline-block"><div data-w-id="08cbc67a-7bd4-5e1f-fe57-1e824a478c64" class="primary-button-color-container">
</div><div class="w-layout-hflex primary-button-label-container">
<div class="primary-button-label">Book a demo</div><img src="/_assets/media/home-7.svg" loading="lazy" data-w-id="90ed8e82-eb8d-6b33-bfdf-611d63b6fb1e" alt="" class="image-51">
</div></a>
</div>
</div><div class="menu-button w-nav-button"><div class="icon-3 w-icon-nav-menu"></div></div>
</div>
</div>
</div>
</nav><div class="w-embed"><style>
.w-code-block {
background: #1C1833 !important;
margin-bottom: 1em;
}
pre.w-code-block code > span {
display: inline !important;
}
</style>
<link rel="stylesheet" href="/_assets/esm.sh/prismjs@1.30.0/themes/prism-dark.f06e1a3b8008.css"></div><div class="w-layout-blockcontainer global-page-container w-container" data-astro-cid-kberb7c2>
<div class="back-to-blog-container" data-astro-cid-kberb7c2>
<a href="/blog" class="back-link w-inline-block" data-astro-cid-kberb7c2><div class="back-icon-container" data-astro-cid-kberb7c2>
<div class="w-embed" data-astro-cid-kberb7c2>
<svg width="10" height="9" viewBox="0 0 10 9" fill="none" xmlns="http://www.w3.org/2000/svg" data-astro-cid-kberb7c2>
<path d="M0.610182 4.7653L3.98499 8.14011C4.05536 8.21047 4.15079 8.25 4.25029 8.25C4.3498 8.25 4.44523 8.21047 4.51559 8.14011C4.58595 8.06975 4.62548 7.97432 4.62548 7.87481C4.62548 7.77531 4.58595 7.67988 4.51559 7.60951L1.78059 4.87498H9.12502C9.22447 4.87498 9.31985 4.83547 9.39017 4.76515C9.46049 4.69483 9.5 4.59945 9.5 4.5C9.5 4.40055 9.46049 4.30517 9.39017 4.23485C9.31985 4.16453 9.22447 4.12502 9.12502 4.12502H1.78059L4.51559 1.39049C4.58595 1.32012 4.62548 1.22469 4.62548 1.12519C4.62548 1.02568 4.58595 0.930251 4.51559 0.85989C4.44523 0.789529 4.3498 0.75 4.25029 0.75C4.15079 0.75 4.05536 0.789529 3.98499 0.85989L0.610182 4.2347C0.575318 4.26953 0.547659 4.31088 0.528789 4.3564C0.509918 4.40193 0.500206 4.45072 0.500206 4.5C0.500206 4.54928 0.509918 4.59807 0.528789 4.64359C0.547659 4.68912 0.575318 4.73047 0.610182 4.7653Z" fill="currentColor" data-astro-cid-kberb7c2></path>
</svg>
</div>
</div><span class="support-tier-body" data-astro-cid-kberb7c2>Back to Blog</span></a>
</div><div class="w-layout-blockcontainer content-wrapper w-container" data-astro-cid-kberb7c2>
<div class="header-blog-post" data-astro-cid-kberb7c2>
<div class="tags-container" data-astro-cid-kberb7c2>
<div class="collection-list-wrapper-8 w-dyn-list" data-astro-cid-kberb7c2>
<div role="list" class="blog-tags-collection-list w-dyn-items" data-astro-cid-kberb7c2>
<div role="listitem" class="w-dyn-item" data-astro-cid-kberb7c2>
<div class="category-pill" data-astro-cid-kberb7c2>
<div class="pill-text" data-astro-cid-kberb7c2>Devops</div>
</div>
</div><div role="listitem" class="w-dyn-item" data-astro-cid-kberb7c2>
<div class="category-pill" data-astro-cid-kberb7c2>
<div class="pill-text" data-astro-cid-kberb7c2>Infrastructure-As-Code</div>
</div>
</div><div role="listitem" class="w-dyn-item" data-astro-cid-kberb7c2>
<div class="category-pill" data-astro-cid-kberb7c2>
<div class="pill-text" data-astro-cid-kberb7c2>Aws</div>
</div>
</div><div role="listitem" class="w-dyn-item" data-astro-cid-kberb7c2>
<div class="category-pill" data-astro-cid-kberb7c2>
<div class="pill-text" data-astro-cid-kberb7c2>Software-Engineering</div>
</div>
</div><div role="listitem" class="w-dyn-item" data-astro-cid-kberb7c2>
<div class="category-pill" data-astro-cid-kberb7c2>
<div class="pill-text" data-astro-cid-kberb7c2>Gruntwork-Talks</div>
</div>
</div>
</div>
</div>
</div><h1 class="blog-h1" data-astro-cid-kberb7c2>5 Lessons Learned From Writing Over 300,000 Lines of Infrastructure Code</h1><h2 class="body-18 w-condition-invisible w-dyn-bind-empty" data-astro-cid-kberb7c2>
</h2><div class="w-layout-hflex blog-author-box"><div class="w-layout-hflex author-block"><div class="author-picture"><img loading="lazy" width="20" height="20" alt="Yevgeniy &quot;Jim&quot; Brikman" class="blog-author-headshot-large" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fyevgeniy-brikman-2.png&w=256&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fyevgeniy-brikman-2.png&w=256&q=75 256w" sizes="(max-width: 20px) 100vw, 20px"/></div><div class="blog-author-name"><div class="name color-primary">Yevgeniy</div><div class="name color-primary">Brikman</div></div><div class="geist color-tertiary">, </div><div class="geist color-tertiary">Co-Founder, Board Member</div><div class="div-block-47"><div class="geist color-tertiary">November 20, 2018</div></div></div>
</div>
</div><div class="full-width-blog-image" data-astro-cid-kberb7c2>
<img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-1.png&amp;w=1920&amp;q=75" loading="lazy" alt class="image-68" data-astro-cid-kberb7c2>
</div><div class="blog-page-content" data-astro-cid-kberb7c2>
<div class="gruntworklongformrichtext w-richtext" data-astro-cid-kberb7c2>
<h3 id="a-concise-masterclass-on-how-to-write-infrastructure-code">A concise masterclass on how to write infrastructure code</h3><p>This October, I gave a talk at HashiConf 2018 where I shared 5 key lessons we learned at Gruntwork while creating and maintaining a <a href="https://gruntwork.io/infrastructure-as-code-library/">library of over 300,000 lines of infrastructure code</a> that’s used in production by hundreds of companies. In this blog post, I’ll share with you the video and slides from the talk, as well as a condensed, written version of the 5 key lessons.</p><h2 id="video-and-slides">Video and slides</h2><figure id class="w-richtext-figure-type-video w-richtext-align-fullwidth" data-rt-type="video" data-rt-align="fullwidth" data-rt-max-width data-rt-max-height="56.206088992974244%" data-rt-dimensions="854:480" data-page-url="https://www.youtube.com/watch?v=RTEgE2lcyk4" style="padding-bottom:56.206088992974244%"><div id><iframe src="https://www.youtube.com/embed/RTEgE2lcyk4" title="5 Lessons Learned From Writing Over 300,000 Lines of Infrastructure Code" scrolling="no" frameborder="0" allowfullscreen></iframe></div></figure><p>‍</p><iframe src="https://www.slideshare.net/slideshow/embed_code/key/2UJpiOB2oG10Jo?startSlide=1" width="597" height="486" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" allowfullscreen style="border:var(--border-1) solid #ccc;border-width:1px;margin-bottom:5px;max-width:100%"></iframe><p><strong><a href="https://www.slideshare.net/brikis98/lessons-learned-from-writing-over-300000-lines-of-infrastructure-code-120597849" title="Lessons learned from writing over 300,000 lines of infrastructure code">Lessons learned from writing over 300,000 lines of infrastructure code</a></strong> from <strong><a href="https://www.slideshare.net/brikis98">Yevgeniy Brikman</a></strong></p><h2 id="intro-devops-is-in-the-stone-ages">Intro: DevOps is in the stone ages</h2><p>Although the industry is full of cutting-edge buzzwords—Kubernetes, microservices, service meshes, immutable infrastructure, big data, data lakes, etc—the reality is that when you’re knee deep in building infrastructure, it doesn’t <em>feel</em> cutting edge.</p><p>To me, DevOps feels more like this:</p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 300px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="300px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-2.webp&amp;w=384&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-2.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-2.webp&amp;w=384&amp;q=75 384w" sizes="(max-width: 300px) 100vw, 300px" width="auto" height="auto" loading="lazy"/></div><figcaption>#thisisdevops</figcaption></figure><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 553px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="553px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-3.webp&amp;w=640&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-3.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-3.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-3.webp&amp;w=640&amp;q=75 640w" sizes="(max-width: 553px) 100vw, 553px" width="auto" height="auto" loading="lazy"/></div><figcaption>#thisisdevops</figcaption></figure><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 500px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="500px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-4.webp&amp;w=640&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-4.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-4.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-4.webp&amp;w=640&amp;q=75 640w" sizes="(max-width: 500px) 100vw, 500px" width="auto" height="auto" loading="lazy"/></div><figcaption>#thisisdevops</figcaption></figure><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 300px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="300px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-5.webp&amp;w=384&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-5.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-5.webp&amp;w=384&amp;q=75 384w" sizes="(max-width: 300px) 100vw, 300px" width="auto" height="auto" loading="lazy"/></div><figcaption>(your company’s CI/CD pipeline) #thisisdevops</figcaption></figure><p>Building production-grade infrastructure is hard. And stressful. And time consuming. Very time consuming.</p><p>Here’s roughly how long you should expect your next infrastructure project to take, based on empirical data we’ve gathered while working with hundreds of different companies:</p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 1763px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="1763px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=1920&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=640&amp;q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=828&amp;q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=1080&amp;q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=1200&amp;q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=1600&amp;q=75 1600w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-6.webp&amp;w=1920&amp;q=75 1920w" sizes="(max-width: 1763px) 100vw, 1763px" width="auto" height="auto" loading="lazy"/></div></figure><h2 id="lesson-1-the-production-grade-infrastructure-checklist">Lesson 1: The Production-Grade Infrastructure Checklist</h2><p>DevOps projects <em>always</em> take way longer than you expect. <em>Always</em>. Why is that?</p><p>Well, the first reason is <a href="https://seths.blog/2005/03/dont_shave_that/">Yak Shaving</a>, as perfectly illustrated in this clip from <em>Malcolm in the Middle:</em></p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 216px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="216px"><div><img src="/_assets/media/blog-5-lessons-learned-writing-over-300-000-lines-7.gif" alt="__wf_reserved_inherit" width="auto" height="auto" loading="lazy"/></div></figure><p>The second reason is that building <em>production-grade infrastructure</em> (as in, the type of infrastructure you’d bet your company on) involves a thousand little details. The vast majority of developers don’t know what those details are, so when you’re estimating a project, you usually forget about number of critical—and time consuming—details.</p><p>To avoid this issue, every time you go to work on a new piece of infrastructure, go through the following checklist:</p><h4 id="the-production-grade-infrastructure-checklist">The Production-Grade Infrastructure Checklist</h4><table><thead><tr><th>Task</th><th>Description</th><th>Example tools</th></tr></thead><tbody><tr><td><strong>Install</strong></td><td>Install the software binaries and all dependencies.</td><td>Bash, Chef, Ansible, Puppet</td></tr><tr><td><strong>Configure</strong></td><td>Configure the software at runtime: e.g., port settings, file paths, users, leaders, followers, replication, etc.</td><td>Bash, Chef, Ansible, Puppet</td></tr><tr><td><strong>Provision</strong></td><td>Provision the infrastructure: e.g., EC2 instances, load balancers, network topology, security groups, IAM permissions, etc.</td><td>Terraform, CloudFormation</td></tr><tr><td><strong>Deploy</strong></td><td>Deploy the service on top of the infrastructure, and roll out updates with no downtime: e.g., blue-green, rolling, canary deployments.</td><td>Scripts, orchestration tools such as ECS, Kubernetes, Nomad</td></tr><tr><td><strong>Security</strong></td><td>Encryption in transit (TLS) and on disk, authentication, authorization, secrets management, server hardening.</td><td>ACM, EBS volumes, Cognito, Vault, CIS</td></tr><tr><td><strong>Monitoring</strong></td><td>Availability metrics, business metrics, app metrics, server metrics, events, observability, tracing, alerting.</td><td>CloudWatch, Datadog, New Relic, Honeycomb</td></tr><tr><td><strong>Logs</strong></td><td>Rotate logs on disk, and aggregate log data to a central location.</td><td>CloudWatch Logs, ELK, Sumo Logic, Papertrail</td></tr><tr><td><strong>Backup and restore</strong></td><td>Make backups of DBs, caches, and other data on a scheduled basis, and replicate to a separate region/account.</td><td>RDS, ElastiCache, ec2-snapper, Lambda</td></tr><tr><td><strong>Networking</strong></td><td>VPCs, subnets, static and dynamic IPs, service discovery, service mesh, firewalls, DNS, SSH access, VPN access.</td><td>EIPs, ENIs, VPCs, NACLs, security groups, Route 53, OpenVPN</td></tr><tr><td><strong>High availability</strong></td><td>Withstand outages of individual processes, EC2 instances, services, Availability Zones, and regions.</td><td>Multi-AZ, multi-region, replication, ASGs, ELBs</td></tr><tr><td><strong>Scalability</strong></td><td>Scale up and down in response to load, horizontally (more servers) and/or vertically (bigger servers).</td><td>ASGs, replication, sharding, caching, divide and conquer</td></tr><tr><td><strong>Performance</strong></td><td>Optimize CPU, memory, disk, network, and GPU usage; query tuning, benchmarking, load testing, profiling.</td><td>Dynatrace, Valgrind, VisualVM, ab, JMeter</td></tr><tr><td><strong>Cost optimization</strong></td><td>Pick proper instance types, use spot and reserved instances, use auto scaling, remove unused resources.</td><td>ASGs, spot instances, reserved instances</td></tr><tr><td><strong>Documentation</strong></td><td>Document your code, architecture, and practices, and create playbooks to respond to incidents.</td><td>READMEs, wikis, Slack</td></tr><tr><td><strong>Tests</strong></td><td>Write automated tests for your infrastructure code, and run them after every commit and nightly.</td><td>Terratest</td></tr><tr><td><strong>Maintenance</strong></td><td>Update the software and tools (e.g., Terraform, Packer), update to the latest best practices, add new features, fix bugs, install security patches.</td><td>Human beings, Gruntwork commercial support</td></tr></tbody></table><p>Not every single piece of infrastructure needs every single item on the list, but you should consciously and explicitly document which items you’ve implemented, which ones you’ve decided to skip, and why.</p><p>A landing zone applies this same checklist one layer up, to the accounts, guardrails, and vending pipeline that every other piece of infrastructure runs inside. See <a href="https://www.gruntwork.io/blog/how-to-build-a-well-architected-aws-landing-zone">How to Build a Well-Architected AWS Landing Zone with OpenTofu/Terraform</a> for how the pieces above map onto that layer.</p><h2 id="lesson-2-the-toolset">Lesson 2: the toolset</h2><p>As of 2018, here are the primary tools we use at Gruntwork to build and manage infrastructure:</p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 1860px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="1860px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=1920&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=640&amp;q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=828&amp;q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=1080&amp;q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=1200&amp;q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=1600&amp;q=75 1600w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-9.webp&amp;w=1920&amp;q=75 1920w" sizes="(max-width: 1860px) 100vw, 1860px" width="auto" height="auto" loading="lazy"/></div></figure><ol><li><a href="https://terraform.io"><strong>Terraform</strong></a>: We use Terraform to provision all the basic infrastructure, including networking, load balancers, databases, users, permissions, and all of our servers.</li><li><a href="https://packer.io"><strong>Packer</strong></a>: We use Packer to define and build the virtual machine images we run on top of our servers.</li><li><a href="http://docker.com"><strong>Docker</strong></a>: Some of our servers form clusters where we run applications as Docker containers. The main Docker cluster tools we use are <a href="https://kubernetes.io/">Kubernetes</a>, <a href="https://aws.amazon.com/ecs/">ECS</a>, and <a href="https://aws.amazon.com/fargate/">Fargate</a>.</li></ol><p>Now, all of these tools are useful, but that’s not the real lesson here. The real lesson is that tools, by themselves, are not enough. You also need to change your team’s behavior.</p><p>In particular, the best tools in the world will not help your team one bit if your team isn’t bought into using those tools or if your team doesn’t have enough time to learn use those tools. Therefore, the key takeaway is that using infrastructure as code is an <em>investment</em>: there’s an up-front cost to get going, but if you invest wisely, you’ll earn big dividends over the long-term.</p><h2 id="lesson-3-large-modules-considered-harmful">Lesson 3: large modules considered harmful</h2><p>Infrastructure as code newbies often define <em>all</em> of their infrastructure for <em>all</em> of their environments (dev, stage, prod, etc) in a single file or single set of files that are deployed as a unit. This is a Bad Idea.</p><p>Here are just a few of the downsides:</p><ol><li><strong>Slow</strong>: If all your infrastructure is defined in one place, running any command will take a long time. We’ve seen companies where <code>terraform plan</code> takes 5–6 minutes to run!</li><li><strong>Insecure</strong>: If all your infrastructure is managed together, then to change <em>anything</em> you need permissions to access <em>everything</em>. That means that almost every user has to be an admin, which is another Bad Idea.</li><li><strong>Risky</strong>: If all your eggs are in one basket, then a mistake <em>anywhere</em> could break <em>everything</em>. You might be making a minor change to a frontend app in dev, but due to a typo or running the wrong command, you delete the production DB.</li><li><strong>Hard to understand</strong>: The more code you have in one place, the harder it is for any one person to understand it all. But if it’s all bundled together, the parts you don’t understand <em>could</em> hurt you.</li><li><strong>Hard to test</strong>: Testing infrastructure code is hard; testing a large amount of infrastructure code is nearly impossible. We’ll come back to this point later.</li><li><strong>Hard to review</strong>: The output of commands such as <code>terraform plan</code> becomes useless, as no one bothers to look through thousands of lines of plan output. Moreover, code reviews become useless:<a href="https://twitter.com/iamdevloper/status/397664295875805184">‍</a></li></ol><p>‍</p><blockquote><p>10 lines of code = 10 issues.<br/> <br/> 500 lines of code = &quot;looks fine.&quot;<br/> <br/> Code reviews.</p><p>— I Am Devloper (@iamdevloper) <a href="https://twitter.com/iamdevloper/status/397664295875805184?ref_src=twsrc%5Etfw">November 5, 2013</a></p></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><p>‍</p><p>In short, you should build your code out of small, standalone, reusable, composable modules. This is not a new or controversial insight. You’ve heard it a thousand times before, albeit in slightly different domains:</p><blockquote><em>“Do one thing and do it well”</em> —<a href="https://en.wikipedia.org/wiki/Unix_philosophy#Do_One_Thing_and_Do_It_Well"><em>Unix Philosophy</em></a></blockquote><blockquote><em>“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.”</em>—Clean Code</blockquote><h2 id="lesson-4-infrastructure-code-without-automated-tests-is-broken">Lesson 4: infrastructure code without automated tests is broken</h2><p>If your infrastructure code does not have automated tests, it’s broken. You just don’t know it yet. That said, testing infrastructure code is hard. You don’t really have “localhost” (e.g., you can’t deploy an AWS VPC on your laptop) and you don’t really have “unit tests” (e.g., you can’t isolate your Terraform code from the “outside” world as all Terraform does is talk to the outside world).</p><p>Therefore, to properly test your infrastructure code, you typically have to deploy it to a real environment, run real infrastructure, validate that it does what it should, and then tear it all down (for this style of testing, see <a href="https://blog.gruntwork.io/open-sourcing-terratest-a-swiss-army-knife-for-testing-infrastructure-code-5d883336fcd5">Terratest</a>, an open source library that includes tools for testing Terraform, Packer, and Docker code, working with AWS, GCP, and Kubernetes APIs, executing shell commands locally and on remote servers over SSH, and much more). What this means is that, with infrastructure testing, you have to slightly redefine terms:</p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 1492px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="1492px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=1600&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=640&amp;q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=828&amp;q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=1080&amp;q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=1200&amp;q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-10.webp&amp;w=1600&amp;q=75 1600w" sizes="(max-width: 1492px) 100vw, 1492px" width="auto" height="auto" loading="lazy"/></div></figure><ul><li><strong>Unit tests</strong> deploy and test one or a small number of closely related modules from one type of infrastructure (e.g., test the modules for a single database).</li><li><strong>Integration tests</strong> deploy and test multiple modules from different types of infrastructure to validate they work together correctly (e.g., test the modules of a database with the modules from a web service).</li><li><strong>End-to-end (e2e) tests</strong> deploy and test your entire architecture.</li></ul><p>Note that the diagram is a pyramid, where we have lots of unit tests, a smaller number of integration tests, and a very small number of e2e tests. Why? Because of how long each type of test takes:</p><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 1495px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="1495px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=1600&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=640&amp;q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=828&amp;q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=1080&amp;q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=1200&amp;q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-11.webp&amp;w=1600&amp;q=75 1600w" sizes="(max-width: 1495px) 100vw, 1495px" width="auto" height="auto" loading="lazy"/></div></figure><p>Cycle time with infrastructure tests is slow, especially as you go up the pyramid, so you’ll want to catch as many bugs as you can as low in the pyramid as you can. That means you should:</p><ol><li>Build small, simple, standalone modules (remember Lesson 3?) and write lots of unit tests for them to build your confidence that they work properly.</li><li>Combine these small, simple, battle-tested building blocks to create more complicated infrastructure that you test with a smaller number of integration and e2e tests.</li></ol><h2 id="lesson-5-the-release-process">Lesson 5: the release process</h2><p>Let’s now put everything in this talk together. Here’s how you’ll be building and managing infrastructure from now on:</p><ol><li>Go through the <a href="#lesson-1-the-production-grade-infrastructure-checklist">Production-Grade Infrastructure Checklist</a> to make sure you’re building the right thing.</li><li>Define your infrastructure as code using tools such as Terraform, Packer, and Docker. Make sure your team has the time to master these tools (see <a href="https://gruntwork.io/devops-resources/">DevOps Resources</a>).</li><li>Build your code out of small, standalone, composable modules (or use the off-the-shelf modules in the <a href="https://gruntwork.io/infrastructure-as-code-library/">Infrastructure as Code Library</a>).</li><li>Write automated tests for your modules using <a href="https://github.com/gruntwork-io/terratest">Terratest</a>.</li><li>Submit a pull request to get your code reviewed.</li><li>Release a new version of your code.</li><li>Promote that new version of your code from environment to environment.</li></ol><figure class="w-richtext-figure-type-image w-richtext-align-fullwidth" style="max-width: 1861px" data-rt-type="image" data-rt-align="fullwidth" data-rt-max-width="1861px"><div><img src="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=1920&amp;q=75" alt="__wf_reserved_inherit" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=256&amp;q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=384&amp;q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=640&amp;q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=828&amp;q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=1080&amp;q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=1200&amp;q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=1600&amp;q=75 1600w, /_vercel/image?url=%2F_assets%2Fmedia%2Fblog-5-lessons-learned-writing-over-300-000-lines-12.webp&amp;w=1920&amp;q=75 1920w" sizes="(max-width: 1861px) 100vw, 1861px" width="auto" height="auto" loading="lazy"/></div></figure><p><em>Get your DevOps superpowers at</em> <a href="https://gruntwork.io/?ref=blog-lessons-learned-300k"><em>Gruntwork.io</em></a><em>.</em></p>
</div><div class="blog-sign-up-container" data-astro-cid-kberb7c2>
<div class="h3" data-astro-cid-kberb7c2>Enjoyed the article?</div><div class="blog-sign-up-body-container" data-astro-cid-kberb7c2>
<span class="support-tier-body inter-body-copy---feature large color-secondary" data-astro-cid-kberb7c2>We’ve got more where that came from. Sign up to get fresh DevOps content delivered right
to you.</span>
</div><div data-wf--divider--variant="purple-no-margin" class="divider-container w-variant-7e18f0cb-3078-4d49-850c-7a242983cea3" data-astro-cid-kberb7c2>
<img loading="lazy" sizes="100vw" alt="" class="divider-img blue w-variant-7e18f0cb-3078-4d49-850c-7a242983cea3" data-astro-cid-kberb7c2 src="/_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=1600&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=384&q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=640&q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=828&q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=1080&q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=1200&q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Findex-blue-divider-2.png&w=1600&q=75 1600w"><img loading="lazy" sizes="100vw" alt="" class="divider-img orange" data-astro-cid-kberb7c2 src="/_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=1600&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=384&q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=640&q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=828&q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=1080&q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=1200&q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Forange-divider.png&w=1600&q=75 1600w"><img loading="lazy" sizes="100vw" alt="" class="divider-img purple w-variant-7e18f0cb-3078-4d49-850c-7a242983cea3" data-astro-cid-kberb7c2 src="/_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=1600&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=384&q=75 384w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=640&q=75 640w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=828&q=75 828w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=1080&q=75 1080w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=1200&q=75 1200w, /_vercel/image?url=%2F_assets%2Fmedia%2Flarge-purple-divider.png&w=1600&q=75 1600w">
</div><div class="blog-signup-container gradient-border" data-astro-cid-kberb7c2>
<div data-astro-cid-kberb7c2>
<div class="text-block-8" data-astro-cid-kberb7c2>Only smart updates. Straight to your inbox.</div><ul role="list" class="blog-sign-up-list" data-astro-cid-kberb7c2>
<li class="list-item" data-astro-cid-kberb7c2>
<div class="list-item-text" data-astro-cid-kberb7c2>No-nonsense DevOps insights</div>
</li><li class="list-item" data-astro-cid-kberb7c2><div class="list-item-text" data-astro-cid-kberb7c2>Expert guidance</div></li><li class="list-item" data-astro-cid-kberb7c2>
<div class="list-item-text" data-astro-cid-kberb7c2>Latest trends on IaC, automation, and DevOps</div>
</li><li class="list-item" data-astro-cid-kberb7c2>
<div class="list-item-text" data-astro-cid-kberb7c2>Real-world best practices</div>
</li>
</ul>
</div><div class="hubspot-container" data-astro-cid-kberb7c2>
<div name="Form Block" class="astro-kberb7c2" data-astro-cid-kberb7c2>
<form name="Form" data-name="Newsletter Registration" data-wf-page-id="67f94fda8156ff7b19690b5d" data-wf-element-id="47bd8805-5825-ab95-a2f7-4b12b18a0be4" class="form-3" data-astro-cid-kberb7c2>
<label for="email" class="label" data-astro-cid-kberb7c2>Your email</label><input type="email" name="email" data-name="Email" required="" id="email" placeholder="Your email here" autocomplete="email" class="newsletter-input" data-astro-cid-kberb7c2><label for="is_newsletter_subscriber" hidden="" data-astro-cid-kberb7c2>is_newsletter_subscriber</label><label for="is_newsletter_subscriber" class="label-2" data-astro-cid-kberb7c2><input type="hidden" name="is_newsletter_subscriber" hidden="" id="is_newsletter_subscriber" value="true" data-astro-cid-kberb7c2>is_newsletter_subscriber</label><input type="hidden" name="hutk" value="" data-astro-cid-kberb7c2><input type="hidden" name="ipAddress" value="" data-astro-cid-kberb7c2><input type="hidden" name="pageUri" value="" data-astro-cid-kberb7c2><input type="hidden" name="pageId" value="" data-astro-cid-kberb7c2><input type="hidden" name="pageName" value="" data-astro-cid-kberb7c2><button type="submit" class="_wf-hubspot-button" data-astro-cid-kberb7c2>Subscribe</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div><section class="related-articles" data-astro-cid-kberb7c2>
<div class="related-articles-title" data-astro-cid-kberb7c2><h3 data-astro-cid-kberb7c2>Related Articles</h3></div><div class="collection-list-wrapper-7 w-dyn-list" data-astro-cid-kberb7c2>
<div role="list" class="related-collection-list w-dyn-items" data-astro-cid-kberb7c2>
<div role="listitem" class="collection-item-7 w-dyn-item" data-astro-cid-kberb7c2>
<div data-wf--blog-card--variant="base" class="sm-blog-card">
<a href="/blog/from-clickops-to-iac-a-practical-guide" class="link-block w-inline-block"><div class="w-layout-vflex flex-block-41">
<div class="blog-card-top">
<img loading="lazy" width="210.86419677734375" height="122" alt="" class="blog-card-blog-image" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fclickops-to-iac-2x.png&w=384&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fclickops-to-iac-2x.png&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fclickops-to-iac-2x.png&w=384&q=75 384w" sizes="(max-width: 210px) 100vw, 210px">
</div><div class="blog-card-bottom">
<div class="content-top">
<div class="category-pill"><div class="pill-text">DevOps</div></div><h6 fs-list-field="title" class="blog-title">
From ClickOps to IaC: a Practical Guide
</h6>
</div><div class="w-layout-hflex blog-author-box">
<div class="w-layout-hflex author-block">
<div class="profile-pic">
<img loading="lazy" width="20" height="20" alt="Ioannis Moustakis" class="blog-author-headshot" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fioannis.webp&w=256&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fioannis.webp&w=256&q=75 256w" sizes="(max-width: 20px) 100vw, 20px">
</div><div class="sm-blog-card-author-name">
<div class="by-text">By</div><div class="name">Ioannis Moustakis</div><div class="name">
</div>
</div><div class="blog-date"><div class="geist color-tertiary">July 31, 2026</div></div>
</div><div class="blog-link">
<div class="w-embed">
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M9.38982 4.2653L6.01501 7.64011C5.94464 7.71047 5.84921 7.75 5.74971 7.75C5.6502 7.75 5.55477 7.71047 5.48441 7.64011C5.41405 7.56975 5.37452 7.47432 5.37452 7.37481C5.37452 7.27531 5.41405 7.17988 5.48441 7.10951L8.21941 4.37498H0.874979C0.775528 4.37498 0.680151 4.33547 0.609829 4.26515C0.539507 4.19483 0.5 4.09945 0.5 4C0.5 3.90055 0.539507 3.80517 0.609829 3.73485C0.680151 3.66453 0.775528 3.62502 0.874979 3.62502H8.21941L5.48441 0.890485C5.41405 0.820124 5.37452 0.724694 5.37452 0.625188C5.37452 0.525682 5.41405 0.430251 5.48441 0.35989C5.55477 0.289529 5.6502 0.25 5.74971 0.25C5.84921 0.25 5.94464 0.289529 6.01501 0.35989L9.38982 3.7347C9.42468 3.76953 9.45234 3.81088 9.47121 3.85641C9.49008 3.90193 9.49979 3.95072 9.49979 4C9.49979 4.04928 9.49008 4.09807 9.47121 4.14359C9.45234 4.18912 9.42468 4.23047 9.38982 4.2653Z"></path>
</svg>
</div>
</div>
</div>
</div>
</div></a><div fs-list-field="category" class="hidden-category-filter">DevOps</div>
</div>
</div><div role="listitem" class="collection-item-7 w-dyn-item" data-astro-cid-kberb7c2>
<div data-wf--blog-card--variant="base" class="sm-blog-card">
<a href="/blog/how-to-build-a-well-architected-aws-landing-zone" class="link-block w-inline-block"><div class="w-layout-vflex flex-block-41">
<div class="blog-card-top">
<img loading="lazy" width="210.86419677734375" height="122" alt="" class="blog-card-blog-image" src="/_vercel/image?url=%2F_assets%2Fmedia%2Flanding-zones.webp&w=384&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Flanding-zones.webp&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Flanding-zones.webp&w=384&q=75 384w" sizes="(max-width: 210px) 100vw, 210px">
</div><div class="blog-card-bottom">
<div class="content-top">
<div class="category-pill"><div class="pill-text">DevOps</div></div><h6 fs-list-field="title" class="blog-title">
How to Build a Well-Architected AWS Landing Zone with OpenTofu/Terraform
</h6>
</div><div class="w-layout-hflex blog-author-box">
<div class="w-layout-hflex author-block">
<div class="profile-pic">
<img loading="lazy" width="20" height="20" alt="Ioannis Moustakis" class="blog-author-headshot" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fioannis-moustakis.webp&w=256&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fioannis-moustakis.webp&w=256&q=75 256w" sizes="(max-width: 20px) 100vw, 20px">
</div><div class="sm-blog-card-author-name">
<div class="by-text">By</div><div class="name">Ioannis Moustakis</div><div class="name">
</div>
</div><div class="blog-date"><div class="geist color-tertiary">June 26, 2026</div></div>
</div><div class="blog-link">
<div class="w-embed">
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M9.38982 4.2653L6.01501 7.64011C5.94464 7.71047 5.84921 7.75 5.74971 7.75C5.6502 7.75 5.55477 7.71047 5.48441 7.64011C5.41405 7.56975 5.37452 7.47432 5.37452 7.37481C5.37452 7.27531 5.41405 7.17988 5.48441 7.10951L8.21941 4.37498H0.874979C0.775528 4.37498 0.680151 4.33547 0.609829 4.26515C0.539507 4.19483 0.5 4.09945 0.5 4C0.5 3.90055 0.539507 3.80517 0.609829 3.73485C0.680151 3.66453 0.775528 3.62502 0.874979 3.62502H8.21941L5.48441 0.890485C5.41405 0.820124 5.37452 0.724694 5.37452 0.625188C5.37452 0.525682 5.41405 0.430251 5.48441 0.35989C5.55477 0.289529 5.6502 0.25 5.74971 0.25C5.84921 0.25 5.94464 0.289529 6.01501 0.35989L9.38982 3.7347C9.42468 3.76953 9.45234 3.81088 9.47121 3.85641C9.49008 3.90193 9.49979 3.95072 9.49979 4C9.49979 4.04928 9.49008 4.09807 9.47121 4.14359C9.45234 4.18912 9.42468 4.23047 9.38982 4.2653Z"></path>
</svg>
</div>
</div>
</div>
</div>
</div></a><div fs-list-field="category" class="hidden-category-filter">DevOps</div>
</div>
</div><div role="listitem" class="collection-item-7 w-dyn-item" data-astro-cid-kberb7c2>
<div data-wf--blog-card--variant="base" class="sm-blog-card">
<a href="/blog/devops-field-guide-your-infrastructure-repo-is-a-mess-here-s-how-to-fix-it" class="link-block w-inline-block"><div class="w-layout-vflex flex-block-41">
<div class="blog-card-top">
<img loading="lazy" width="210.86419677734375" height="122" alt="" class="blog-card-blog-image" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fconcept-3-hierarchical-tree-v2.webp&w=384&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fconcept-3-hierarchical-tree-v2.webp&w=256&q=75 256w, /_vercel/image?url=%2F_assets%2Fmedia%2Fconcept-3-hierarchical-tree-v2.webp&w=384&q=75 384w" sizes="(max-width: 210px) 100vw, 210px">
</div><div class="blog-card-bottom">
<div class="content-top">
<div class="category-pill"><div class="pill-text">DevOps</div></div><h6 fs-list-field="title" class="blog-title">
DevOps Field Guide: Your Infrastructure Repo Is a Mess (Here&#39;s How to Fix It)
</h6>
</div><div class="w-layout-hflex blog-author-box">
<div class="w-layout-hflex author-block">
<div class="profile-pic">
<img loading="lazy" width="20" height="20" alt class="blog-author-headshot" src="/_vercel/image?url=%2F_assets%2Fmedia%2Fabout-1.jpeg&w=256&q=75" srcset="/_vercel/image?url=%2F_assets%2Fmedia%2Fabout-1.jpeg&w=256&q=75 256w" sizes="(max-width: 20px) 100vw, 20px">
</div><div class="sm-blog-card-author-name">
<div class="by-text">By</div><div class="name">Brian</div><div class="name">
Torres
</div>
</div><div class="blog-date"><div class="geist color-tertiary">May 19, 2026</div></div>
</div><div class="blog-link">
<div class="w-embed">
<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor" d="M9.38982 4.2653L6.01501 7.64011C5.94464 7.71047 5.84921 7.75 5.74971 7.75C5.6502 7.75 5.55477 7.71047 5.48441 7.64011C5.41405 7.56975 5.37452 7.47432 5.37452 7.37481C5.37452 7.27531 5.41405 7.17988 5.48441 7.10951L8.21941 4.37498H0.874979C0.775528 4.37498 0.680151 4.33547 0.609829 4.26515C0.539507 4.19483 0.5 4.09945 0.5 4C0.5 3.90055 0.539507 3.80517 0.609829 3.73485C0.680151 3.66453 0.775528 3.62502 0.874979 3.62502H8.21941L5.48441 0.890485C5.41405 0.820124 5.37452 0.724694 5.37452 0.625188C5.37452 0.525682 5.41405 0.430251 5.48441 0.35989C5.55477 0.289529 5.6502 0.25 5.74971 0.25C5.84921 0.25 5.94464 0.289529 6.01501 0.35989L9.38982 3.7347C9.42468 3.76953 9.45234 3.81088 9.47121 3.85641C9.49008 3.90193 9.49979 3.95072 9.49979 4C9.49979 4.04928 9.49008 4.09807 9.47121 4.14359C9.45234 4.18912 9.42468 4.23047 9.38982 4.2653Z"></path>
</svg>
</div>
</div>
</div>
</div>
</div></a><div fs-list-field="category" class="hidden-category-filter">DevOps</div>
</div>
</div>
</div>
</div>
</section></div><div class="w-embed w-script"><script>
// analyze the dom, find headings, build toc
// put toc into a div
</script></div><section data-wf--footer--variant="base" class="footer-section">
<div class="w-layout-blockcontainer footer-inner-container w-container">
<div class="w-layout-blockcontainer footer-logo w-container">
<div class="company">
<img src="/_assets/media/gruntwork-logotype-black-2.svg" loading="lazy" alt="" class="gruntwork-logo"><div class="copyright-text">© 2026 Gruntwork, Inc.</div>
</div><div class="w-layout-hflex social-links">
<div data-wf--social-link-w-icon--variant="github" class="social-link-container">
<a href="https://github.com/gruntwork-io" target="_blank" class="social-link w-variant-2495b6c4-7fcd-af23-53c1-e2d3373a330c w-inline-block"><div class="github w-variant-2495b6c4-7fcd-af23-53c1-e2d3373a330c w-embed">
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.11152 0C2.72402 0 -0.000976562 2.75 -0.000976562 6.15C-0.000976562 8.875 1.74902 11.175 4.17402 11.9875C4.47402 12.05 4.58652 11.85 4.58652 11.6875C4.58652 11.55 4.57402 11.05 4.57402 10.55C2.87402 10.9125 2.52402 9.8125 2.52402 9.8125C2.24902 9.1 1.84902 8.9125 1.84902 8.9125C1.29902 8.5375 1.88652 8.5375 1.88652 8.5375C2.49902 8.575 2.82402 9.175 2.82402 9.175C3.37402 10.1125 4.24902 9.85 4.59902 9.6875C4.64902 9.2875 4.81152 9.0125 4.98652 8.8625C3.63652 8.725 2.21152 8.1875 2.21152 5.825C2.21152 5.15 2.44902 4.6 2.83652 4.175C2.77402 4.025 2.56152 3.3875 2.89902 2.55C2.89902 2.55 3.41152 2.3875 4.57402 3.1875C5.06152 3.05 5.58652 2.9875 6.09902 2.9875C6.61152 2.9875 7.13652 3.0625 7.62402 3.1875C8.78652 2.3875 9.29902 2.55 9.29902 2.55C9.63652 3.4 9.42402 4.025 9.36152 4.175C9.76152 4.6 9.98652 5.15 9.98652 5.825C9.98652 8.1875 8.56152 8.7125 7.19902 8.8625C7.42402 9.05 7.61152 9.425 7.61152 10C7.61152 10.825 7.59902 11.4875 7.59902 11.6875C7.59902 11.85 7.71152 12.05 8.01152 11.9875C10.449 11.175 12.199 8.875 12.199 6.15C12.2115 2.75 9.47402 0 6.11152 0Z" fill="CurrentColor"></path>
</svg>
</div><div class="linkedin w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6657 12H1.33236C0.595977 12 -0.000976562 11.403 -0.000976562 10.6667V1.33333C-0.000976562 0.596954 0.595977 0 1.33236 0H10.6657C11.4021 0 11.999 0.596954 11.999 1.33333V10.6667C11.999 11.403 11.4021 12 10.6657 12ZM8.55293 10.3332H10.3337V6.67504C10.3337 5.12725 9.45627 4.37887 8.23075 4.37887C7.00467 4.37887 6.48867 5.33366 6.48867 5.33366V4.55539H4.77255V10.3332H6.48867V7.30019C6.48867 6.48752 6.86276 6.00393 7.57878 6.00393C8.23696 6.00393 8.55293 6.46863 8.55293 7.30019V10.3332ZM1.66699 2.73267C1.66699 3.32145 2.14067 3.79884 2.72522 3.79884C3.30977 3.79884 3.78316 3.32145 3.78316 2.73267C3.78316 2.1439 3.30977 1.6665 2.72522 1.6665C2.14067 1.6665 1.66699 2.1439 1.66699 2.73267ZM3.62856 10.3332H1.83908V4.55539H3.62856V10.3332Z" fill="CurrentColor"></path>
</svg>
</div><div class="x-twitter w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.11827 5.07857L11.4872 0H10.4519L6.65836 4.40965L3.62844 0H0.133789L4.71562 6.66818L0.133789 11.9938H1.16915L5.17527 7.3371L8.37508 11.9938H11.8697L7.11801 5.07857H7.11827ZM5.70019 6.72692L5.23596 6.06292L1.54221 0.779407H3.13247L6.11337 5.04337L6.5776 5.70737L10.4524 11.2499H8.86216L5.70019 6.72718V6.72692Z" fill="CurrentColor"></path>
</svg>
</div></a>
</div><div data-wf--social-link-w-icon--variant="linkedin" class="social-link-container">
<a href="https://www.linkedin.com/company/gruntwork/" target="_blank" class="social-link w-inline-block"><div class="github w-variant-1f2e668e-dd04-7e7e-7fb5-36e74a8e2b27 w-embed">
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.11152 0C2.72402 0 -0.000976562 2.75 -0.000976562 6.15C-0.000976562 8.875 1.74902 11.175 4.17402 11.9875C4.47402 12.05 4.58652 11.85 4.58652 11.6875C4.58652 11.55 4.57402 11.05 4.57402 10.55C2.87402 10.9125 2.52402 9.8125 2.52402 9.8125C2.24902 9.1 1.84902 8.9125 1.84902 8.9125C1.29902 8.5375 1.88652 8.5375 1.88652 8.5375C2.49902 8.575 2.82402 9.175 2.82402 9.175C3.37402 10.1125 4.24902 9.85 4.59902 9.6875C4.64902 9.2875 4.81152 9.0125 4.98652 8.8625C3.63652 8.725 2.21152 8.1875 2.21152 5.825C2.21152 5.15 2.44902 4.6 2.83652 4.175C2.77402 4.025 2.56152 3.3875 2.89902 2.55C2.89902 2.55 3.41152 2.3875 4.57402 3.1875C5.06152 3.05 5.58652 2.9875 6.09902 2.9875C6.61152 2.9875 7.13652 3.0625 7.62402 3.1875C8.78652 2.3875 9.29902 2.55 9.29902 2.55C9.63652 3.4 9.42402 4.025 9.36152 4.175C9.76152 4.6 9.98652 5.15 9.98652 5.825C9.98652 8.1875 8.56152 8.7125 7.19902 8.8625C7.42402 9.05 7.61152 9.425 7.61152 10C7.61152 10.825 7.59902 11.4875 7.59902 11.6875C7.59902 11.85 7.71152 12.05 8.01152 11.9875C10.449 11.175 12.199 8.875 12.199 6.15C12.2115 2.75 9.47402 0 6.11152 0Z" fill="CurrentColor"></path>
</svg>
</div><div class="linkedin w-variant-1f2e668e-dd04-7e7e-7fb5-36e74a8e2b27 w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6657 12H1.33236C0.595977 12 -0.000976562 11.403 -0.000976562 10.6667V1.33333C-0.000976562 0.596954 0.595977 0 1.33236 0H10.6657C11.4021 0 11.999 0.596954 11.999 1.33333V10.6667C11.999 11.403 11.4021 12 10.6657 12ZM8.55293 10.3332H10.3337V6.67504C10.3337 5.12725 9.45627 4.37887 8.23075 4.37887C7.00467 4.37887 6.48867 5.33366 6.48867 5.33366V4.55539H4.77255V10.3332H6.48867V7.30019C6.48867 6.48752 6.86276 6.00393 7.57878 6.00393C8.23696 6.00393 8.55293 6.46863 8.55293 7.30019V10.3332ZM1.66699 2.73267C1.66699 3.32145 2.14067 3.79884 2.72522 3.79884C3.30977 3.79884 3.78316 3.32145 3.78316 2.73267C3.78316 2.1439 3.30977 1.6665 2.72522 1.6665C2.14067 1.6665 1.66699 2.1439 1.66699 2.73267ZM3.62856 10.3332H1.83908V4.55539H3.62856V10.3332Z" fill="CurrentColor"></path>
</svg>
</div><div class="x-twitter w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.11827 5.07857L11.4872 0H10.4519L6.65836 4.40965L3.62844 0H0.133789L4.71562 6.66818L0.133789 11.9938H1.16915L5.17527 7.3371L8.37508 11.9938H11.8697L7.11801 5.07857H7.11827ZM5.70019 6.72692L5.23596 6.06292L1.54221 0.779407H3.13247L6.11337 5.04337L6.5776 5.70737L10.4524 11.2499H8.86216L5.70019 6.72718V6.72692Z" fill="CurrentColor"></path>
</svg>
</div></a>
</div><div data-wf--social-link-w-icon--variant="x-twitter" class="social-link-container">
<a href="https://x.com/gruntwork_io" target="_blank" class="social-link w-inline-block"><div class="github w-embed">
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.11152 0C2.72402 0 -0.000976562 2.75 -0.000976562 6.15C-0.000976562 8.875 1.74902 11.175 4.17402 11.9875C4.47402 12.05 4.58652 11.85 4.58652 11.6875C4.58652 11.55 4.57402 11.05 4.57402 10.55C2.87402 10.9125 2.52402 9.8125 2.52402 9.8125C2.24902 9.1 1.84902 8.9125 1.84902 8.9125C1.29902 8.5375 1.88652 8.5375 1.88652 8.5375C2.49902 8.575 2.82402 9.175 2.82402 9.175C3.37402 10.1125 4.24902 9.85 4.59902 9.6875C4.64902 9.2875 4.81152 9.0125 4.98652 8.8625C3.63652 8.725 2.21152 8.1875 2.21152 5.825C2.21152 5.15 2.44902 4.6 2.83652 4.175C2.77402 4.025 2.56152 3.3875 2.89902 2.55C2.89902 2.55 3.41152 2.3875 4.57402 3.1875C5.06152 3.05 5.58652 2.9875 6.09902 2.9875C6.61152 2.9875 7.13652 3.0625 7.62402 3.1875C8.78652 2.3875 9.29902 2.55 9.29902 2.55C9.63652 3.4 9.42402 4.025 9.36152 4.175C9.76152 4.6 9.98652 5.15 9.98652 5.825C9.98652 8.1875 8.56152 8.7125 7.19902 8.8625C7.42402 9.05 7.61152 9.425 7.61152 10C7.61152 10.825 7.59902 11.4875 7.59902 11.6875C7.59902 11.85 7.71152 12.05 8.01152 11.9875C10.449 11.175 12.199 8.875 12.199 6.15C12.2115 2.75 9.47402 0 6.11152 0Z" fill="CurrentColor"></path>
</svg>
</div><div class="linkedin w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.6657 12H1.33236C0.595977 12 -0.000976562 11.403 -0.000976562 10.6667V1.33333C-0.000976562 0.596954 0.595977 0 1.33236 0H10.6657C11.4021 0 11.999 0.596954 11.999 1.33333V10.6667C11.999 11.403 11.4021 12 10.6657 12ZM8.55293 10.3332H10.3337V6.67504C10.3337 5.12725 9.45627 4.37887 8.23075 4.37887C7.00467 4.37887 6.48867 5.33366 6.48867 5.33366V4.55539H4.77255V10.3332H6.48867V7.30019C6.48867 6.48752 6.86276 6.00393 7.57878 6.00393C8.23696 6.00393 8.55293 6.46863 8.55293 7.30019V10.3332ZM1.66699 2.73267C1.66699 3.32145 2.14067 3.79884 2.72522 3.79884C3.30977 3.79884 3.78316 3.32145 3.78316 2.73267C3.78316 2.1439 3.30977 1.6665 2.72522 1.6665C2.14067 1.6665 1.66699 2.1439 1.66699 2.73267ZM3.62856 10.3332H1.83908V4.55539H3.62856V10.3332Z" fill="CurrentColor"></path>
</svg>
</div><div class="x-twitter w-variant-0dd8c4d5-adc3-7589-d0f7-a9bee9c5178f w-embed">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.11827 5.07857L11.4872 0H10.4519L6.65836 4.40965L3.62844 0H0.133789L4.71562 6.66818L0.133789 11.9938H1.16915L5.17527 7.3371L8.37508 11.9938H11.8697L7.11801 5.07857H7.11827ZM5.70019 6.72692L5.23596 6.06292L1.54221 0.779407H3.13247L6.11337 5.04337L6.5776 5.70737L10.4524 11.2499H8.86216L5.70019 6.72718V6.72692Z" fill="CurrentColor"></path>
</svg>
</div></a>
</div>
</div>
</div><div class="w-layout-hflex flex-block-3">
<div class="w-layout-blockcontainer footer-platform w-container">
<h4 class="footer-column-header">Platform</h4><div class="collection-list-wrapper w-dyn-list">
<div role="list" class="footer-collection-list w-dyn-items">
<div role="listitem" class="collection-item-3 w-dyn-item">
<a href="/platform/iac-library" class="footerlink">IaC Library</a>
</div><div role="listitem" class="collection-item-3 w-dyn-item">
<a href="/platform/account-factory" class="footerlink">Account Factory</a>
</div><div role="listitem" class="collection-item-3 w-dyn-item">
<a href="/platform/pipelines" class="footerlink">Pipelines</a>
</div><div role="listitem" class="collection-item-3 w-dyn-item">
<a href="/platform/patcher" class="footerlink">Patcher</a>
</div>
</div>
</div>
</div><div class="w-layout-blockcontainer footer-services w-container">
<h4 class="footer-column-header">Services</h4><div class="w-dyn-list">
<div role="list" class="footer-collection-list w-dyn-items">
<div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/accelerator" class="footerlink">Accelerator</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/services/opentofu" class="footerlink">OpenTofu Services</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/services/terragrunt" class="footerlink">Terragrunt Services</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/pricing" class="footerlink">Pricing</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/support" class="footerlink">Support</a>
</div>
</div>
</div>
</div><div class="w-layout-blockcontainer footer-open-source w-container">
<h4 class="footer-column-header">Open Source</h4><div class="w-dyn-list">
<div role="list" class="footer-collection-list w-dyn-items">
<div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://terragrunt.com" class="footerlink">Terragrunt</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://terratest.gruntwork.io" class="footerlink">Terratest</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://github.com/gruntwork-io/boilerplate" class="footerlink">Boilerplate</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://github.com/gruntwork-io/cloud-nuke" class="footerlink">Cloudnuke</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://github.com/gruntwork-io/git-xargs" class="footerlink">Git Xargs</a>
</div>
</div>
</div>
</div><div class="w-layout-blockcontainer footer-resources w-container">
<h4 class="footer-column-header">Resources</h4><div class="w-dyn-list">
<div role="list" class="footer-collection-list w-dyn-items">
<div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://docs.gruntwork.io" class="footerlink">Docs</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/customer-stories" class="footerlink">Customer Stories</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/blog" class="footerlink">Blog</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/books" class="footerlink">Books</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/resources/community" class="footerlink">Community</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/gruntwork-comparisons" class="footerlink">Comparisons</a>
</div>
</div>
</div>
</div><div class="w-layout-blockcontainer footer-company w-container">
<h4 class="footer-column-header">Company</h4><div class="w-dyn-list">
<div role="list" class="footer-collection-list w-dyn-items">
<div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/about" class="footerlink">About</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/careers" class="footerlink">Careers</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://store.gruntwork.io/" class="footerlink">Merch</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/legal/terms-of-service" class="footerlink">Legal</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="https://github.com/gruntwork-io/legal/tree/main/security" class="footerlink">Security</a>
</div><div role="listitem" class="collection-item-2 w-dyn-item">
<a href="/ai-info-page" class="footerlink">AI &amp; LLM Info</a>
</div>
</div>
</div>
</div>
</div>
</div>
</section><div class="w-layout-blockcontainer vertical-grid w-container"></div><script src="/_assets/d3e54v103j8qbb.cloudfront.net/js/jquery-3.5.1.min.dc5e7f18c8.1046680f.js" type="text/javascript"></script><script src="/_assets/cdn.prod.website-files.com/67f94fda8156ff7b19690b57/js/site.schunk.36b8fb49256177c8.js" type="text/javascript"></script><script src="/_assets/cdn.prod.website-files.com/67f94fda8156ff7b19690b57/js/site.30ff6952.17dba879e730a467.js" type="text/javascript"></script><!-- Google Tag Manager (noscript) -->
<noscript><iframe src="/mtag/ns.html?id=GTM-5TTJJGTL" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
<style>
.w-code-block {
background: #1c1833 !important;
border: 1px solid #343956;
border-radius: 6px;
display: inline-block;
left: -24px;
overflow-x: auto;
padding-top: 0.5em;
padding-bottom: 0.5em;
padding-left: 0 !important;
position: relative;
width: 700px;
}
pre.w-code-block code {
background: none;
border: none;
left: 2em;
padding: 0;
width: fit-content;
}
@media screen and (max-width: 991px) {
.w-code-block {
left: 0px;
width: auto;
}
}
</style></body>
</html>