<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anil Jaiswal</title>
    <description>The latest articles on DEV Community by Anil Jaiswal (@aniljaiswal).</description>
    <link>https://dev.to/aniljaiswal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F252678%2Fa9185f48-53cf-413c-b639-53f5f224cee7.png</url>
      <title>DEV Community: Anil Jaiswal</title>
      <link>https://dev.to/aniljaiswal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aniljaiswal"/>
    <language>en</language>
    <item>
      <title>GitOps at Scale: What Breaks at 200 Repos and 40 Teams</title>
      <dc:creator>Anil Jaiswal</dc:creator>
      <pubDate>Mon, 27 Jul 2026 05:11:54 +0000</pubDate>
      <link>https://dev.to/aniljaiswal/gitops-at-scale-what-breaks-at-200-repos-and-40-teams-35bf</link>
      <guid>https://dev.to/aniljaiswal/gitops-at-scale-what-breaks-at-200-repos-and-40-teams-35bf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uhu1uhtu8x15svwd6fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1uhu1uhtu8x15svwd6fx.png" alt="Gitops-at-scale" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally published on &lt;a href="https://aniljaiswal.com/blog/gitops-at-scale-what-breaks" rel="noopener noreferrer"&gt;aniljaiswal.com&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The GitOps demo is gorgeous. One repo, one app, one cluster. You change a value in Git. A few seconds later, the cluster changes to match. Production is a commit hash. Rollback is a git revert. Everyone in the room nods, and you roll it out.&lt;/p&gt;

&lt;p&gt;Two years later, you have 200 repos, 40 teams, and four environments. The beautiful model is groaning. The ArgoCD controller is pegged. Someone hotfixed prod with kubectl three weeks ago, and nobody noticed until the next deploy quietly reverted it. A team deployed into another team's namespace by accident. Promoting a change from staging to prod means copy-pasting YAML between folders and praying. And every change, even a one-line config bump, is now a pull request waiting on a review.&lt;/p&gt;

&lt;p&gt;None of this means GitOps was the wrong call. It means GitOps is a distributed system like any other. The simple setup that works for one team does not survive forty. The principles hold. The shape has to change. Here is what breaks as you scale, roughly in the order it bites, and how to fix each part.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control plane melts before you notice
&lt;/h2&gt;

&lt;p&gt;The first thing to break is the least interesting and the most disruptive. The controller runs out of headroom. ArgoCD, Flux, whichever you run, is a reconciliation engine. It constantly compares the desired state in Git against the live state in the cluster, for every resource it manages. At one app, that is nothing. At a few thousand apps across dozens of clusters, that loop is real, steady work, and the default single-instance setup buckles.&lt;/p&gt;

&lt;p&gt;The symptoms are sneaky, because they are not outages. Syncs get slow. A change you merged takes ten minutes to land instead of ten seconds. The UI times out. Reconciliation falls behind, and the gap between merged and deployed stretches. People stop trusting that Git is the source of truth, and that quietly kills the whole idea.&lt;/p&gt;

&lt;p&gt;The fixes are operational, and you want them in early, before the melt. Shard the application controller across replicas, so the load spreads across clusters instead of hammering one process. Turn off polling and drive syncs with webhooks, so a push triggers reconciliation right away instead of the controller re-listing every repo on a timer. And raise the reconciliation interval for things that rarely change. Re-diffing a stable app every three minutes is pure waste at scale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# argocd-cmd-params-cm: spread controller load and stop re-listing everything constantly&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Shard the application controller across replicas (one shard per N clusters)&lt;/span&gt;
  &lt;span class="na"&gt;controller.sharding.algorithm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;round-robin&lt;/span&gt;
  &lt;span class="c1"&gt;# Back off the default reconciliation timer; webhooks handle the urgent path&lt;/span&gt;
  &lt;span class="na"&gt;timeout.reconciliation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The deeper point is simple. Your GitOps controller is production infrastructure. It has capacity limits, and it needs the same monitoring as anything else you run. Alert on reconciliation lag and sync latency before your engineers notice. When they notice, it is by losing faith that Git reflects reality.&lt;/p&gt;

&lt;p&gt;It is worth saying plainly, because this is the failure that erodes everything else. The whole value of GitOps rests on one belief: what is in Git is what is running. The first time a merge takes fifteen minutes to land, or a sync fails silently and nobody is paged, that belief cracks. Once it cracks, engineers start checking the cluster directly instead of trusting Git. And the moment they do that, you have all the ceremony of GitOps and none of the guarantee. Controller health is not a nicety at scale. It is what keeps the source of truth actually true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registering 200 apps by hand does not work
&lt;/h2&gt;

&lt;p&gt;The second thing to break is the idea that someone declares each application by hand. In the demo, you write one Application manifest pointing at one repo. At 200 repos, times four environments, hand-maintaining 200-plus manifests is a full-time job nobody wants and everybody gets wrong.&lt;/p&gt;

&lt;p&gt;The fix is to generate applications, not declare them. ArgoCD's ApplicationSet does this. You describe a pattern once, point a generator at your set of repos, teams, or clusters, and it produces the Application objects for you. A new service shows up, matches the pattern, and gets deployed. No human edits a registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ApplicationSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;team-services&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generators&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://git.corp.local/platform/service-catalog&lt;/span&gt;
        &lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
        &lt;span class="c1"&gt;# Each service drops a config.json under its own directory; the&lt;/span&gt;
        &lt;span class="c1"&gt;# generator turns every match into an Application automatically.&lt;/span&gt;
        &lt;span class="na"&gt;directories&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;services/*"&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{path.basename}}"&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{path.basename}}"&lt;/span&gt;
      &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;repoURL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://git.corp.local/{{path.basename}}"&lt;/span&gt;
        &lt;span class="na"&gt;targetRevision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy/overlays/prod&lt;/span&gt;
      &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://kubernetes.default.svc&lt;/span&gt;
        &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{path.basename}}"&lt;/span&gt;
      &lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shift is from registering apps one by one to describing how apps map to the platform. That is the difference between onboarding a new service in a day and onboarding it through a ticket queue. Ask why platform teams fail to get adoption, and half the answer is that onboarding was manual and slow. ApplicationSets are how you make it automatic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drift, and the question of who wins
&lt;/h2&gt;

&lt;p&gt;The third thing to break is the assumption that Git is the only thing changing the cluster. It is not. Someone will &lt;code&gt;kubectl edit&lt;/code&gt; a production resource during an incident, because it is 2 a.m. and that is faster than a PR. Someone will scale a deployment by hand. An operator will mutate something. Now live state and Git disagree, and the whole model hinges on what happens next.&lt;/p&gt;

&lt;p&gt;There are two choices, and you have to pick on purpose. With self-heal on, the controller treats Git as absolute. It reverts any live change that does not match, right away. That is the pure GitOps promise. It is also how you erase the 2 a.m. hotfix that was keeping prod alive, ten minutes later, silently, because someone merged an unrelated change and triggered a sync. With self-heal off, drift is detected and shown but not corrected. The human hotfix survives. But now your cluster can quietly drift from Git and stay that way, which chips away at the source-of-truth guarantee.&lt;/p&gt;

&lt;p&gt;Most mature setups land on self-heal on, plus making the emergency path go through Git so there is nothing to erase. If the 2 a.m. fix is a one-line commit to a fast-tracked branch instead of a kubectl edit, self-heal is your friend, not your enemy. The fix is now the desired state. The hard part is not the config, it is the culture. You have to make the Git path fast enough that engineers actually use it under pressure. And you have to alert on drift loudly, so when someone does bypass it, everyone knows at once instead of finding out at the next sync.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Detect drift everywhere; auto-correct deliberately. Notifications make&lt;/span&gt;
&lt;span class="c1"&gt;# a bypass visible instead of silent.&lt;/span&gt;
&lt;span class="na"&gt;syncPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;automated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;selfHeal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;      &lt;span class="c1"&gt;# Git wins, so the emergency path must go through Git&lt;/span&gt;
    &lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;syncOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;RespectIgnoreDifferences=true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Secrets do not go in Git, but the reference to them does
&lt;/h2&gt;

&lt;p&gt;The fourth thing to break is obvious in hindsight and still catches teams. GitOps wants all desired state in Git, and you cannot put secrets in Git. A plaintext database password in a company repo is a breach waiting for an audit to find it.&lt;/p&gt;

&lt;p&gt;The fix is that Git holds a reference to a secret, never the secret itself. Two patterns dominate. Sealed Secrets encrypts the secret so the ciphertext is safe to commit, and only the in-cluster controller can decrypt it. The External Secrets Operator goes further. It keeps the real secret in a proper secrets manager, and Git holds only a pointer to where the value lives. That is the cleaner model at scale, because your secrets sit in one system with rotation and access control, instead of scattered as sealed blobs across repos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Git holds the pointer. The value lives in the secrets manager and is&lt;/span&gt;
&lt;span class="c1"&gt;# pulled into the cluster at runtime, never committed anywhere.&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external-secrets.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExternalSecret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-db&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;refreshInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;
  &lt;span class="na"&gt;secretStoreRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-backend&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterSecretStore&lt;/span&gt;
  &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-db-credentials&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
      &lt;span class="na"&gt;remoteRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod/app/db&lt;/span&gt;
        &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ties straight into governance. When security asks where the secrets live, "in our secrets manager, referenced by a pointer from Git, never in a repo" is a clean answer. "Base64 in a values file" is a failed audit. Get this right from the first repo. Retrofitting secret handling across 200 repos later is exactly the kind of migration nobody has time for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blast radius: 40 teams cannot all deploy everywhere
&lt;/h2&gt;

&lt;p&gt;The fifth thing to break is isolation. In the single-team demo, whoever controls the repo controls the deploy, and that is fine. With 40 teams sharing one control plane, a flat setup means any team can deploy into any namespace on any cluster, by accident or on purpose. That is too big a blast radius. The first cross-team incident, team A's ApplicationSet grabbing team B's namespace, teaches it the hard way.&lt;/p&gt;

&lt;p&gt;The fix is to make isolation structural, not a convention. ArgoCD's AppProject is the boundary. It limits which repos an app can pull from, which clusters and namespaces it can deploy to, and which resource kinds it can touch. Each team gets a project scoped to their own repos and namespaces, and the control plane enforces it. A team cannot deploy outside its boundary, because the project rejects it, not because a policy doc asked them not to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AppProject&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;team-payments&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Only this team's repos can be sources&lt;/span&gt;
  &lt;span class="na"&gt;sourceRepos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://git.corp.local/payments/*"&lt;/span&gt;
  &lt;span class="c1"&gt;# Only this team's namespaces, only on the clusters they are allowed on&lt;/span&gt;
  &lt;span class="na"&gt;destinations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://prod.k8s.corp.local&lt;/span&gt;
      &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payments-*"&lt;/span&gt;
  &lt;span class="c1"&gt;# No cluster-scoped resource changes from a team project&lt;/span&gt;
  &lt;span class="na"&gt;clusterResourceWhitelist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployer&lt;/span&gt;
      &lt;span class="na"&gt;policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;p,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proj:team-payments:deployer,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;applications,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sync,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;team-payments/*,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;allow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same least-privilege thinking a good IAM policy applies to a cloud account, pointed at your deploy plane. A boundary you can cross by forgetting a convention is not a boundary. The one the platform refuses to let you cross is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promotion across environments is where the copy-paste chaos hides
&lt;/h2&gt;

&lt;p&gt;The sixth thing to break is the one people feel every day: getting a change from dev to staging to prod. The simple setup has a folder per environment, and promotion means copying YAML from the staging folder to the prod folder. At scale, this is a swamp. Environments drift apart because someone forgot to copy one change. Reviews are noisy, because the diff is full of duplicated boilerplate. And nobody can tell at a glance whether prod is actually running what staging validated.&lt;/p&gt;

&lt;p&gt;The pattern that holds is rendered manifests. Instead of promoting templates and re-rendering per environment, you render the fully-resolved manifests once, per environment, into a branch or folder. Promotion becomes a diff of the actual final YAML that will be applied. You can see exactly what will change in prod, line for line, because you are looking at the rendered output, not a template that might resolve differently. Promotion is then a small, honest pull request that moves a known-good state forward. Not a copy-paste of templates with a prayer that they resolve the same way in prod as they did in staging.&lt;/p&gt;

&lt;p&gt;The key discipline: the same artifact moves forward. The same digest-pinned images and the same rendered config that passed in staging is what goes to prod. Promotion is moving a validated thing forward, not rebuilding it and hoping. If prod re-renders from a template, you tested one thing in staging and shipped a slightly different thing to prod, which defeats the point of having staging at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is a pull request now
&lt;/h2&gt;

&lt;p&gt;The last thing to break is social, not technical, and it surprises teams because it is a side effect of GitOps working. When Git is the only way to change production, every change becomes a pull request, even the trivial ones. A one-line config bump that used to be a kubectl command is now a PR, a review, a merge, and a sync. Multiply by 40 teams, and review becomes a bottleneck. Worse, it becomes a reason to route around GitOps entirely, which is how you get the 2 a.m. kubectl edit that started this whole thing.&lt;/p&gt;

&lt;p&gt;The fix is to match the friction of a change to its risk. Not every change needs a human reviewer. Auto-merge low-risk, well-tested changes, like an image digest bump that passed CI. Save human review for the risky surfaces: RBAC, network policy, resource limits, anything cluster-scoped. Push validation left with policy checks in CI, so a broken manifest fails on the PR, before it ever reaches the cluster, instead of failing a sync and paging someone. And give teams real autonomy inside their AppProject boundary, so a team changing its own namespace is not gated on a central platform team. That gating is the most common way a platform becomes the bottleneck everyone resents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Fail bad manifests in CI, on the PR, not at sync time. Cheap gate,&lt;/span&gt;
&lt;span class="c1"&gt;# huge reduction in review load and in 2 a.m. surprises.&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;validate manifests&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;kubeconform -strict -summary rendered/prod/*.yaml&lt;/span&gt;
    &lt;span class="s"&gt;conftest test rendered/prod/*.yaml   # policy: no privileged pods, limits set, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The principle under all of these fixes is one line: GitOps should make the safe path the easy path. If following the process is slow and painful, engineers will bypass it under pressure. And a bypassed GitOps process is worse than none, because now you have the overhead and none of the guarantee. Fast auto-merge for safe changes, hard gates for risky ones, and real team autonomy are what keep people on the paved road.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rollback is not just git revert
&lt;/h2&gt;

&lt;p&gt;There is one more thing that breaks, and it breaks at the worst possible moment: during an incident. The GitOps pitch says rollback is a git revert. At small scale, that is true. At scale, "revert the commit" hides a few sharp edges you do not want to find while production is down.&lt;/p&gt;

&lt;p&gt;The first: a revert only rolls back what the commit changed. If the bad deploy also ran a database migration, a sync hook, or anything with a side effect outside the manifests, reverting the YAML does not undo it. Your pods roll back to the old version and then fail against a schema that moved forward. That is worse than the outage you were fixing. This is the same irreversible-migration trap that bites air-gapped upgrades, and the fix is the same. Migrations have to be backward compatible, so the old version can run against the new schema. Otherwise a revert is not really a rollback.&lt;/p&gt;

&lt;p&gt;The second is ordering. A real application is not one resource, it is a graph of them. Roll back in the wrong order and you can wedge yourself. ArgoCD sync waves let you set that order, so on the way back the database and config settle before the app that depends on them. If you have never tested a rollback, you do not know your order is right. You are hoping. Hope is not a rollback strategy.&lt;/p&gt;

&lt;p&gt;The third is speed and clarity under pressure. A stressed on-call engineer at 2 a.m. should not be reasoning about git history and sync waves. The revert should be one obvious, documented action. ArgoCD's own rollback to a previous synced revision is often faster and clearer in the moment than a git revert plus a wait for reconciliation. Decide and rehearse this before the incident, so rollback is muscle memory, not improvisation. A rollback path you have never run is a rollback path that does not work, and you will find that out exactly when you can least afford to.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually scales
&lt;/h2&gt;

&lt;p&gt;Step back, and the pattern is the same every time. The GitOps principles, declarative desired state, Git as the source of truth, continuous reconciliation, never stop being right. What breaks is always a shape or an operational assumption that was invisible at one team and load-bearing at forty. The controller needs sharding. Apps need generating, not declaring. Drift needs a deliberate policy and a fast path through Git. Secrets need a reference model. Teams need enforced boundaries. Promotion needs rendered artifacts. Reviews need risk-matched friction.&lt;/p&gt;

&lt;p&gt;None of this is exotic. All of it is far cheaper to build in early than to retrofit once you are at 200 repos with the control plane on fire. If you are standing up GitOps today for a handful of teams, build as if you already have forty. Shard the controller, generate your apps, enforce project boundaries, and reference your secrets, before you need any of it. The demo topology is a trap, precisely because it works so well at small scale that you forget it was never built for the scale you are heading toward.&lt;/p&gt;

&lt;p&gt;GitOps at scale is still GitOps. It just stops being a clever trick with one repo and becomes what it always was underneath: a distributed system you have to operate with the same rigor as the systems it deploys. Treat it that way from the start, and the beautiful demo becomes a platform that holds. Treat it as magic, and it holds right up until the day it very publicly does not.&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>kubernetes</category>
      <category>devops</category>
      <category>platform</category>
    </item>
    <item>
      <title>Building a Cron Expression Parser using Python</title>
      <dc:creator>Anil Jaiswal</dc:creator>
      <pubDate>Sun, 03 Sep 2023 09:24:24 +0000</pubDate>
      <link>https://dev.to/aniljaiswal/building-a-cron-expression-parser-using-python-3cdi</link>
      <guid>https://dev.to/aniljaiswal/building-a-cron-expression-parser-using-python-3cdi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Task scheduling can be a complex task in software development, especially when it comes to specifying when and how often a task should run. This is where cron expressions come in handy. Cron expressions are widely used to define schedules for recurring tasks, but they can be a bit cryptic to read and understand. That's where the "Cron Expression Parser" project comes to the rescue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Cron Expression?
&lt;/h2&gt;

&lt;p&gt;A cron expression is a string representing a schedule that determines when a task should be executed. It consists of five time fields: minute, hour, day of month, month, and day of week, followed by a command to execute. Each field can have various values or operators to define the schedule. For example, a cron expression like &lt;code&gt;*/15 0 1,15 * 1-5 /usr/bin/find&lt;/code&gt; tells us that a task should run every 15 minutes, at midnight, on the 1st and &lt;br&gt;
15th day of every month, from Monday to Friday, and the command to execute is &lt;code&gt;/usr/bin/find&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Simplifying Cron Expressions
&lt;/h2&gt;

&lt;p&gt;While cron expressions are powerful, they can be challenging to interpret, especially for those new to them. That's where the Cron Expression Parser comes in. This Python-based tool takes a standard cron expression and converts it into a readable table format. Let's take a closer look at how it works.&lt;/p&gt;
&lt;h2&gt;
  
  
  How the Cron Expression Parser Works
&lt;/h2&gt;

&lt;p&gt;Our Cron Expression Parser takes a standard cron expression as input and does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Parsing&lt;/strong&gt;: It breaks down the expression into its individual fields, such as minute, hour, and so on.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Handling Operators&lt;/strong&gt;: The parser intelligently handles various operators used in cron expressions, including &lt;code&gt;*&lt;/code&gt; (any value), &lt;code&gt;-&lt;/code&gt; (range), &lt;code&gt;,&lt;/code&gt; (list), and &lt;code&gt;/&lt;/code&gt; (step).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Formatting&lt;/strong&gt;: The tool formats the parsed cron expression into a clear and organized table. Each field name is displayed in the first 14 columns, followed by the corresponding time values.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Example Output
&lt;/h2&gt;

&lt;p&gt;Let's take our previous example cron expression:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*/15 0 1,15 * 1-5 /usr/bin/find
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Cron Expression Parser converts it into the following table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minute        0 15 30 45
hour          0
day of month  1 15
month         1 2 3 4 5 6 7 8 9 10 11 12
day of week   1 2 3 4 5
command       /usr/bin/find
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Use the Cron Expression Parser?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity&lt;/strong&gt;: It makes complex cron expressions easy to understand, even for those not familiar with cron syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Detection&lt;/strong&gt;: The tool can quickly spot issues or errors in your cron expressions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: It simplifies the task of creating and debugging cron schedules for your recurring tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: The Cron Expression Parser is open-source, so you can use it freely and even contribute to its development.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Using the Cron Expression Parser is straightforward. You can find the code and detailed instructions in my &lt;a href="https://github.com/aniljaiswal/cron-parser" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;. Simply clone the repository, run the script, and input your cron expression. You'll get a neatly formatted table in no time!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Managing task schedules is a crucial part of software development, and cron expressions are a powerful tool for this purpose. &lt;br&gt;
However, understanding and working with them can be challenging. The Cron Expression Parser simplifies this process, making it easier for developers and administrators to create and manage task schedules. Give it a try, and you'll never look at cron expressions the same way again!&lt;/p&gt;

&lt;p&gt;Feel free to raise a Github issue if you find something broken.&lt;/p&gt;

</description>
      <category>python</category>
      <category>cron</category>
    </item>
    <item>
      <title>Infrastructure as Code: A Beginner's Guide</title>
      <dc:creator>Anil Jaiswal</dc:creator>
      <pubDate>Sat, 19 Aug 2023 07:06:49 +0000</pubDate>
      <link>https://dev.to/aniljaiswal/infrastructure-as-code-a-beginners-guide-26ln</link>
      <guid>https://dev.to/aniljaiswal/infrastructure-as-code-a-beginners-guide-26ln</guid>
      <description>&lt;p&gt;The percentage of software companies that use IAC tools in the world is growing rapidly. In 2022, it was estimated that 55% of software companies were using IAC tools, and this number is expected to reach 75% by 2028.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Infrastructure as Code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At its core, Infrastructure as Code (IAC) refers to the practice of managing and provisioning infrastructure resources through code and automation. In essence, it treats infrastructure components in the same way software developers handle their codebase. Instead of manually configuring servers, networks, and other resources, developers can define and manage these elements using code scripts and templates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Significance of Infrastructure as Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The importance of adopting Infrastructure as Code (IAC) cannot be overstated, particularly in today's dynamic and competitive tech environment. Here are some key reasons why embracing IAC is essential:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Consistency and Reproducibility:&lt;/strong&gt; Manual setups are prone to errors, and inconsistencies between different environments can lead to unexpected issues. IAC ensures that the infrastructure is defined in a consistent manner across all stages, from development to testing and production. This consistency facilitates easy replication of environments, reducing the risk of discrepancies that often lead to production outages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Version Control and Collaboration:&lt;/strong&gt; Treating infrastructure as code allows teams to leverage version control systems, just like they do for software code. This enables collaboration, tracking changes, and maintaining a historical record of modifications made to the infrastructure. As a result, teams can work together seamlessly, iterate efficiently, and revert to previous configurations if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Automation and Efficiency:&lt;/strong&gt; With IAC, repetitive tasks and configurations can be automated, freeing up valuable time for developers and operations teams. Automated provisioning not only accelerates the deployment process but also minimizes human errors that can arise from manual interventions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Scalability and Flexibility:&lt;/strong&gt; As applications grow and evolve, so does the need for scalable infrastructure. IAC allows teams to define scalability rules and configurations upfront, ensuring that the infrastructure can seamlessly adapt to changing demands without requiring substantial manual adjustments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Disaster Recovery and Redundancy:&lt;/strong&gt; IAC facilitates the creation of disaster recovery plans and redundancy setups by codifying backup configurations and failover mechanisms. This ensures that in the event of a failure, the recovery process can be initiated promptly and consistently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Documentation and Auditability:&lt;/strong&gt; Traditional setups often lack comprehensive documentation, making it challenging to understand the intricate details of the infrastructure. IAC inherently brings documentation through code comments and self-explanatory scripts, enhancing auditability and facilitating a deeper understanding of the infrastructure's architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comparing AWS CDK, Pulumi, and Terraform: Making Informed Choices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As organizations continue to embrace Infrastructure as Code (IAC) principles, the landscape of tools and frameworks to achieve this goal has expanded significantly. Among the prominent players in this arena are &lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt;, &lt;a href="https://www.pulumi.com/" rel="noopener noreferrer"&gt;Pulumi&lt;/a&gt;, and &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;. Each of these tools brings its unique approach and features to the table, catering to the diverse needs of developers and operations teams. In this section, we will delve into a detailed comparison of these three tools, highlighting their strengths, weaknesses, and use cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS CDK&lt;/strong&gt; is a framework for writing infrastructure code in JavaScript, TypeScript, Python, or Java. It uses the AWS CloudFormation service to deploy infrastructure. AWS CDK is a good choice for organizations that are already using AWS and want to use a tool that is tightly integrated with the AWS ecosystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pulumi&lt;/strong&gt; is a multi-cloud IAC tool that supports over 60 cloud providers, including AWS, Azure, and Google Cloud Platform. It uses a variety of programming languages, including Python, Go, C#, and JavaScript. Pulumi is a good choice for organizations that want to use a tool that is not tied to any particular cloud provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt; is an open-source IAC tool that supports over 200 cloud providers and infrastructure services. It uses a domain-specific language called HashiCorp Configuration Language (HCL) to define infrastructure. Terraform is a good choice for organizations that want a flexible and extensible IAC tool.&lt;/p&gt;

&lt;p&gt;Here is a table that summarizes the key differences between AWS CDK, Pulumi, and Terraform:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS CDK&lt;/th&gt;
&lt;th&gt;Pulumi&lt;/th&gt;
&lt;th&gt;Terraform&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Programming languages&lt;/td&gt;
&lt;td&gt;JavaScript, TypeScript, Python, Java&lt;/td&gt;
&lt;td&gt;Python, Go, C#, JavaScript&lt;/td&gt;
&lt;td&gt;HashiCorp Configuration Language (HCL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud providers&lt;/td&gt;
&lt;td&gt;AWS&lt;/td&gt;
&lt;td&gt;Over 60&lt;/td&gt;
&lt;td&gt;Over 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Similarities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All three tools can be used to automate the provisioning and configuration of infrastructure.&lt;/li&gt;
&lt;li&gt;All three tools can be used to manage changes to infrastructure.&lt;/li&gt;
&lt;li&gt;All three tools can be used to track changes to infrastructure.&lt;/li&gt;
&lt;li&gt;All three tools can be used to roll back to previous configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Differences&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CDK is tightly integrated with the AWS ecosystem.&lt;/li&gt;
&lt;li&gt;Pulumi supports over 60 cloud providers.&lt;/li&gt;
&lt;li&gt;Terraform is an open-source tool with a large community.&lt;/li&gt;
&lt;li&gt;AWS CDK uses JavaScript, TypeScript, Python, or Java.&lt;/li&gt;
&lt;li&gt;Pulumi uses Python, Go, C#, or JavaScript.&lt;/li&gt;
&lt;li&gt;Terraform uses HashiCorp Configuration Language (HCL).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Getting Started: Tutorials for AWS CDK, Pulumi, and Terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Embarking on your journey with AWS CDK, Pulumi, and Terraform can be exciting, but getting started might seem a bit overwhelming. Fear not, for each tool provides excellent resources to guide you through the initial steps. In this section, I'll provide you with brief tutorials to help you kickstart your experience with these powerful Infrastructure as Code tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS CDK:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Installation:&lt;/strong&gt; To begin, ensure you have Node.js and npm installed. Then, install the AWS CDK CLI using the following command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   npm install -g aws-cdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a CDK App:&lt;/strong&gt; Use the CDK CLI to create a new app scaffold:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   cdk init app --language=typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define Infrastructure:&lt;/strong&gt; Navigate to the newly created app directory and open the &lt;code&gt;lib&lt;/code&gt; folder. You'll find a TypeScript file where you can define your infrastructure components using AWS CDK constructs.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Create an EC2 Instance&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AmazonLinuxImage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Vpc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-ec2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EC2Stack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyVPC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyInstance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;InstanceType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;InstanceClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BURSTABLE2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InstanceSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MICRO&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;machineImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AmazonLinuxImage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EC2Stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EC2Stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Create an S3 bucket&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Bucket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-cdk-lib/aws-s3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;S3Stack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyBucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;versioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;S3Stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;S3Stack&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deploy:&lt;/strong&gt; Run the following commands to deploy your infrastructure to AWS:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   cdk synth
   cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pulumi:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt; Install the Pulumi CLI by following the instructions for your platform: &lt;a href="https://www.pulumi.com/docs/get-started/install/" rel="noopener noreferrer"&gt;https://www.pulumi.com/docs/get-started/install/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a New Project:&lt;/strong&gt; Use the Pulumi CLI to create a new project in your desired programming language:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pulumi new
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define Infrastructure:&lt;/strong&gt; Navigate to the project directory and open the main program file. You can now define your infrastructure resources using Pulumi's programming constructs.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// Create an EC2 instance&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pulumi/pulumi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pulumi/aws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-vpc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;cidrBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10.0.0.0/16&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-instance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;instanceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;t2.micro&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ami&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAmi&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amazon-linux-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="na"&gt;mostRecent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;subnetId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnetIds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="c1"&gt;// Create an S3 bucket&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;pulumi&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pulumi/pulumi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@pulumi/aws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-bucket&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;versioning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Provision Resources:&lt;/strong&gt; Run the following command to preview and deploy your resources:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pulumi up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Terraform:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt; Install the Terraform CLI by following the instructions for your platform: &lt;a href="https://learn.hashicorp.com/tutorials/terraform/install-cli" rel="noopener noreferrer"&gt;https://learn.hashicorp.com/tutorials/terraform/install-cli&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create a Configuration:&lt;/strong&gt; Create a new directory for your Terraform configuration files. Inside this directory, create a &lt;code&gt;.tf&lt;/code&gt; file to define your infrastructure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Define Resources:&lt;/strong&gt; In your Terraform configuration file, define the resources you want to create using HashiCorp Configuration Language (HCL).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# Create an EC2 instance.&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"my_vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cidr_block&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"10.0.0.0/16"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"my_instance"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0c55b159cbfafe1f0"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;my_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_ids&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="c1"&gt;# Craete an S3 bucket&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"my_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-unique-bucket-name"&lt;/span&gt;
  &lt;span class="nx"&gt;acl&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt;

  &lt;span class="nx"&gt;versioning&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialize and Apply:&lt;/strong&gt; Run the following commands to initialize and apply your Terraform configuration:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   terraform init
   terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion: Choosing the Right Tool&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As you've experienced, AWS CDK, Pulumi, and Terraform each offer distinct approaches to Infrastructure as Code, catering to various preferences and project requirements. AWS CDK stands out for its programming language familiarity and AWS integration. Pulumi excels in multi-cloud support and fine-grained control. Terraform's declarative syntax and thriving community make it a solid choice for many.&lt;/p&gt;

&lt;p&gt;To make an informed decision, consider the complexity of your project, your team's expertise, and the cloud providers you intend to work with. Each tool has its strengths and can be a valuable asset in your IAC journey. By mastering the nuances of these tools, you're poised to streamline infrastructure provisioning, enhance collaboration, and create more robust and scalable applications.&lt;/p&gt;

&lt;p&gt;If you're eager to delve deeper into the world of AWS CDK and learn about practical insights from real-world experiences, I invite you to subscribe to my newsletter (I won't spam, I promise!). In an upcoming series, I'll unravel how &lt;a href="https://www.cogoport.com" rel="noopener noreferrer"&gt;Cogoport&lt;/a&gt; has harnessed the power of AWS CDK to sculpt its infrastructure, navigating challenges and triumphs along the way. It's a chance to gain firsthand knowledge and discover the art of shaping digital landscapes.&lt;/p&gt;

&lt;p&gt;Originally published at &lt;a href="https://aniljaiswal.com/blog/introduction-to-iac-using-cdk-pulumi-and-terraform?utm_source=dev-to&amp;amp;utm_medium=post&amp;amp;utm_campaign=IAC-Article" rel="noopener noreferrer"&gt;https://aniljaiswal.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>iac</category>
      <category>terraform</category>
      <category>cdk</category>
      <category>pulumi</category>
    </item>
  </channel>
</rss>
